Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/49713 Changelog: [Internal] Reviewed By: huntie Differential Revision: D70317013 fbshipit-source-id: f131cb204135a2a41aa7d3bafe13fc7b44446036
scripts/build
Shared build setup for the React Native monorepo.
Overview
These scripts form the modern build setup for JavaScript (Flow) 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.
- Currently, only Node.js-targeting packages are included, configured in
- 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 buildwill mutatepackage.jsonfiles 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.
# 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 buildwill make changes to eachpackage.jsonfile, 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).
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.
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]
package.json # Includes "exports" field, ideally only src/index.js
Notes:
- 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 undersrc/:- For every
@flowfile, strip Flow annotations using flow-api-extractor. - For every entry point in
"exports", remove the.jswrapper file and compile from the.flow.jssource.
- For every
- Rewrite each package
"exports"target to map to thedist/directory location. - If configured, emit a Flow (
.js.flow) or TypeScript (.d.ts) type definition file per source file, using flow-api-extractor.
Together, this might look like the following:
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.