Skip to content

docs: add guidelines for ESM support #597

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

Merged
merged 1 commit into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/pages/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"index": "Introduction",
"create": "Scaffold a library",
"build": "Build a library",
"esm": "ESM support",
"faq": "FAQ"
}
8 changes: 3 additions & 5 deletions docs/pages/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ yarn add --dev react-native-builder-bob
"source": "src",
"output": "lib",
"targets": [
["commonjs", { "esm" : true }],
["module", { "esm" : true }],
["commonjs", { "esm": true }],
["module", { "esm": true }],
"typescript",
]
}
Expand Down Expand Up @@ -166,9 +166,7 @@ In addition, the following options are supported:

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.

This mainly adds file extensions to the imports and exports. Note that file extensions are not added when importing a file that may have platform-specific extensions (e.g. `.android.ts`) to avoid breaking tools.

If you use TypeScript, also make sure to set `"moduleResolution": "Bundler"` in your `tsconfig.json` file.
See the [ESM support](./esm.md) guide for more details.

##### `configFile`

Expand Down
55 changes: 55 additions & 0 deletions docs/pages/esm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# ESM support

Libraries created with [`create-react-native-library`](./create.md) are pre-configured to work with ESM (ECMAScript Modules) out of the box.

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:

```json
"react-native-builder-bob": {
"source": "src",
"output": "lib",
"targets": [
["commonjs", { "esm" : true }],
["module", { "esm" : true }],
"typescript",
]
}
```

The `"esm": true` option enables ESM-compatible output. Here's what it does:

- It adds the `.js` extension to the import statements in the generated files.
- It creates a `package.json` file in the output directory with the content: `{ "type": "module" }`

In addition, it's necessary to specify `"moduleResolution": "Bundler"` in your `tsconfig.json` file:

```json
{
"compilerOptions": {
"moduleResolution": "Bundler"
}
}
```

This means that you don't need to specify the file extension in the import statements. They'll be automatically added when possible during the build process.

## Guidelines

There are still a few things to keep in mind if you want your library to be ESM-compatible:

- 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 the library uses platform-specific extensions (e.g., `.ios.js` or `.android.js`), the ESM output will not be compatible with Node.js. 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. Bundlers such as Webpack (with [`resolve.fullySpecified: false`](https://webpack.js.org/configuration/module/#resolvefullyspecified)) or Metro can handle this. It's still possible to `require` the CommonJS build directly in Node.js.
- Avoid using `.cjs`, `.mjs`, `.cts` or `.mts` extensions. Metro always requires file extensions in import statements when using `.cjs` or `.mjs` which breaks platform-specific extension resolution.
- Avoid using `"moduleResolution": "Node16"` or `"moduleResolution": "NodeNext"` in your `tsconfig.json` file. They require file extensions in import statements which breaks platform-specific extension resolution.
- If you specify a `react-native` condition in `exports`, make sure that it comes before `import` or `require`. The conditions should be ordered from the most specific to the least specific:

```json
"exports": {
".": {
"types": "./lib/typescript/src/index.d.ts",
"react-native": "./lib/modules/index.native.js",
"import": "./lib/modules/index.js",
"require": "./lib/commonjs/index.js"
}
}
```
Loading