Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recommend node/default conditions instead of require/import as a solution to the dual package hazard #52174

Open
nicolo-ribaudo opened this issue Mar 21, 2024 · 6 comments · May be fixed by #53873
Labels
doc Issues and PRs related to the documentations. good first issue Issues that are suitable for first-time contributors.

Comments

@nicolo-ribaudo
Copy link
Contributor

Affected URL(s)

https://nodejs.org/api/packages.html#dual-package-hazard

Description of the problem

Publishing packages with dual CommonJS and ESM sources, while has the benefits of supporting both CJS consumers and ESM-only platforms, is known to cause problems because Node.js might load both versions. Example:

package.json foo.cjs foo.mjs
{
  "name": "foo",
  "exports": {
    "require": "./foo.cjs",
    "import": "./foo.mjs"
  }
}
exports.object = {};     
export const object = {};     
package.json bar.js
{
  "name": "bar",
  "main": "./bar.js"
}
const foo = require("foo");
exports.object = foo.object;     
// my app

import { object as fooObj } from "foo";
import { object as barObj } from "bar";

console.log(fooObj === barObj); // false?????

The two suggested solutions boil down to "even when you have an ESM entrypoint, still use only CJS internallly". This solves the dual package hazard, but completely defeats the cross-platform benefits of dual modules.

If foo instead used these export conditions:

{
  "name": "foo",
  "exports": {
    "node": "./foo.cjs",
    "default": "./foo.mjs"
  }
}

Then:

  • there would be no dual-package hazard in Node.js, because it only ever loads the CommonJS version
  • there would be no dual-package hazard in bundlers, because they would only ever load either the node version (if they are configured to target Node.js) or the default version (if they are configured to target other platforms).
  • the package solves the dual-package hazard while still providing an ESM-only version

We have been using this node/default pattern in @babel/runtime for a couple years, because we wanted to provide an ESM-only version for browsers while still avoiding the dual-package hazard (@babel/runtime is mostly stateless, but @babel/runtime/helpers/temporalUndefined relies on object identity of an object defined in a separate file).

@nicolo-ribaudo nicolo-ribaudo added the doc Issues and PRs related to the documentations. label Mar 21, 2024
@joyeecheung joyeecheung added the good first issue Issues that are suitable for first-time contributors. label Apr 11, 2024
@joyeecheung
Copy link
Member

Looks like a good first issue. Relevant file is https://github.com/nodejs/node/blob/main/doc/api/packages.md

@eliphazbouye
Copy link
Contributor

@joyeecheung , @nicolo-ribaudo this issue is still relevant ?

@joyeecheung
Copy link
Member

joyeecheung commented Apr 26, 2024

Yes, IMO the doc can still be improved as suggested in the OP.

@mews6
Copy link

mews6 commented May 19, 2024

Is there still work to be done here?

@joyeecheung
Copy link
Member

joyeecheung commented Sep 1, 2024

In #54648 which adds a new pattern I realize that it just doesn't seem appropriate to document them this way in the API docs. To quote my comments:

  1. It teaches opinionated practices that some consider dangerous
  2. It will soon be obsolete when we unflag --experimental-require-module.
  3. It's difficult to understand a multi-file structure via long texts and snippets in a (rendered) markdown document.

I think they should just be placed in their own example repo with some notes on pros/cons and maybe links to threads of discussions. But anyway API docs is the wrong place for them.

@B4nan
Copy link

B4nan commented Sep 4, 2024

It will soon be obsolete when we unflag --experimental-require-module.

May I ask if there is some schedule for unflagging this? Given the node 22 LTS is nearby, any chance it would happen with that version already?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
doc Issues and PRs related to the documentations. good first issue Issues that are suitable for first-time contributors.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants