-
Notifications
You must be signed in to change notification settings - Fork 14
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
Call out singleton module concerns around dual-mode packages #10
Comments
You can search around github to see this problem of having 2 modules trying to act as if they are a single module in various places like the create-react-app issue tracker as well. Not only is let id = 0;
export function foo() {
return {id: id++};
} and let id = 0;
module.exports = {
foo: function foo() {
return {id: id++};
}
} |
Yes, instanceof was just one. The issue title tries to capture the general concern by calling it "singleton module concerns". E.g. any concerns connected to there suddenly being two instances of the same package. |
When would the same project import both the ESM and the CommonJS versions of the same module? If I’m writing a project in ESM, wouldn’t all my I guess is the use case an “in migration” project where some of my files are ESM and some are still CommonJS, and the CommonJS files |
@GeoffreyBooth but other 3rd party packages could be using |
I’m not sure this really is resolvable. Say I create a package like this: package.json {
"name": "sneaky-package",
"main": "./cjs.js",
"exports": "./esm.mjs"
} cjs.js module.exports = function () {
console.log('Arrr! X marks the spot!');
} esm.mjs export default function () {
console.log('Arrr! O marks the spot!');
} These really are two distinct packages. Even if we looked at the module map to see that |
At its core, I do agree with what @GeoffreyBooth is saying. I don't think this is something that necessarily needs a technical solution. But we can (try to) be helpful. E.g. we could write a deprecation warning when the same module is loaded in both ways. Or we could publish clear guidance for package maintainers that warns of these issues and points out design patterns. |
I'm fine with either, I'd also be fine with throwing if both fields exist. |
I don’t think we need to throw purely if both fields exist; that would effectively prohibit dual-mode packages. Instead we could throw if both versions are loaded. The question is, do we need to throw if both versions are loaded anywhere in the module graph, or only if both are loaded into the same package? Like if my app imports |
@GeoffreyBooth that boundary does not necessarily protect you. |
@GeoffreyBooth Pretend |
Okay, so is my conclusion correct then? We only throw if both the CommonJS and ESM versions of a dual-mode package are loaded? @bmeck would it be feasible to update Node to take advantage of package boundaries to gain “protection,” or is that just not possible because of I’m sure various very good reasons? How does Node deal with two different versions of the same module being loaded by an app? For example, my app directly imports |
Since exports is now used in CJS as well, this shouldn't apply anymore. At most we would shadow main in both ESM and CJS iff we bring back dot-main. |
The solution to allow two independent entrypoints for CJS and ESM introduces one fundamental issue which is that there are now potentially two copies of the module. Example:
A user of this library might attempt the following:
This problem appeared in the wild in GraphQL.
/cc @bmeck who reported this issue.
The text was updated successfully, but these errors were encountered: