Skip to content

Commit

Permalink
docs: add guidelines for ESM support
Browse files Browse the repository at this point in the history
  • Loading branch information
satya164 committed Jul 23, 2024
1 parent a7c9ae0 commit df50192
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 5 deletions.
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"
}
}
```

0 comments on commit df50192

Please sign in to comment.