-
Notifications
You must be signed in to change notification settings - Fork 24.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Document monorepo build setup (#48420)
Summary: Adds a long overdue README for our newer monorepo build setup. Changelog: [Internal] Differential Revision: D67740763
- Loading branch information
1 parent
93117ea
commit 04b847a
Showing
1 changed file
with
107 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
# scripts/build | ||
|
||
Shared build setup for the React Native monorepo. | ||
|
||
## Overview | ||
|
||
These scripts form the modern build setup for JavaScript ([Flow](https://flow.org/)) packages in `react-native`, exposed as `yarn build`. | ||
|
||
> [!Tip] | ||
> 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. | ||
#### Key info | ||
|
||
- **Which packages are included?** | ||
- Currently, only Node.js-targeting packages are included, configured in `config.js`. | ||
- We don't yet include runtime packages (targeting Metro). These are instead transformed in user space via `@react-native/babel-preset`. | ||
- **When does the build run?** | ||
- Packages are built in CI workflows — both for integration/E2E tests, and before publishing to npm. | ||
|
||
#### Limitations/quirks | ||
|
||
> [!Note] | ||
> **🚧 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. | ||
- Running `yarn build` will mutate `package.json` files in place, resulting in a dirty Git working copy. | ||
- 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"`. | ||
|
||
## Usage | ||
|
||
**💡 Reminder**: 99% of the time, there is no need to use `yarn build`, as all packages will run from source during development. | ||
|
||
Build commands are exposed as npm scripts at the repo root. | ||
|
||
```sh | ||
# Build all packages | ||
yarn build | ||
|
||
# Build a specific package | ||
yarn build dev-middleware | ||
|
||
# Clean build directories | ||
yarn clean | ||
``` | ||
|
||
Once built, developing in the monorepo should continue to work — now using the compiled version of each package. | ||
|
||
> [!Warning] | ||
> **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. | ||
## Configuration | ||
|
||
Monorepo packages must be opted in for build, configured in `config.js` (where build options are also documented). | ||
|
||
```js | ||
const buildConfig /*: BuildConfig */ = { | ||
'packages': { | ||
'dev-middleware': { | ||
emitTypeScriptDefs: true, | ||
target: 'node', | ||
}, | ||
... | ||
``` | ||
#### Required package structure | ||
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. | ||
```sh | ||
packages/ | ||
example-pkg/ | ||
src/ # All source files | ||
index.js # Entry point wrapper file (calls babel-register.js) (compiled away) | ||
index.flow.js # Entry point implementation in Flow | ||
[other files] | ||
index.js.flow # Shim for the Flow typechecker | ||
package.json # Includes "exports" field, ideally only src/index.js | ||
``` | ||
Notes: | ||
- The additional root `index.js.flow` shim is needed due to Flow itself not supporting Package Exports. | ||
- To minimize complexity, prefer only a single entry of `{".": "src/index.js"}` in `"exports"` for new packages. | ||
## Build behavior | ||
Running `yarn build` will compile each package following the below steps, depending on the configured `target` and other build options. | ||
- Create a `dist/` directory, replicating each source file under `src/`: | ||
- For every `@flow` file, strip Flow annotations using [flow-api-extractor](https://www.npmjs.com/package/flow-api-translator). | ||
- For every entry point in `"exports"`, remove the `.js` wrapper file and compile from the `.flow.js` source. | ||
- Rewrite each package `"exports"` target to map to the `dist/` directory location. | ||
- 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). | ||
Together, this might look like the following: | ||
```sh | ||
packages/ | ||
example-pkg/ | ||
dist/ | ||
index.js # Compiled source file (from index.flow.js) | ||
index.js.flow # Flow definition file | ||
index.d.ts # TypeScript definition file | ||
[other transformed files] | ||
package.json # "src/index.js" export rewritten to "dist/index.js" | ||
``` | ||
**Link**: [Example `dist/` output on npm](https://www.npmjs.com/package/@react-native/dev-middleware/v/0.76.5?activeTab=code). |