Skip to content

Commit e6dcb05

Browse files
huntiefacebook-github-bot
authored andcommitted
Add shared monorepo build setup (facebook#38240)
Summary: Pull Request resolved: facebook#38240 ## Context RFC: Decoupling Flipper from React Native core: react-native-community/discussions-and-proposals#641 ## Changes To support incoming new React Native packages around debugging (including migrating over [`react-native-community/cli-plugin-metro`](https://github.com/react-native-community/cli/tree/main/packages/cli-plugin-metro)) — which target Node.js and require a build step, this PR adds a minimal shared build setup across the `react-native` monorepo. The setup is closely inspired/based on the build scripts in Jest, Metro, and React Native CLI — and is a simple set of script wrappers around Babel and Chokidar. These are available as build commands at the root of the repo: - `yarn build` - `yarn clean` - `yarn watch` Build configuration (i.e. Babel config) is shared as a set standard across the monorepo, and **packages are opted-in to requiring a build**, configured in `scripts/build.config.js`. ``` const buildConfig /*: BuildConfig */ = { // The packages to include for build and their build options packages: { 'dev-middleware': {target: 'node'}, }, }; ``` For now, there is a single `target: 'node'` option — this is necessary as `react-native`, unlike the above other projects, is a repository with packages targeting several runtimes. We may, in future, introduce a build step for other, non-Node, packages — which may be useful for things such as auto-generated TypeScript definitions. {F1043312771} ## Current integration points - `.circleci/config.yml` — Added to `run_yarn` (with project install). - Root `yarn start` — Convenience for local developers. - `yarn start` within `packages/rn-tester` — Convenience for local developers. **Planned**: I will be adding notes on `yarn build` to the following "Contributing" website pages: - https://reactnative.dev/contributing/overview#contributing-code - https://reactnative.dev/contributing/how-to-open-a-pull-request#chapter-ii-implementing-your-changes **This is not load bearing quite yet**: There are not yet any built packages added to the dependencies of `packages/react-native/`, so this will be further tested in a later PR. ### Alternative designs **Per-package config file** Replace `scripts/build/config.js` with a package-defined key in in `package.json`, similar to Jest's [`publishConfig`](https://github.com/jestjs/jest/blob/1f019afdcdfc54a6664908bb45f343db4e3d0848/packages/jest-cli/package.json#L87C3-L89C4). ``` "buildConfig": { "type": "node" }, ``` This would be the only customisation required, with a single Babel config still standardised. Another option this might receive in future is `enableTypeScriptCodgeen`. **Rollup** More sophisticated build tool for Node.js, used by the React codebase (albeit within a custom script setup as well). **Lerna and Nx** - Most sophisticated setup enabling caching and optimised cloud runs. - Probably the most likely thing we'll move towards at a later stage. Changelog: [Internal] Differential Revision: D46759508 fbshipit-source-id: dbbee26e82dbcdeaad1ef5532d817aea9dc1382d
1 parent 823839b commit e6dcb05

File tree

12 files changed

+617
-34
lines changed

12 files changed

+617
-34
lines changed

.circleci/config.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,9 @@ commands:
237237
paths:
238238
- ~/.cache/yarn
239239
key: << parameters.yarn_base_cache_key >>-{{ arch }}-{{ checksum "yarn.lock" }}
240+
- run:
241+
name: Build packages
242+
command: yarn build
240243

241244
brew_install:
242245
parameters:

flow-typed/npm/chokidar_v3.x.x.js

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
/**
2+
* @flow strict
3+
* @format
4+
*/
5+
6+
declare module 'chokidar' {
7+
import type {Stats} from 'fs';
8+
9+
declare export class FSWatcher extends events$EventEmitter {
10+
options: WatchOptions;
11+
12+
/**
13+
* Constructs a new FSWatcher instance with optional WatchOptions parameter.
14+
*/
15+
constructor(options?: WatchOptions): this;
16+
17+
/**
18+
* Add files, directories, or glob patterns for tracking. Takes an array of strings or just one
19+
* string.
20+
*/
21+
add(paths: string | $ReadOnlyArray<string>): this;
22+
23+
/**
24+
* Stop watching files, directories, or glob patterns. Takes an array of strings or just one
25+
* string.
26+
*/
27+
unwatch(paths: string | $ReadOnlyArray<string>): this;
28+
29+
/**
30+
* Returns an object representing all the paths on the file system being watched by this
31+
* `FSWatcher` instance. The object's keys are all the directories (using absolute paths unless
32+
* the `cwd` option was used), and the values are arrays of the names of the items contained in
33+
* each directory.
34+
*/
35+
getWatched(): {
36+
[directory: string]: string[],
37+
};
38+
39+
/**
40+
* Removes all listeners from watched files.
41+
*/
42+
close(): Promise<void>;
43+
44+
on(
45+
event: 'add' | 'addDir' | 'change',
46+
listener: (path: string, stats?: Stats) => void,
47+
): this;
48+
49+
on(
50+
event: 'all',
51+
listener: (
52+
eventName: 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir',
53+
path: string,
54+
stats?: Stats,
55+
) => void,
56+
): this;
57+
58+
/**
59+
* Error occurred
60+
*/
61+
on(event: 'error', listener: (error: Error) => void): this;
62+
63+
/**
64+
* Exposes the native Node `fs.FSWatcher events`
65+
*/
66+
on(
67+
event: 'raw',
68+
listener: (eventName: string, path: string, details: any) => void,
69+
): this;
70+
71+
/**
72+
* Fires when the initial scan is complete
73+
*/
74+
on(event: 'ready', listener: () => void): this;
75+
76+
on(event: 'unlink' | 'unlinkDir', listener: (path: string) => void): this;
77+
78+
on(event: string, listener: (...args: any[]) => void): this;
79+
}
80+
81+
declare export interface WatchOptions {
82+
/**
83+
* Indicates whether the process should continue to run as long as files are being watched. If
84+
* set to `false` when using `fsevents` to watch, no more events will be emitted after `ready`,
85+
* even if the process continues to run.
86+
*/
87+
persistent?: boolean;
88+
89+
/**
90+
* ([anymatch](https://github.com/micromatch/anymatch)-compatible definition) Defines files/paths to
91+
* be ignored. The whole relative or absolute path is tested, not just filename. If a function
92+
* with two arguments is provided, it gets called twice per path - once with a single argument
93+
* (the path), second time with two arguments (the path and the
94+
* [`Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) object of that path).
95+
*/
96+
ignored?: string | Array<string>;
97+
98+
/**
99+
* If set to `false` then `add`/`addDir` events are also emitted for matching paths while
100+
* instantiating the watching as chokidar discovers these file paths (before the `ready` event).
101+
*/
102+
ignoreInitial?: boolean;
103+
104+
/**
105+
* When `false`, only the symlinks themselves will be watched for changes instead of following
106+
* the link references and bubbling events through the link's path.
107+
*/
108+
followSymlinks?: boolean;
109+
110+
/**
111+
* The base directory from which watch `paths` are to be derived. Paths emitted with events will
112+
* be relative to this.
113+
*/
114+
cwd?: string;
115+
116+
/**
117+
* If set to true then the strings passed to .watch() and .add() are treated as literal path
118+
* names, even if they look like globs. Default: false.
119+
*/
120+
disableGlobbing?: boolean;
121+
122+
/**
123+
* Whether to use fs.watchFile (backed by polling), or fs.watch. If polling leads to high CPU
124+
* utilization, consider setting this to `false`. It is typically necessary to **set this to
125+
* `true` to successfully watch files over a network**, and it may be necessary to successfully
126+
* watch files in other non-standard situations. Setting to `true` explicitly on OS X overrides
127+
* the `useFsEvents` default.
128+
*/
129+
usePolling?: boolean;
130+
131+
/**
132+
* Whether to use the `fsevents` watching interface if available. When set to `true` explicitly
133+
* and `fsevents` is available this supercedes the `usePolling` setting. When set to `false` on
134+
* OS X, `usePolling: true` becomes the default.
135+
*/
136+
useFsEvents?: boolean;
137+
138+
/**
139+
* If relying upon the [`Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) object that
140+
* may get passed with `add`, `addDir`, and `change` events, set this to `true` to ensure it is
141+
* provided even in cases where it wasn't already available from the underlying watch events.
142+
*/
143+
alwaysStat?: boolean;
144+
145+
/**
146+
* If set, limits how many levels of subdirectories will be traversed.
147+
*/
148+
depth?: number;
149+
150+
/**
151+
* Interval of file system polling.
152+
*/
153+
interval?: number;
154+
155+
/**
156+
* Interval of file system polling for binary files. ([see list of binary extensions](https://gi
157+
* thub.com/sindresorhus/binary-extensions/blob/master/binary-extensions.json))
158+
*/
159+
binaryInterval?: number;
160+
161+
/**
162+
* Indicates whether to watch files that don't have read permissions if possible. If watching
163+
* fails due to `EPERM` or `EACCES` with this set to `true`, the errors will be suppressed
164+
* silently.
165+
*/
166+
ignorePermissionErrors?: boolean;
167+
168+
/**
169+
* `true` if `useFsEvents` and `usePolling` are `false`). Automatically filters out artifacts
170+
* that occur when using editors that use "atomic writes" instead of writing directly to the
171+
* source file. If a file is re-added within 100 ms of being deleted, Chokidar emits a `change`
172+
* event rather than `unlink` then `add`. If the default of 100 ms does not work well for you,
173+
* you can override it by setting `atomic` to a custom value, in milliseconds.
174+
*/
175+
atomic?: boolean | number;
176+
177+
/**
178+
* can be set to an object in order to adjust timing params:
179+
*/
180+
awaitWriteFinish?: AwaitWriteFinishOptions | boolean;
181+
}
182+
183+
declare export interface AwaitWriteFinishOptions {
184+
/**
185+
* Amount of time in milliseconds for a file size to remain constant before emitting its event.
186+
*/
187+
stabilityThreshold?: number;
188+
189+
/**
190+
* File size polling interval.
191+
*/
192+
pollInterval?: number;
193+
}
194+
195+
/**
196+
* produces an instance of `FSWatcher`.
197+
*/
198+
declare export function watch(
199+
paths: string | $ReadOnlyArray<string>,
200+
options?: WatchOptions,
201+
): FSWatcher;
202+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow strict
8+
* @format
9+
* @oncall react_native
10+
*/
11+
12+
declare module '@pkgjs/parseargs' {
13+
declare type ParseArgsOptionConfig = {
14+
type: 'string' | 'boolean',
15+
short?: string,
16+
multiple?: boolean,
17+
};
18+
19+
declare type ParseArgsOptionsConfig = {
20+
[longOption: string]: ParseArgsOptionConfig,
21+
};
22+
23+
declare export type ParseArgsConfig = {
24+
strict?: boolean,
25+
allowPositionals?: boolean,
26+
tokens?: boolean,
27+
options?: ParseArgsOptionsConfig,
28+
args?: string[],
29+
};
30+
31+
declare type ParsedResults = {
32+
values: {
33+
[longOption: string]: void | string | boolean | Array<string | boolean>,
34+
},
35+
positionals: string[],
36+
...
37+
};
38+
39+
declare export function parseArgs(config: ParseArgsConfig): ParsedResults;
40+
}

package.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@
1111
"outputName": "js-test-results.xml"
1212
},
1313
"scripts": {
14-
"start": "cd packages/rn-tester && npm run start",
14+
"postinstall": "yarn build",
15+
"start": "yarn build && cd packages/rn-tester && npm run start",
1516
"android": "cd packages/rn-tester && npm run android",
17+
"build": "node ./scripts/build/build.js",
18+
"clean": "node ./scripts/build/clean.js",
19+
"watch": "yarn build && node ./scripts/build/watch.js",
1620
"test": "jest",
1721
"test-ci": "jest --maxWorkers=2 --ci --reporters=\"default\" --reporters=\"jest-junit\"",
1822
"flow": "flow",
@@ -57,11 +61,14 @@
5761
"@babel/plugin-transform-regenerator": "^7.20.0",
5862
"@definitelytyped/dtslint": "^0.0.127",
5963
"@jest/create-cache-key-function": "^29.2.1",
64+
"@pkgjs/parseargs": "^0.11.0",
6065
"@react-native/metro-config": "^0.73.0",
6166
"@types/react": "^18.0.18",
6267
"@typescript-eslint/parser": "^5.57.1",
6368
"async": "^3.2.2",
6469
"babel-plugin-transform-flow-enums": "^0.0.2",
70+
"chalk": "^4.0.0",
71+
"chokidar": "^3.5.3",
6572
"clang-format": "^1.8.0",
6673
"connect": "^3.6.5",
6774
"eslint": "^8.19.0",
@@ -79,6 +86,7 @@
7986
"eslint-plugin-redundant-undefined": "^0.4.0",
8087
"eslint-plugin-relay": "^1.8.3",
8188
"flow-bin": "^0.211.0",
89+
"glob": "^7.1.1",
8290
"hermes-eslint": "0.14.0",
8391
"inquirer": "^7.1.0",
8492
"jest": "^29.2.1",
@@ -87,6 +95,7 @@
8795
"metro-babel-register": "0.76.2",
8896
"metro-memory-fs": "0.76.2",
8997
"metro-react-native-babel-transformer": "0.76.2",
98+
"micromatch": "^4.0.4",
9099
"mkdirp": "^0.5.1",
91100
"mock-fs": "^5.1.4",
92101
"prettier": "2.8.8",

packages/dev-middleware/.babelrc

Lines changed: 0 additions & 13 deletions
This file was deleted.

packages/dev-middleware/package.json

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,12 @@
1818
"files": [
1919
"dist"
2020
],
21-
"scripts": {
22-
"build": "yarn clean && babel src --out-dir dist",
23-
"dev": "babel src --out-dir dist --source-maps --watch",
24-
"clean": "rimraf dist",
25-
"prepare": "yarn build"
26-
},
2721
"dependencies": {
2822
"chrome-launcher": "^0.15.2",
2923
"connect": "^3.6.5",
3024
"node-fetch": "^2.2.0",
3125
"temp-dir": "^2.0.0"
3226
},
33-
"devDependencies": {
34-
"@babel/cli": "^7.20.0",
35-
"@babel/core": "^7.20.0",
36-
"@babel/preset-env": "^7.20.0",
37-
"@babel/preset-flow": "^7.20.0",
38-
"rimraf": "^3.0.2"
39-
},
4027
"engines": {
4128
"node": ">=18"
4229
}

packages/rn-tester/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"node": ">=18"
1414
},
1515
"scripts": {
16-
"start": "react-native start",
16+
"start": "yarn --cwd ../.. build && react-native start",
1717
"android": "react-native run-android --mode HermesDebug --appId 'com.facebook.react.uiapp' --main-activity 'com.facebook.react.uiapp.RNTesterActivity'",
1818
"install-android-jsc": "../../gradlew :packages:rn-tester:android:app:installJscDebug",
1919
"install-android-hermes": "../../gradlew :packages:rn-tester:android:app:installHermesDebug",

0 commit comments

Comments
 (0)