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
The output file should be referenced in the `types` field or `exports['.'].types` field of `package.json`.
274
+
The output file should be referenced in the `exports['.'].types` field of `package.json`.
275
+
276
+
If you need to support legacy setups that use `moduleResolution: node10` or `moduleResolution: node`, you can also add a `types` field to the `package.json` file that points to the output file.
Copy file name to clipboardExpand all lines: docs/pages/esm.md
+68-3Lines changed: 68 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -60,9 +60,11 @@ The `./package.json` field is used to point to the library's `package.json` file
60
60
61
61
> 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.
62
62
63
-
## Dual package setup
63
+
## Legacy environments
64
64
65
-
The previously mentioned setup only works with tools that support ES modules. If you want to support tools that don't support ESM and use the CommonJS module system, you can set up a dual package setup.
65
+
The previously mentioned setup only works with tools that support ES modules. If you want to support tools that don't support ESM and use the CommonJS module system, there are a few approaches you can take.
66
+
67
+
### Dual package setup
66
68
67
69
A dual package setup means that you have 2 builds of your library: one for ESM and one for CommonJS. The ESM build is used by tools that support ES modules, while the CommonJS build is used by tools that don't support ES modules.
68
70
@@ -161,7 +163,70 @@ Putting it all together, the fields in your `package.json` file should look like
161
163
}
162
164
```
163
165
164
-
> **Important:** With this approach, the ESM and CommonJS versions of the package are treated as separate modules by Node.js as they are different files, leading to [potential issues](https://nodejs.org/docs/latest-v19.x/api/packages.html#dual-package-hazard) if the package is both imported and required in the same runtime environment. If the package relies on any state that can cause issues if 2 separate instances are loaded, it's necessary to isolate the state into a separate CommonJS module that can be shared between the ESM and CommonJS builds.
166
+
#### Dual package hazard
167
+
168
+
With this approach, the ESM and CommonJS versions of the package are treated as separate modules by Node.js as they are different files. On Node.js, `import` will load the ESM package and `require` will load the CommonJS package, leading to [potential issues](https://nodejs.org/docs/latest-v19.x/api/packages.html#dual-package-hazard) if the package is both imported and required in the same runtime environment.
169
+
170
+
If the library relies on any state that can cause issues if 2 separate instances are loaded (e.g. global state, 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.
171
+
172
+
### CommonJS-first setup
173
+
174
+
The simplest way to avoid dual package hazard is to use a CommonJS-first setup.
175
+
176
+
With this approach, Node.js will always use the CommonJS build - so two versions of the same package won't be loaded, while the ESM build can optionally be used by some tools such as bundlers (e.g. [Webpack](https://webpack.js.org/) and [Rollup](https://rollupjs.org/)) that use the ESM build for tree-shaking).
177
+
178
+
To configure a CommonJS-first setup, you can follow these steps:
179
+
180
+
1. Add the `commonjs` target to the `react-native-builder-bob` field in your `package.json` or `bob.config.js`:
181
+
182
+
```diff
183
+
"react-native-builder-bob": {
184
+
"source": "src",
185
+
"output": "lib",
186
+
"targets": [
187
+
["module", { "esm": true }],
188
+
+ "commonjs",
189
+
"typescript",
190
+
]
191
+
}
192
+
```
193
+
194
+
Optionally, remove the `module` target if you don't need the ESM build at all.
195
+
196
+
2. Change the `main` and `default` fields to point the CommonJS build instead:
197
+
198
+
```diff
199
+
- "main": "./lib/module/index.js",
200
+
+ "main": "./lib/commonjs/index.js",
201
+
"exports": {
202
+
".": {
203
+
"types": "./lib/typescript/src/index.d.ts",
204
+
- "default": "./lib/module/index.js"
205
+
+ "default": "./lib/commonjs/index.js"
206
+
},
207
+
"./package.json": "./package.json"
208
+
},
209
+
```
210
+
211
+
Here, tools that support the `exports` field will use the CommonJS build when importing or requiring the library, while tools that don't support the `exports` field will fall back to the `main` field.
212
+
213
+
Optionally, you can add a `module` field under `exports` to point to the ESM build for bundlers:
214
+
215
+
```diff
216
+
"main": "./lib/commonjs/index.js",
217
+
"exports": {
218
+
".": {
219
+
"types": "./lib/typescript/src/index.d.ts",
220
+
+ "module": "./lib/module/index.js"
221
+
"default": "./lib/commonjs/index.js"
222
+
},
223
+
"./package.json": "./package.json"
224
+
},
225
+
```
226
+
227
+
Note that [Metro](https://metrobundler.dev) doesn't support the `module` field. So it will always use the CommonJS build.
228
+
229
+
Alternatively, you can drop the `exports` field altogether and use the `main` field to point to the CommonJS build and `module` field to point to the ESM build. However, you will lose the benefits of the `exports` field, such as restricted access to the package's internals and [conditional exports](https://nodejs.org/api/packages.html#conditional-exports).
0 commit comments