I want to write a package. I prefer to use new (and cool) ESM syntax rather than commonjs, and (of course) want it to have maximum compatibility. So I write my code with ESM and convert them to commonjs.
But how can I write my package.json now?
type=module, main=index.mjs:type=commonjs, main=index.cjs, exports.import=index.mjs:import on node=12.It's there any way to resolve this?
Btw. In the plan, you say "want to encourage all packages, both ESM and CommonJS, to include an explicit type field"
But isn't the "Conditional exports" already did the job of "type" field, and even more powerfull than it?
Wait until pkg.exports lands. Then...
{
"type": "module",
"main": "compat-bundle.cjs",
"exports": {
"import": "esm-entry.js",
"require": "compat-bundle.cjs"
}
}
When pkg.exports is defined, pkg.main will be ignored by Node>=12 so it can be used for legacy support.
Aside: Let me know if you could use guidance on how to build the CJS bundle.
esm isn’t second-class just because .js means CJS; all “type” means is which parse goal the author prefers .js to mean (.mjs always means ESM and .cjs always means CJS).
I assume that when the author writes "still feels like esm is second-class" they mean that because in that example, type is set to commonjs, which sends a signal that the primary type of the package is CommonJS; but the original sources are ESM.
@GongT The best advice we have for you right now is in https://nodejs.org/api/esm.html#esm_dual_commonjs_es_module_packages. There are two extended examples there.
The situation will improve _this month_ when conditional exports is unflagged. Then the ideal scenario that you’re looking for will be achievable. The features that enable this should be backported to 12 (albeit still behind --experimental-modules) also in January; they might be unflagged in 12 in April, assuming all goes well with early adopters using the new features in Node 13. So the short version is, just wait a few weeks. Maybe publish your package as ESM-only for now and add the CommonJS version later in January or in April when that path becomes clear and optimized.
Really thanks for your reply! (and sorry for my bad english😇)
Yesterday I was confused by myself because I did not realize that main and type not bind with each other. They can be different. 😂
After re-read the doc (as @evanplaice mentioned), I was cleared about this.
I'm using TypeScript, and the good news is I do not have a internal state need to share.
So I'm simply compile sources twice. That was really confused me! because all files ends with .js (in different folder). I was not able to change my thought after switched to .mjs.
Now I know I'm doing wrong, I should set type=module and create cjs files with .cjs. Then all node version can require() my package without "ERR_REQUIRE_ESM".
I also found that TypeScript will support modify extension very soon. Maybe they are facing same issue.
I personally dislike the "ESM Wrapper" way, it is not Cool ESM first, and not work with tree shaking.
Nodejs release said v10 will "alive" more than 1 year. (longer if think about node v12 without flag)
After conditional exports is out, Will the main field becomes obsolete?
Here's one way you can do it, once conditional exports is unflagged. For the sake of this example I’ll assume your main entry point is index.ts, which becomes index.js or index.cjs or index.mjs; but it can be anything (main.ts, foo.ts, etc.).
/src - TypeScript files in here
/dist-commonjs/ - CommonJS output files in here, with either .cjs or .js extensions
/dist-commonjs/package.json - Just { "type": "commonjs" }
/dist-commonjs/index.js - (or .cjs) main entry point for CommonJS version of package
/dist-module/ - ES module output files in here, with either .mjs or .js extensions
/dist-module/package.json - Just { "type": "module" }
/dist-module/index.js - (or .mjs) main entry point for ES module version of package
/package.json:
type: module
main: ./dist-commonjs/index.js - For legacy Node versions
exports:
require: ./dist-commonjs/index.js - For modern Node when your package is required
import: ./dist-module/index.js
default: ./dist-module/index.js
Most helpful comment
I assume that when the author writes "still feels like esm is second-class" they mean that because in that example,
typeis set tocommonjs, which sends a signal that the primary type of the package is CommonJS; but the original sources are ESM.@GongT The best advice we have for you right now is in https://nodejs.org/api/esm.html#esm_dual_commonjs_es_module_packages. There are two extended examples there.
The situation will improve _this month_ when conditional exports is unflagged. Then the ideal scenario that you’re looking for will be achievable. The features that enable this should be backported to 12 (albeit still behind
--experimental-modules) also in January; they might be unflagged in 12 in April, assuming all goes well with early adopters using the new features in Node 13. So the short version is, just wait a few weeks. Maybe publish your package as ESM-only for now and add the CommonJS version later in January or in April when that path becomes clear and optimized.