Terminology: Modules versus Packages #136
Description
The fact that ECMAScript Modules are individual files can be a great cause for assumptions and confusion, especially when the terms "packages" and "modules" are historically interchangeable within the Node.js eco-system, not in implementation of course, but at least from the end-user's perception.
I have been thinking of this notion a lot, and I wanted to open this issue and discuss it in detail because I believe it has a silver lining to solve a lot of problems simply by putting them in the right context, which can formalize better interop stories.
My own position is that ECMAScript Modules (ie that file that exports and can be imported) should always work in Node.js and in the Browser. It cannot throw things that go "uncaught". It should not require implicit bundling. It cannot be non-conforming. However, Node.js Packages (ie that folder that includes ECMAScript Modules and/or CommonJS... etc) is not expected to have any of the above guarantees backed in.
From my own viewpoint, this means that ECMAScript Modules in a package are either ECMAScript Modules (no breaking specifiers) or Node.js-specific (also ES) Modules. IMHO, all outstanding interop (web/standards) become a lot more palatable with the a clear articulation of those as two separate scenarios and potentially two separate flavours of modules.
The idea of packages with bare specifiers, at least today, is something that comes with implicit workflow requirements that limit the scope of any ECMAScript module that use them. Assuming that those always exist inside a relative "node_modules/<[@scope/]package>/<file.ext>"
then relative specifiers should not be unfeasible for ES modules that conform. In node, those can have the benefit of Node.js module path resolution (ie fixing relative paths that resolve to node_modules
in the search path). In the browser, they are not breaking, as long as all dependencies are in the single node_modules folder when going live — also, a basic service worker can do all sorts of magic with this one.
What about builtins? I think that both import.meta.require or dynamic import that allow the modules within a package to only import their Node.js specific logic in node offer a good starting point for interop, but it only works in the more recent releases of only some browsers. That is not to say it is node's problem to solve, but it is node's burden to make it clear to users that compatibility requires work on their part, and here is what some work looked like.