Skip to content

Commit 95bd4a2

Browse files
authored
feat: use a unique name for the exports condition for source (#948)
This is a breaking change for libraries that use `react-native-builder-bob/vite-config` They now must add the custom condition to their vite config. To preserve existing behavior, add `conditions: ['source']` under `resolve`: ```diff export default defineConfig((env) => mergeConfig(config(env), { resolve: { alias: { [pack.name]: new URL('..', import.meta.url), }, + conditions: ['source'], dedupe: Object.keys(pack.peerDependencies), }, }) ); ```
1 parent 4e6cfa8 commit 95bd4a2

16 files changed

Lines changed: 97 additions & 826 deletions

File tree

docs/pages/build.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ To configure your project manually, follow these steps:
7878
"types": "./lib/typescript/src/index.d.ts",
7979
"exports": {
8080
".": {
81-
"source": "./src/index.tsx",
8281
"types": "./lib/typescript/src/index.d.ts",
8382
"default": "./lib/module/index.js"
8483
},

docs/pages/esm.md

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ To make use of the output files, ensure that your `package.json` file contains t
4242
"types": "./lib/typescript/src/index.d.ts",
4343
"exports": {
4444
".": {
45-
"source": "./src/index.tsx",
45+
"my-library-source": "./src/index.tsx",
4646
"types": "./lib/typescript/src/index.d.ts",
4747
"default": "./lib/module/index.js"
4848
},
@@ -56,10 +56,57 @@ The `exports` field is used by Node.js 12+, modern browsers and tools to determi
5656

5757
Here, we specify 3 conditions:
5858

59-
- `source`: A custom condition used by `react-native-builder-bob` to determine the source file for the library.
59+
- `my-library-source`: A custom condition used to resolve the source file for the library in development.
6060
- `types`: Used for the TypeScript definitions.
6161
- `default`: Used for the actual JS code when the library is imported or required.
6262

63+
When creating a project, a custom condition name pointing to the source code is automatically set. You can also change it to something else if you want by updating any occurrences in your project.
64+
65+
TypeScript can resolve the source condition by adding it to [`customConditions`](https://www.typescriptlang.org/tsconfig/#customConditions):
66+
67+
```json
68+
{
69+
"compilerOptions": {
70+
"customConditions": ["my-library-source"]
71+
}
72+
}
73+
```
74+
75+
When using [`react-native-monorepo-config`](https://github.com/satya164/react-native-monorepo-config), pass the same condition to Metro so the example app resolves the library source:
76+
77+
```js
78+
const config = withMetroConfig(getDefaultConfig(__dirname), {
79+
root,
80+
dirname: __dirname,
81+
conditions: ['my-library-source'],
82+
});
83+
```
84+
85+
If you use [Jest](https://jestjs.io), add the source condition to [`testEnvironmentOptions.customExportConditions`](https://jestjs.io/docs/configuration#testenvironmentoptions-object). With the React Native Jest preset, keep React Native's default conditions as well:
86+
87+
```json
88+
{
89+
"jest": {
90+
"preset": "@react-native/jest-preset",
91+
"testEnvironmentOptions": {
92+
"customExportConditions": ["require", "react-native", "my-library-source"]
93+
}
94+
}
95+
}
96+
```
97+
98+
If you use [Vite](https://vitejs.dev), add the source condition to [`resolve.conditions`](https://vitejs.dev/config/#resolve-conditions):
99+
100+
```ts
101+
import { defineConfig } from 'vite';
102+
103+
export default defineConfig({
104+
resolve: {
105+
conditions: ['my-library-source'],
106+
},
107+
});
108+
```
109+
63110
You can also specify additional conditions for different scenarios, such as `react-native`, `browser`, `production`, `development` etc. Note that support for these conditions depends on the tooling you're using.
64111

65112
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)).
@@ -74,7 +121,7 @@ Using the `exports` field has a few benefits, such as:
74121
```diff
75122
"exports": {
76123
".": {
77-
"source": "./src/index.tsx",
124+
"my-library-source": "./src/index.tsx",
78125
"types": "./lib/typescript/src/index.d.ts",
79126
"default": "./lib/module/index.js"
80127
},
@@ -135,7 +182,6 @@ To configure a dual package setup, you can follow these steps:
135182
```
136183

137184
Here, we specify 2 conditions:
138-
139185
- `import`: Used when the library is imported with an `import` statement or a dynamic `import()`. It will point to the ESM build.
140186
- `require`: Used when the library is required with a `require` call. It will point to the CommonJS build.
141187

@@ -292,7 +338,6 @@ There are still a few things to keep in mind if you want your library to be ESM-
292338
```
293339

294340
Alternatively, if you want to be able to use the library in Node.js with `import` syntax, there are a few options:
295-
296341
- Use `Platform.select` instead of platform-specific extensions:
297342

298343
```js

docs/pages/faq.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ If your library depends on another react-native library containing native code,
3232
- **Add the native library to `peerDependencies`**
3333

3434
This means that the consumer of the library will need to install the native library and add it to the `dependencies` section of their `package.json`. It makes sure that:
35-
3635
- There are no version conflicts if another package also happens to use the same library, or if the user wants to use the library in their app. While there can be multiple versions of a JavaScript-only library, there can only be one version of a native library - so avoiding version conflicts is important.
3736
- The package manager installs it in correct location so that autolinking can work properly.
3837

@@ -51,7 +50,6 @@ If your library depends on another react-native library containing native code,
5150
Since this is a library, the `react-native` version specified in the `package.json` is not relevant for the consumers. It's only used for developing and testing the library. If you'd like to upgrade the `react-native` version to test with it, you'd need to:
5251

5352
1. **Bump versions of the following packages under `devDependencies` in the `package.json`:**
54-
5553
- `react-native`
5654
- `react`
5755
- `@types/react`
@@ -74,9 +72,8 @@ There are 2 parts to this process.
7472
1. **Aliasing the JavaScript code**
7573

7674
The JavaScript (or TypeScript) source code is aliased to be used by the example app. This makes it so that when you import from `'your-library-name'`, it imports the source code directly and avoids having to rebuild the library for JavaScript only changes. We configure several tools to make this work:
77-
78-
- [Metro](https://facebook.github.io/metro/) is configured to allow importing from outside of the `example` directory by configuring `watchFolders`, to use the appropriate peer dependencies, and to import source code of the library in the example. This configuration exists in the `example/metro.config.js` file.
79-
- [TypeScript](https://www.typescriptlang.org/) is configured to use the source code for type checking by using the `paths` property under `compilerOptions`. This configuration exists in the `tsconfig.json` file at the root.
75+
- [Metro](https://facebook.github.io/metro/) is configured to allow importing from outside of the `example` directory by configuring `watchFolders`, to use the appropriate peer dependencies, and to resolve the library's custom source condition. This configuration exists in the `example/metro.config.js` file.
76+
- [TypeScript](https://www.typescriptlang.org/) is configured to use the source code for type checking with the custom source condition and the `paths` property under `compilerOptions`. This configuration exists in the `tsconfig.json` file at the root.
8077

8178
2. **Linking the native code**
8279

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export const FALLBACK_BOB_VERSION = '0.41.0';
22
export const FALLBACK_NITRO_MODULES_VERSION = '0.35.3';
3-
export const SUPPORTED_MONOREPO_CONFIG_VERSION = '0.3.3';
3+
export const SUPPORTED_MONOREPO_CONFIG_VERSION = '0.4.0';
44
export const SUPPORTED_REACT_NATIVE_VERSION = '0.85.0';
55
export const SUPPORTED_EXPO_SDK_VERSION = '55';

packages/create-react-native-library/src/template.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export type TemplateConfiguration = {
3333
swift: boolean;
3434
viewConfig: ViewConfig;
3535
moduleConfig: ModuleConfig;
36+
sourceCondition: string;
3637
};
3738
author: {
3839
name: string;
@@ -177,6 +178,8 @@ export function generateTemplateConfiguration({
177178
}
178179

179180
const project = slug.replace(/^(react-native-|@[^/]+\/)/, '');
181+
const sourceCondition = `${slug.replace(/^@/, '').replace(/\//g, '-')}-source`;
182+
180183
let namespace: string | undefined;
181184

182185
if (slug.startsWith('@') && slug.includes('/')) {
@@ -213,6 +216,7 @@ export function generateTemplateConfiguration({
213216
swift: languages === 'kotlin-swift',
214217
viewConfig: getViewConfig(type),
215218
moduleConfig: getModuleConfig(type),
219+
sourceCondition,
216220
},
217221
author: {
218222
name: authorName,

packages/create-react-native-library/templates/common/$package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"types": "./lib/typescript/src/index.d.ts",
77
"exports": {
88
".": {
9-
"source": "./src/index.tsx",
9+
"<%- project.sourceCondition -%>": "./src/index.tsx",
1010
"types": "./lib/typescript/src/index.d.ts",
1111
"default": "./lib/module/index.js"
1212
},

packages/create-react-native-library/templates/common/tsconfig.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66
},
77
"allowUnreachableCode": false,
88
"allowUnusedLabels": false,
9-
"customConditions": ["react-native-strict-api"],
9+
"customConditions": [
10+
"<%- project.sourceCondition -%>",
11+
"react-native-strict-api"
12+
],
1013
"esModuleInterop": true,
1114
"forceConsistentCasingInFileNames": true,
1215
"jsx": "react-jsx",

packages/create-react-native-library/templates/example-common/example/metro.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const root = path.resolve(__dirname, '..');
1313
const config = withMetroConfig(getDefaultConfig(__dirname), {
1414
root,
1515
dirname: __dirname,
16+
conditions: ['<%- project.sourceCondition -%>'],
1617
});
1718

1819
module.exports = config;

packages/create-react-native-library/templates/tools/jest/~package.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44
},
55
"jest": {
66
"preset": "@react-native/jest-preset",
7+
"testEnvironmentOptions": {
8+
"customExportConditions": [
9+
"require",
10+
"react-native",
11+
"<%- project.sourceCondition -%>"
12+
]
13+
},
714
"modulePathIgnorePatterns": [
815
"<rootDir>/example/node_modules",
916
"<rootDir>/lib/"

packages/create-react-native-library/templates/tools/vite/example/vite.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export default defineConfig((env) =>
99
alias: {
1010
[pack.name]: new URL('..', import.meta.url),
1111
},
12+
conditions: ['<%- project.sourceCondition -%>'],
1213
dedupe: Object.keys(pack.peerDependencies),
1314
},
1415
})

0 commit comments

Comments
 (0)