You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/pages/build.md
+4-2
Original file line number
Diff line number
Diff line change
@@ -176,7 +176,7 @@ In addition, the following options are supported:
176
176
177
177
##### `esm`
178
178
179
-
Setting this option to `true` will output ES modules compatible code for Node.js 12+, modern browsers and other tools that support `package.json`'s `exports` field.
179
+
Setting this option to `true` will output ES modules compatible code for Node.js 12+, modern browsers and tools that support `package.json`'s `exports` field.
180
180
181
181
See the [ESM support](./esm.md) guide for more details.
182
182
@@ -241,7 +241,9 @@ Example:
241
241
242
242
Enable compiling source files with Babel and use CommonJS module system. This is essentially the same as the `module` target and accepts the same options, but transforms the `import`/`export` statements in your code to `require`/`module.exports`.
243
243
244
-
This is useful for supporting usage of this module with `require` in Node versions older than 20 (it can still be used with `import` for Node.js 12+ if `module` target with `esm` is enabled), and some tools such as [Jest](https://jestjs.io). The output file should be referenced in the `main` field. If you have a [dual package setup](esm.md#dual-package-setup) with both ESM and CommonJS builds, it needs to be specified in `exports['.'].require` field of `package.json`.
244
+
This is useful for supporting tools that don't support ES modules yet, see [the Compatibility section in our ESM guide](./esm.md#compatibility) for more details.
245
+
246
+
The output file should be referenced in the `main` field. If you have a [dual package setup](esm.md#dual-package-setup) with both ESM and CommonJS builds, it needs to be specified in `exports['.'].require` field of `package.json`.
Copy file name to clipboardExpand all lines: docs/pages/esm.md
+42-12
Original file line number
Diff line number
Diff line change
@@ -63,9 +63,7 @@ The `./package.json` field is used to point to the library's `package.json` file
63
63
Using the `exports` field has a few benefits, such as:
64
64
65
65
- It [restricts access to the library's internals](https://nodejs.org/api/packages.html#main-entry-point-export) by default. You can explicitly specify which files are accessible with [subpath exports](https://nodejs.org/api/packages.html#subpath-exports).
66
-
- It allows you to specify different entry points for different environments with [conditional exports](https://nodejs.org/api/packages.html#conditional-exports) (e.g. `node`, `browser`, `react-native`, `production`, `development` etc.). More examples can be found in the [Webpack documentation](https://webpack.js.org/guides/package-exports/#conditions).
67
-
68
-
> Note: Metro enables support for `package.json` exports by default from version [0.82.0](https://github.com/facebook/metro/releases/tag/v0.82.0). In previous versions, experimental support can be enabled by setting the `unstable_enablePackageExports` option to `true` in the [Metro configuration](https://metrobundler.dev/docs/configuration/). If this is not enabled, Metro will use the entrypoint specified in the `main` field. Features such as [subpath exports](https://nodejs.org/api/packages.html#subpath-exports) and [conditional exports](https://nodejs.org/api/packages.html#conditional-exports) will not work when `exports` supported is not enabled.
66
+
- It allows you to specify different entry points for different environments with [conditional exports](https://nodejs.org/api/packages.html#conditional-exports) (e.g. `node`, `browser`, `module`, `react-native`, `production`, `development` etc.).
69
67
70
68
## Dual package setup
71
69
@@ -174,31 +172,63 @@ With this approach, the ESM and CommonJS versions of the package are treated as
174
172
175
173
If the library relies on any state that can cause issues if 2 separate instances are loaded (e.g. global state, constructors, react context etc.), it's necessary to isolate the state into a separate CommonJS module that can be shared between the ESM and CommonJS builds.
176
174
175
+
## Compatibility
176
+
177
+
[Node.js](https://nodejs.org) v12 and higher natively support ESM and the `exports` field. However, an ESM library can synchronously loaded in a CommonJS environment in only in recent Node.js versions. The following Node.js versions support synchronous `require()` for ESM libraries without any flags or warnings:
178
+
179
+
- v20.19.0 and higher (LTS)
180
+
- v22.12.0 and higher (LTS)
181
+
- v23.4.0 and higher
182
+
183
+
Older versions can still load your library asynchronously using `import()`.
184
+
185
+
Most modern tools such as [Webpack](https://webpack.js.org), [Rollup](https://rollupjs.org), [Vite](https://vitejs.dev) etc. also support ESM and the `exports` field. See the supported conditions in the [Webpack documentation](https://webpack.js.org/guides/package-exports/#conditions).
186
+
187
+
[Metro](https://metrobundler.dev) enables support for `package.json` exports by default from version [0.82.0](https://github.com/facebook/metro/releases/tag/v0.82.0). In previous versions, experimental support can be enabled by setting the [`unstable_enablePackageExports` option to `true`](https://metrobundler.dev/docs/package-exports/) in the Metro configuration. If this is not enabled, Metro will use the entrypoint specified in the `main` field. Features such as [subpath exports](https://nodejs.org/api/packages.html#subpath-exports) and [conditional exports](https://nodejs.org/api/packages.html#conditional-exports) will not work when `exports` supported is not enabled.
188
+
189
+
[Jest](https://jestjs.io) supports the `exports` field, but doesn't support ESM natively. Experimental support is [available under a flag](https://jestjs.io/docs/ecmascript-modules), but requires changes to how tests are written. It can still load ESM libraries using a transform such as [`babel-jest`](https://github.com/jestjs/jest/tree/main/packages/babel-jest).
190
+
177
191
## Guidelines
178
192
179
193
There are still a few things to keep in mind if you want your library to be ESM-compatible:
180
194
181
-
- Avoid using default exports in your library. Named exports are recommended. Default exports produce a CommonJS module with a `default` property, which will work differently than the ESM build and can cause issues.
195
+
- Avoid using default exports in your library. Named exports are recommended. Default exports produce a CommonJS module with a `default` property, which will work differently than the ESM build and can cause issues if you have a dual package setup. Needing to use `.default` in CommonJS environment may also be confusing for users.
182
196
- If the library uses platform-specific extensions (e.g., `.ios.js` or `.android.js`), the ESM output will not be compatible with Node.js, i.e. it's not possible to use the library in Node.js with `import` syntax. It's necessary to omit file extensions from the imports to make platform-specific extensions work, however, Node.js requires file extensions to be present.
183
197
184
-
Bundlers such as Metro can handle this without additional configuration. Other bundlers may need to be configured to make extensionless imports to work, (e.g. it's necessary to specify [`resolve.fullySpecified: false`](https://webpack.js.org/configuration/module/#resolvefullyspecified) for Webpack).
198
+
While Bob automatically adds file extensions to the import statements during the build process if `esm` is set to `true`, it will skip the imports that reference files with platform-specific extensions to avoid breaking the resolution.
199
+
200
+
Bundlers such as Metro can handle imports without file extensions for ESM without additional configuration. Other bundlers may need to be configured to make extensionless imports to work, (e.g. it's necessary to specify [`resolve.fullySpecified: false`](https://webpack.js.org/configuration/module/#resolvefullyspecified) for Webpack).
185
201
186
202
It's still possible to use the library in Node.js using the CommonJS build with `require`:
187
203
188
204
```js
189
205
const { foo } =require('my-library');
190
206
```
191
207
192
-
Alternatively, if you want to be able to use the library in Node.js with `import` syntax, you can use `require` to import code with platform-specific extensions in your library:
208
+
Alternatively, if you want to be able to use the library in Node.js with `import` syntax, there are a few options:
193
209
194
-
```js
195
-
// will import `foo.native.js`, `foo.ios.js`, `foo.js` etc.
196
-
const { foo } =require('./foo');
197
-
```
210
+
- Use `Platform.select` instead of platform-specific extensions:
211
+
212
+
```js
213
+
import { Platform } from'react-native';
214
+
215
+
constfoo=Platform.select({
216
+
android:require('./fooAndroid.js'),
217
+
ios:require('./fooIOS.js'),
218
+
default:require('./fooFallback.js'),
219
+
});
220
+
```
221
+
222
+
- Use `require` to import code with platform-specific extensions in your library:
223
+
224
+
```js
225
+
// will import `foo.native.js`, `foo.ios.js`, `foo.js` etc.
226
+
const { foo } = require('./foo');
227
+
```
198
228
199
-
Make sure to have a file without any platform-specific extensions that will be loaded by Node.js.
229
+
Make sure to have a file without any platform-specific extensions that will be loaded by Node.js.
200
230
201
-
Also note that if your module (e.g. `foo.js` in this case) contains ESM syntax, it will only work on Node.js 20 or newer.
231
+
Also note that if your module (e.g. `foo.js`inthis case) contains ESM syntax, it will only work on a recent Node.jsversion. See [Compatibility](#compatibility) section for more information.
202
232
203
233
- Avoid using `.cjs`, `.mjs`, `.cts` or `.mts`extensions. Metro always requires file extensions inimport statements when using `.cjs` or `.mjs` which breaks platform-specific extension resolution.
204
234
- Avoid using `"moduleResolution": "node16"` or `"moduleResolution": "nodenext"`in your `tsconfig.json`file. They require file extensions inimport statements which breaks platform-specific extension resolution.
0 commit comments