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

doc: update to package.exports docs #33074

Closed
wants to merge 24 commits into from
Closed
Changes from 22 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
77 changes: 62 additions & 15 deletions doc/api/esm.md
Expand Up @@ -183,25 +183,72 @@ versions of Node.js, but its capabilities are limited: it only defines the main
entry point of the package.

The `"exports"` field provides an alternative to `"main"` where the package
main entry point can be defined while also encapsulating the package, preventing
any other entry points besides those defined in `"exports"`. If package entry
points are defined in both `"main"` and `"exports"`, the latter takes precedence
in versions of Node.js that support `"exports"`. [Conditional Exports][] can
also be used within `"exports"` to define different package entry points per
environment, including whether the package is referenced via `require` or via
`import`.
main entry point can be defined while also encapsulating the package,
**preventing any other entry points besides those defined in `"exports"`**.
This encapsulation allows module authors to define a public interface for
their package.

If both `"exports"` and `"main"` are defined, the `"exports"` field takes
precedence over `"main"`.
precedence over `"main"`. `"exports"` are not specific to ES modules or
CommonJS; `"main"` will be overridden by `"exports"` if it exists. As such
`"main"` cannot be used as a fallback for CommonJS but it can be used as a
fallback for legacy versions of Node.js that do not support the `"exports"`
field.

[Conditional Exports][] can be used within `"exports"` to define different
package entry points per environment, including whether the package is
referenced via `require` or via `import`. For more information about supporting
both CommonJS and ES Modules in a single package please consult
[the dual CommonJS/ES module packages section][].

**Warning**: Introducing the `"exports"` field prevents consumers of a package
from using any entry points that are not defined, including the `package.json`
(e.g. `require('your-package/package.json')`. **This will likely be a breaking
change.**

To make the introduction of `"exports"` non-breaking, ensure that every
previously supported entry point is exported. It is best to explicitly specify
entry points so that the package’s public API is well-defined. For example,
a project that previous exported `main`, `lib`,
`feature`, and the `package.json` could use the following `package.exports`:

Both `"main"` and `"exports"` entry points are not specific to ES modules or
CommonJS; `"main"` will be overridden by `"exports"` in a `require` so it is
not a CommonJS fallback.
```json
{
"name": "my-mod",
"exports": {
".": "./lib/index.js",
"./lib": "./lib/index.js",
"./lib/index": "./lib/index.js",
"./lib/index.js": "./lib/index.js",
MylesBorins marked this conversation as resolved.
Show resolved Hide resolved
"./feature": "./feature/index.js",
"./feature/index.js": "./feature/index.js",
"./package.json": "./package.json"
}
}
```

Alternatively a project could choose to export entire folders:

```json
{
"name": "my-mod",
"exports": {
".": "./lib/index.js",
"./lib": "./lib/index.js",
"./lib/": "./lib/",
"./feature": "./feature/index.js",
"./feature/": "./feature/",
"./package.json": "./package.json"
}
}
```

This is important with regard to `require`, since `require` of ES module files
throws an error in all versions of Node.js. To create a package that works both
in modern Node.js via `import` and `require` and also legacy Node.js versions,
see [the dual CommonJS/ES module packages section][].
As a last resort, package encapsulation can be disabled entirely by creating an
export for the root of the package `"./": "./"`. This will expose every file in
jkrems marked this conversation as resolved.
Show resolved Hide resolved
the package at the cost of disabling encapsulation. As the ES Module loader in
Node.js will not resolve file extensions or an `index.js` exporting the root is
less expressive than either of the above examples as individuals will be unable
to `import feature from 'my-mod/feature'`.
MylesBorins marked this conversation as resolved.
Show resolved Hide resolved

#### Main Entry Point Export

Expand Down