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

Dual package hazard #3

Closed
jcbhmr opened this issue Jun 9, 2023 · 1 comment
Closed

Dual package hazard #3

jcbhmr opened this issue Jun 9, 2023 · 1 comment

Comments

@jcbhmr
Copy link

jcbhmr commented Jun 9, 2023

This package seems to encounter the dual package hazard where the same code is bundled twice. Once for CJS and once for ESM in a final browser dist bundle. There's no actual published npm packages that have this as a dependency (yet), but I encountered this in dev like this: https://stackblitz.com/edit/vitejs-vite-4y95fw?file=html-prompt.js,node-util-types.cjs,main.js,dist%2Fassets%2Findex-bc7f32d1.js&terminal=dev
(simulated by one mjs file and one cjs file that could easily be actual package.json packages)

https://nodejs.org/api/packages.html#packages_dual_package_hazard

The fix to this is to use CJS as the main implementation, and either a) do nothing and let Node.js infer named exports or b) explicitly export things in a wrapper.mjs or similar file or c) only support ESM with NO CJS build

// wrapper.mjs
import moduleExports from "./index.cjs";
export const { a, b, c } = moduleExports;

There's an open issue on typescript github to support changing file extensions at tsc buildtime. That hasn't been encouraged since it's mostly used to cause the not-so-great dual package hazard. Instead TS team seems to recommend that you just build an ESM or CJS and then wrap it in another .mjs or .cjs file as a facade for the other module system. microsoft/TypeScript#49462

@isaacs
Copy link
Owner

isaacs commented Jun 15, 2023

I write almost all my packages as hybrids these days. (The only exceptions are purely CLI packages, where it's just easier to use ESM only, since there's no chance that someone might require() or import it.)

I assume that multiple instances of any node package might be present. Module uniqueness hasn't ever been guaranteed by npm; in fact just the opposite, if there are conflicting dependency versions, then multiple copies of a module may be present. I'm actually the person who made it that way, back in 2010. I disagree that the "dual module hazard" is a hazard at all, or at least, a new hazard related to dual modules; it should be called just "the module hazard", since all node packages have always been subject to it.

Since JavaScript modules may not ever assume that they are the only instance loaded, by design, and thus the "dual module hazard" imposes no additional hazards that are not already present without shipping dual modules, and shipping dual modules means that they work as expected with both import and require, I'm going to keep doing it.

It'd be nice if TSC would provide a way to emit .mjs/.cjs from a .ts file, which would save me having to write package.json files into my dist folder.

@isaacs isaacs closed this as completed Jun 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants