@@ -183,25 +183,75 @@ versions of Node.js, but its capabilities are limited: it only defines the main
183183entry point of the package.
184184
185185The `"exports"` field provides an alternative to `"main"` where the package
186- main entry point can be defined while also encapsulating the package, preventing
187- any other entry points besides those defined in `"exports"`. If package entry
188- points are defined in both `"main"` and `"exports"`, the latter takes precedence
189- in versions of Node.js that support `"exports"`. [Conditional Exports][] can
190- also be used within `"exports"` to define different package entry points per
191- environment, including whether the package is referenced via `require` or via
192- `import`.
186+ main entry point can be defined while also encapsulating the package,
187+ **preventing any other entry points besides those defined in `"exports"`**.
188+ This encapsulation allows module authors to define a public interface for
189+ their package.
193190
194191If both `"exports"` and `"main"` are defined, the `"exports"` field takes
195- precedence over `"main"`.
192+ precedence over `"main"`. `"exports"` are not specific to ES modules or
193+ CommonJS; `"main"` will be overridden by `"exports"` if it exists. As such
194+ `"main"` cannot be used as a fallback for CommonJS but it can be used as a
195+ fallback for legacy versions of Node.js that do not support the `"exports"`
196+ field.
197+
198+ [Conditional Exports][] can be used within `"exports"` to define different
199+ package entry points per environment, including whether the package is
200+ referenced via `require` or via `import`. For more information about supporting
201+ both CommonJS and ES Modules in a single package please consult
202+ [the dual CommonJS/ES module packages section][].
203+
204+ **Warning**: Introducing the `"exports"` field prevents consumers of a package
205+ from using any entry points that are not defined, including the `package.json`
206+ (e.g. `require('your-package/package.json')`. **This will likely be a breaking
207+ change.**
208+
209+ To make the introduction of `"exports"` non-breaking, ensure that every
210+ previously supported entry point is exported. It is best to explicitly specify
211+ entry points so that the package’s public API is well-defined. For example,
212+ a project that previous exported `main`, `lib`,
213+ `feature`, and the `package.json` could use the following `package.exports`:
196214
197- Both `"main"` and `"exports"` entry points are not specific to ES modules or
198- CommonJS; `"main"` will be overridden by `"exports"` in a `require` so it is
199- not a CommonJS fallback.
215+ ```json
216+ {
217+ "name": "my-mod",
218+ "exports": {
219+ ".": "./lib/index.js",
220+ "./lib": "./lib/index.js",
221+ "./lib/index": "./lib/index.js",
222+ "./lib/index.js": "./lib/index.js",
223+ "./feature": "./feature/index.js",
224+ "./feature/index.js": "./feature/index.js",
225+ "./package.json": "./package.json"
226+ }
227+ }
228+ ```
229+
230+ Alternatively a project could choose to export entire folders:
231+
232+ ```json
233+ {
234+ "name": "my-mod",
235+ "exports": {
236+ ".": "./lib/index.js",
237+ "./lib": "./lib/index.js",
238+ "./lib/": "./lib/",
239+ "./feature": "./feature/index.js",
240+ "./feature/": "./feature/",
241+ "./package.json": "./package.json"
242+ }
243+ }
244+ ```
200245
201- This is important with regard to `require`, since `require` of ES module files
202- throws an error in all versions of Node.js. To create a package that works both
203- in modern Node.js via `import` and `require` and also legacy Node.js versions,
204- see [the dual CommonJS/ES module packages section][].
246+ As a last resort, package encapsulation can be disabled entirely by creating an
247+ export for the root of the package `"./": "./"`. This will expose every file in
248+ the package at the cost of disabling the encapsulation and potential tooling
249+ benefits this provides. As the ES Module loader in Node.js enforces the use of
250+ [the full specifier path][], exporting the root rather than being explicit
251+ about entry is less expressive than either of the prior examples. Not only
252+ will encapsulation be lost but module consumers will be unable to
253+ `import feature from 'my-mod/feature'` as they will need to provide the full
254+ path `import feature from 'my-mod/feature/index.js`.
205255
206256#### Main Entry Point Export
207257
@@ -1746,6 +1796,7 @@ success!
17461796[dynamic instantiate hook]: #esm_code_dynamicinstantiate_code_hook
17471797[import an ES or CommonJS module for its side effects only]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Import_a_module_for_its_side_effects_only
17481798[special scheme]: https://url.spec.whatwg.org/#special-scheme
1799+ [the full specifier path]: #esm_mandatory_file_extensions
17491800[the official standard format]: https://tc39.github.io/ecma262/#sec-modules
17501801[the dual CommonJS/ES module packages section]: #esm_dual_commonjs_es_module_packages
17511802[transpiler loader example]: #esm_transpiler_loader
0 commit comments