Skip to content
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

feat: add esm build option for typescript #603

Merged
merged 1 commit into from
Aug 1, 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
21 changes: 16 additions & 5 deletions docs/pages/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ yarn add --dev react-native-builder-bob
"targets": [
["commonjs", { "esm": true }],
["module", { "esm": true }],
"typescript",
["typescript", { "esm": true }]
]
}
```
Expand Down Expand Up @@ -76,12 +76,17 @@ yarn add --dev react-native-builder-bob
"source": "./src/index.tsx",
"main": "./lib/commonjs/index.js",
"module": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
"types": "./lib/typescript/commonjs/src/index.d.ts",
"exports": {
".": {
"types": "./typescript/src/index.d.ts",
"import": "./module/index.js",
"require": "./commonjs/index.js"
"import": {
"types": "./lib/typescript/module/src/index.d.ts",
"default": "./lib/module/index.js"
},
"require": {
"types": "./lib/typescript/commonjs/src/index.d.ts",
"default": "./lib/commonjs/index.js"
}
}
},
"files": [
Expand Down Expand Up @@ -224,6 +229,12 @@ Example:

The output file should be referenced in the `types` field or `exports['.'].types` field of `package.json`.

##### `esm`

Setting this option to `true` will output 2 sets of type definitions: one for the CommonJS build and one for the ES module build.

See the [ESM support](./esm.md) guide for more details.

## Commands

The `bob` CLI exposes the following commands:
Expand Down
18 changes: 12 additions & 6 deletions docs/pages/esm.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ You can verify whether ESM support is enabled by checking the configuration for
"targets": [
["commonjs", { "esm": true }],
["module", { "esm": true }],
"typescript",
["typescript", { "esm": true }]
]
}
```

The `"esm": true` option enables ESM-compatible output by adding the `.js` extension to the import statements in the generated files.
The `"esm": true` option enables ESM-compatible output by adding the `.js` extension to the import statements in the generated files. For TypeScript, it also generates 2 sets of type definitions: one for the CommonJS build and one for the ES module build.

It's recommended to specify `"moduleResolution": "Bundler"` in your `tsconfig.json` file as well:

Expand All @@ -43,10 +43,16 @@ There are still a few things to keep in mind if you want your library to be ESM-
```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"
"import": {
"types": "./lib/typescript/module/src/index.d.ts",
"react-native": "./lib/modules/index.native.js",
"default": "./lib/module/index.js"
},
"require": {
"types": "./lib/typescript/commonjs/src/index.d.ts",
"react-native": "./lib/commonjs/index.native.js",
"default": "./lib/commonjs/index.js"
}
}
}
```
2 changes: 1 addition & 1 deletion packages/create-react-native-library/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import generateExampleApp, {
import { spawn } from './utils/spawn';
import { version } from '../package.json';

const FALLBACK_BOB_VERSION = '0.28.0';
const FALLBACK_BOB_VERSION = '0.29.0';

const BINARIES = [
/(gradlew|\.(jar|keystore|png|jpg|gif))$/,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@
"source": "./src/index.tsx",
"main": "./lib/commonjs/index.js",
"module": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
"exports": {
".": {
"types": "./lib/typescript/src/index.d.ts",
"import": "./lib/module/index.js",
"require": "./lib/commonjs/index.js"
"import": {
"types": "./lib/typescript/module/src/index.d.ts",
"default": "./lib/module/index.js"
},
"require": {
"types": "./lib/typescript/commonjs/src/index.d.ts",
"default": "./lib/commonjs/index.js"
}
}
},
"files": [
Expand Down Expand Up @@ -178,7 +182,8 @@
[
"typescript",
{
"project": "tsconfig.build.json"
"project": "tsconfig.build.json",
"esm": true
}
]
]
Expand Down
64 changes: 41 additions & 23 deletions packages/react-native-builder-bob/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,14 +175,29 @@ yargs
entries.main = entries.source;
}

const types: {
[key in 'require' | 'import']?: string;
} = {};

if (targets.includes('typescript')) {
entries.types = `./${path.join(
types.require = `./${path.join(
output,
'typescript',
'commonjs',
source,
'index.d.ts'
)}`;

types.import = `./${path.join(
output,
'typescript',
'module',
source,
'index.d.ts'
)}`;

entries.types = types.require;

if (!(await fs.pathExists(path.join(root, 'tsconfig.json')))) {
const { tsconfig } = await prompts({
type: 'confirm',
Expand Down Expand Up @@ -258,9 +273,14 @@ yargs

const exports = {
'.': {
...(entries.types ? { types: entries.types } : null),
...(entries.module ? { import: entries.module } : null),
...(entries.main ? { require: entries.main } : null),
import: {
...(types.import ? { types: types.import } : null),
...(entries.module ? { default: entries.module } : null),
},
require: {
...(types.require ? { types: types.require } : null),
...(entries.main ? { default: entries.main } : null),
},
},
};

Expand Down Expand Up @@ -318,25 +338,23 @@ yargs
pkg.scripts.prepare = prepare;
}

if (
pkg.files &&
JSON.stringify(pkg.files.slice().sort()) !==
JSON.stringify(files.slice().sort())
) {
const { update } = await prompts({
type: 'confirm',
name: 'update',
message: `Your package.json already has a 'files' field.\n Do you want to update it?`,
initial: true,
});
if (pkg.files) {
const pkgFiles = pkg.files;

if (update) {
pkg.files = [
...files,
...pkg.files.filter(
(file: string) => !files.includes(file.replace(/\/$/g, ''))
),
];
if (files?.some((file) => !pkgFiles.includes(file))) {
const { update } = await prompts({
type: 'confirm',
name: 'update',
message: `Your package.json already has a 'files' field.\n Do you want to update it?`,
initial: true,
});

if (update) {
pkg.files = [
...files,
...pkg.files.filter((file: string) => !files.includes(file)),
];
}
}
} else {
pkg.files = files;
Expand All @@ -350,7 +368,7 @@ yargs
return [t, { copyFlow: true }];
}

if (t === 'commonjs' || t === 'module') {
if (t === 'commonjs' || t === 'module' || t === 'typescript') {
return [t, { esm }];
}

Expand Down
Loading
Loading