Skip to content

Commit 79c7c58

Browse files
huntiefacebook-github-bot
authored andcommitted
Document monorepo build setup (facebook#48420)
Summary: Pull Request resolved: facebook#48420 Adds a long overdue README for our newer monorepo build setup. Changelog: [Internal] Reviewed By: cipolleschi Differential Revision: D67740763 fbshipit-source-id: 0c7686d75272acf74c0af5a1c4c08336fb45e2a2
1 parent 2c338a7 commit 79c7c58

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed

scripts/build/README.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# scripts/build
2+
3+
Shared build setup for the React Native monorepo.
4+
5+
## Overview
6+
7+
These scripts form the modern build setup for JavaScript ([Flow](https://flow.org/)) packages in `react-native`, exposed as `yarn build`.
8+
9+
> [!Tip]
10+
> Generally, React Native maintainers do not need to run `yarn build`, as all packages will run from source during development. Please continue reading if you are adding/removing a package or modifying its build configuration.
11+
12+
#### Key info
13+
14+
- **Which packages are included?**
15+
- Currently, only Node.js-targeting packages are included, configured in `config.js`.
16+
- We don't yet include runtime packages (targeting Metro). These are instead transformed in user space via `@react-native/babel-preset`.
17+
- **When does the build run?**
18+
- Packages are built in CI workflows — both for integration/E2E tests, and before publishing to npm.
19+
20+
#### Limitations/quirks
21+
22+
> [!Note]
23+
> **🚧 Work in progress!** This is not the final state for our monorepo build tooling. Unfortunately, our solution options are narrow due to integration requirements with Meta's codebase.
24+
25+
- Running `yarn build` will mutate `package.json` files in place, resulting in a dirty Git working copy.
26+
- We make use of "wrapper files" (`.js``.js.flow`) for each package entry point, to enable running from source with zero config. To validate these, package entry points must be explicitly defined via `"exports"`.
27+
28+
## Usage
29+
30+
**💡 Reminder**: 99% of the time, there is no need to use `yarn build`, as all packages will run from source during development.
31+
32+
Build commands are exposed as npm scripts at the repo root.
33+
34+
```sh
35+
# Build all packages
36+
yarn build
37+
38+
# Build a specific package
39+
yarn build dev-middleware
40+
41+
# Clean build directories
42+
yarn clean
43+
```
44+
45+
Once built, developing in the monorepo should continue to work — now using the compiled version of each package.
46+
47+
> [!Warning]
48+
> **Build changes should not be committed**. Currently, `yarn build` will make changes to each `package.json` file, which should not be committed. This is validated in CI.
49+
50+
## Configuration
51+
52+
Monorepo packages must be opted in for build, configured in `config.js` (where build options are also documented).
53+
54+
```js
55+
const buildConfig /*: BuildConfig */ = {
56+
'packages': {
57+
'dev-middleware': {
58+
emitTypeScriptDefs: true,
59+
target: 'node',
60+
},
61+
...
62+
```
63+
64+
#### Required package structure
65+
66+
Opting a package into the `yarn build` setup requires a strict file layout. This is done to simplify config and to force consistency across the monorepo.
67+
68+
```sh
69+
packages/
70+
example-pkg/
71+
src/ # All source files
72+
index.js # Entry point wrapper file (calls babel-register.js) (compiled away)
73+
index.flow.js # Entry point implementation in Flow
74+
[other files]
75+
index.js.flow # Shim for the Flow typechecker
76+
package.json # Includes "exports" field, ideally only src/index.js
77+
```
78+
79+
Notes:
80+
81+
- The additional root `index.js.flow` shim is needed due to Flow itself not supporting Package Exports.
82+
- To minimize complexity, prefer only a single entry of `{".": "src/index.js"}` in `"exports"` for new packages.
83+
84+
## Build behavior
85+
86+
Running `yarn build` will compile each package following the below steps, depending on the configured `target` and other build options.
87+
88+
- Create a `dist/` directory, replicating each source file under `src/`:
89+
- For every `@flow` file, strip Flow annotations using [flow-api-extractor](https://www.npmjs.com/package/flow-api-translator).
90+
- For every entry point in `"exports"`, remove the `.js` wrapper file and compile from the `.flow.js` source.
91+
- Rewrite each package `"exports"` target to map to the `dist/` directory location.
92+
- If configured, emit a Flow (`.js.flow`) or TypeScript (`.d.ts`) type definition file per source file, using [flow-api-extractor](https://www.npmjs.com/package/flow-api-translator).
93+
94+
Together, this might look like the following:
95+
96+
```sh
97+
packages/
98+
example-pkg/
99+
dist/
100+
index.js # Compiled source file (from index.flow.js)
101+
index.js.flow # Flow definition file
102+
index.d.ts # TypeScript definition file
103+
[other transformed files]
104+
package.json # "src/index.js" export rewritten to "dist/index.js"
105+
```
106+
107+
**Link**: [Example `dist/` output on npm](https://www.npmjs.com/package/@react-native/dev-middleware/v/0.76.5?activeTab=code).

0 commit comments

Comments
 (0)