To set the main entry point for a package, it is advisable to define both "exports" and "main" in the package’s package.json file:
{
"main": "./main.js",
"exports": "./main.js"
}
The benefit of doing this is that when using the "exports" field all subpaths of the package will no longer be available to importers under require('pkg/subpath.js'), and instead they will get a new error, ERR_PACKAGE_PATH_NOT_EXPORTED.
This encapsulation of exports provides more reliable guarantees about package interfaces for tools and when handling semver upgrades for a package. It is not a strong encapsulation since a direct require of any absolute subpath of the package such as require('/path/to/node_modules/pkg/subpath.js') will still load subpath.js.
Also the order within exports (and the order within exportssubpaths, e.g., {exports: {"./feature": {browser: "./feature-browser.js", default: "./feature.js"}} and within nested conditions, e.g., {"exports": {"import": {"node": "./feature-node.mjs"}}}) could be enforced per https://nodejs.org/api/esm.html#esm_conditional_exports :
"node" - matched for any Node.js environment. Can be a CommonJS or ES module file. This condition should always come after "import" or "require".
"default" - the generic fallback that will always match. Can be a CommonJS or ES module file. This condition should always come last.
Per https://nodejs.org/api/esm.html#esm_main_entry_point_export
Also the order within
exports
(and the order withinexports
subpaths, e.g.,{exports: {"./feature": {browser: "./feature-browser.js", default: "./feature.js"}}
and within nested conditions, e.g.,{"exports": {"import": {"node": "./feature-node.mjs"}}}
) could be enforced per https://nodejs.org/api/esm.html#esm_conditional_exports :