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
+73-22Lines changed: 73 additions & 22 deletions
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,7 @@
1
1
# ESM support
2
2
3
+
## Default setup
4
+
3
5
Libraries created with [`create-react-native-library`](./create.md) are pre-configured to work with ESM (ECMAScript Modules) out of the box.
4
6
5
7
You can verify whether ESM support is enabled by checking the configuration for [`react-native-builder-bob`](./build.md) in the `package.json` file of the library:
@@ -58,11 +60,16 @@ You can also specify additional conditions for different scenarios, such as `rea
58
60
59
61
The `./package.json` field is used to point to the library's `package.json` file. It's necessary for tools that may need to read the `package.json` file directly (e.g. [React Native Codegen](https://reactnative.dev/docs/the-new-architecture/what-is-codegen)).
60
62
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.
63
+
Using the `exports` field has a few benefits, such as:
64
+
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.
62
69
63
70
## Dual package setup
64
71
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.
72
+
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
73
67
74
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
75
@@ -82,25 +89,7 @@ To configure a dual package setup, you can follow these steps:
82
89
}
83
90
```
84
91
85
-
2. Optionally change the `main` field in your `package.json` to point to the CommonJS build:
86
-
87
-
```diff
88
-
- "main": "./lib/module/index.js",
89
-
+ "main": "./lib/commonjs/index.js",
90
-
```
91
-
92
-
This is needed if you want to support tools that don't support the `exports` field and need to use the CommonJS build.
93
-
94
-
3. Optionally add a `module` field in your `package.json` to point to the ESM build:
95
-
96
-
```diff
97
-
"main": "./lib/commonjs/index.js",
98
-
+ "module": "./lib/module/index.js",
99
-
```
100
-
101
-
The `module` field is a non-standard field that some tools use to determine the ESM entry point.
102
-
103
-
4. Change the `exports` field in your `package.json` to include 2 conditions:
92
+
2. Change the `exports` field in your `package.json` to include 2 conditions:
104
93
105
94
```diff
106
95
"exports": {
@@ -128,7 +117,62 @@ To configure a dual package setup, you can follow these steps:
128
117
129
118
The `default` field is the fallback entry point for both conditions. It's used for the actual JS code when the library is imported or required.
130
119
131
-
> **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.
120
+
3. Optionally change the `main` field in your `package.json` to point to the CommonJS build:
121
+
122
+
```diff
123
+
- "main": "./lib/module/index.js",
124
+
+ "main": "./lib/commonjs/index.js",
125
+
```
126
+
127
+
This is needed if you want to support tools that don't support the `exports` field and need to use the CommonJS build.
128
+
129
+
4. Optionally add a `module` field in your `package.json` to point to the ESM build:
130
+
131
+
```diff
132
+
"main": "./lib/commonjs/index.js",
133
+
+ "module": "./lib/module/index.js",
134
+
```
135
+
136
+
The `module` field is a non-standard field that some tools use to determine the ESM entry point.
137
+
138
+
5. Optionally add a `types` field in your `package.json` to point to the CommonJS type definitions:
This is necessary to support legacy TypeScript setup, i.e. which have `moduleResolution: "node10"` or `moduleResolution: "node"` under the `compilerOptions` section in the `tsconfig.json`.
147
+
148
+
Putting it all together, the fields in your `package.json` file should look like this:
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.
174
+
175
+
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.
132
176
133
177
## Guidelines
134
178
@@ -189,3 +233,10 @@ There are still a few things to keep in mind if you want your library to be ESM-
189
233
"./package.json": "./package.json"
190
234
}
191
235
```
236
+
237
+
## References
238
+
239
+
-[Node.js documentation on ESM](https://nodejs.org/docs/latest/api/esm.html)
0 commit comments