You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Create doc on how to support ESM and CommonJS when publishing modules #542
Given that by far the easiest way is “only publish CJS”, and if you want named exports, “publish CJS transpiled from ESM” - what more would go in this document?
@lemanschik i strongly disagree with that; a default export is what a module is; named exports are what module has, and most modules should be something. That’s a stylistic choice and not something node should be weighing in on. I, and the Airbnb style guide ftr, say that you should almost always do module.exports = function.
@ljharb i am happy that you ask for example it makes total new forms of builds more enjoyable and compose able at present we have overall good results with opening component based ipc specifiers inside chromium and v8 it self. this leads to stuff like running the monaco editor as chrome extension directly then using workspaces and overrides and then directly use unmodified directly loaded modules out of the npm ecosystem in a way that i can patch and replace them or use single functions of them to compose something total diffrent
and get all original source references without parsing generating and all that of tons of import maps in facts i am also working mean while on building the whole chromium platform in a browser in a virtual x86 vm running on wasm and other stuff also directly exposing remote filesystems for distributed builds via webrtc and such stuff it helps a lot if we do not need to add incremental build steps and can directly cache distributed incremental build results
note also collabing on MESON Build system written in ECMAScript that opens up building NodeJS inside the browser distributed.
we talk about projects with a lot of dynamic references and far more then some million well documented symbols.
@lemanschik thank you so much for this detailed response.
I've just read all of your replies including tiny book and small discussion in TS repo by links above.
I appreciate it.
But I also have 2 theses:
I really think that it would be more effective to discuss about new module approaches in Modules Team.
Main topic for this discussion is Create doc on how to support ESM and CommonJS when publishing modules. That's why we should focus on current ecosystem state and document it. Of course with simplicity criteria as u described.
Let me repeat my suggestion:
Can we add drafts to this issue from both opinions in format like this:
Original demo JavaScript code
Export notation for CJS and ESM
Settings samples for popular bundlers (webpack, rollup, parcel, maybe more)
I. e. add examples folder to our repository and 2 samples which we can test in GitHub Codespaces and discuss about it.
@ljharb, @mhdawson tell me please, what do you think about my propose and about maybe(!) a little bit off-topic vibe from previous messages.
P. S. @lemanschik I really appreciate your thoughts and even ready to participate in PoC of your idea if needed.
execution strategy lets move npm it self into the browser via replacing the nativ parts with esm implementations something that is easy replace able it does only need filesystem it should need nothing more
@lholmquist it was not what we search for but it is today maybe the thing we search for let me explain:
Out of Historical Reason there where 1x Export per Package JSON then later with es2015 the package json got the import / export field which can store multiple exports.
This exports have also support for nested conditional exports thats the part that your posting.
So the Field is only supported by current tooling every tooling today supports them as far as i know. If not support can be added in less then a day.
the --condition flag lets you choose one set of imports/exports.
Also i can announce the landing of require esm inside NodeJS 22+
require('es-module.js')
works under a flag if the ESM does not contain top level await at last.
Create ESM-only packages and only use the module field. Call it a day.
Use the -r esm flag to require the ESM NPM module to activate user-land support for require(esm-module.js) with additional support for top-level await as a migration path.
From Node.js 22+ onward, migrate to --experimental-require-module and -r esm until the other flag works.
From Node.js 22.x+ when the experimental flag gets an opt-out flag, call it a day. We will have resolved the ambiguity. Top-level import can import ESM and CJS code, and require can do the same. While everything should get transpiled to ESM for analyzability and tooling.
should annoy people to produce only exports["string"] = assignments and do avoid module.exports as migration path also exports.name = any is total ok simple let them avoid module.exports = and we wre good to go
Special edge case electron and other runtimes consuming npm
There are cases where .cjs is needed they will simple need to create a cjs entrypoint inside that single application where they use the modules they should not publish that application but if they wish to publish it then they simple publish it with a post install transpil to cjs hook or again use the -r esm flag
Activity
ljharb commentedon Oct 12, 2022
Given that by far the easiest way is “only publish CJS”, and if you want named exports, “publish CJS transpiled from ESM” - what more would go in this document?
lemanschik commentedon Nov 27, 2022
ljharb commentedon Nov 27, 2022
@lemanschik i strongly disagree with that; a default export is what a module is; named exports are what module has, and most modules should be something. That’s a stylistic choice and not something node should be weighing in on. I, and the Airbnb style guide ftr, say that you should almost always do module.exports = function.
lemanschik commentedon Nov 27, 2022
ljharb commentedon Nov 27, 2022
I have a number of projects that work perfectly compatibly with a build process, so I’m not sure about those reports.
lemanschik commentedon Nov 27, 2022
lemanschik commentedon Nov 28, 2022
lemanschik commentedon Nov 28, 2022
lemanschik commentedon Nov 28, 2022
lemanschik commentedon Nov 28, 2022
lemanschik commentedon Nov 28, 2022
lemanschik commentedon Nov 29, 2022
ljharb commentedon Nov 29, 2022
What is the benefit of doing all this when “just CJS” works everywhere?
lemanschik commentedon Nov 29, 2022
@ljharb i am happy that you ask for example it makes total new forms of builds more enjoyable and compose able at present we have overall good results with opening component based ipc specifiers inside chromium and v8 it self. this leads to stuff like running the monaco editor as chrome extension directly then using workspaces and overrides and then directly use unmodified directly loaded modules out of the npm ecosystem in a way that i can patch and replace them or use single functions of them to compose something total diffrent
It is simply expressiv when i can write
and get all original source references without parsing generating and all that of tons of import maps in facts i am also working mean while on building the whole chromium platform in a browser in a virtual x86 vm running on wasm and other stuff also directly exposing remote filesystems for distributed builds via webrtc and such stuff it helps a lot if we do not need to add incremental build steps and can directly cache distributed incremental build results
note also collabing on MESON Build system written in ECMAScript that opens up building NodeJS inside the browser distributed.
we talk about projects with a lot of dynamic references and far more then some million well documented symbols.
17 remaining items
vostrik commentedon Dec 9, 2022
@lemanschik thank you so much for this detailed response.
I've just read all of your replies including tiny book and small discussion in TS repo by links above.
I appreciate it.
But I also have 2 theses:
Create doc on how to support ESM and CommonJS when publishing modules. That's why we should focus on current ecosystem state and document it. Of course with simplicity criteria as u described.Let me repeat my suggestion:
@ljharb, @mhdawson tell me please, what do you think about my propose and about maybe(!) a little bit off-topic vibe from previous messages.
P. S. @lemanschik I really appreciate your thoughts and even ready to participate in PoC of your idea if needed.
lemanschik commentedon Dec 10, 2022
ljharb commentedon Dec 10, 2022
@lemanschik can you please stop posting dozens of essays? The thread is already impossibly long to read.
lemanschik commentedon Dec 10, 2022
execution strategy lets move npm it self into the browser via replacing the nativ parts with esm implementations something that is easy replace able it does only need filesystem it should need nothing more
ljharb commentedon Dec 10, 2022
That’s not likely to happen, and either way it’s entirely off topic for this thread.
This is about documenting what is, not trying to imagine a different reality.
lemanschik commentedon Dec 10, 2022
@ljharb that is the current case but no one uses it please bring up blockers.
mhdawson commentedon Jan 19, 2023
@ljharb doc where you can fill in the approach you discussed - https://docs.google.com/document/d/1NIYPxF4OsVBX3ES9Gx48pomZlWtQNG1NIiY9aRSpp8k/edit
lholmquist commentedon Jun 4, 2024
Found this on the node.js docs: https://nodejs.org/api/packages.html#dual-commonjses-module-packages
Does this cover what we wanted?
frank-dspeed commentedon Jun 5, 2024
@lholmquist it was not what we search for but it is today maybe the thing we search for let me explain:
Out of Historical Reason there where 1x Export per Package JSON then later with es2015 the package json got the import / export field which can store multiple exports.
This exports have also support for nested conditional exports thats the part that your posting.
So the Field is only supported by current tooling every tooling today supports them as far as i know. If not support can be added in less then a day.
the --condition flag lets you choose one set of imports/exports.
Also i can announce the landing of require esm inside NodeJS 22+
works under a flag if the ESM does not contain top level await at last.
lemanschik commentedon Jul 2, 2024
I would propose the following path forward now:
-r esmflag to require the ESM NPM module to activate user-land support forrequire(esm-module.js)with additional support for top-level await as a migration path.--experimental-require-moduleand-r esmuntil the other flag works.requirecan do the same. While everything should get transpiled to ESM for analyzability and tooling.Special edge case electron and other runtimes consuming npm
There are cases where .cjs is needed they will simple need to create a cjs entrypoint inside that single application where they use the modules they should not publish that application but if they wish to publish it then they simple publish it with a post install transpil to cjs hook or again use the -r esm flag
ESM -r esm as migration path is green for
AugustinMauroy commentedon Jan 11, 2025
https://nodejs.org/en/learn/modules/publishing-a-package fix this issue
bjohansebas commentedon Jan 7, 2026
fixed by https://github.com/nodejs/package-examples and https://nodejs.org/en/learn/modules/publishing-a-package