Skip to content

Commit 33999c4

Browse files
authored
[compiler][be] Test runner (snap) now uses tsup bundled plugin (#32758)
Currently, `babel-plugin-react-compiler` is bundled with (almost) all external dependencies. This is because babel traversal and ast logic is not forward-compatible. Since `babel-plugin-react-compiler` needs to be compatible with babel pipelines across a wide semvar range, we (1) set this package's babel dependency to an early version and (2) inline babel libraries into our bundle. A few other packages in `react/compiler` depend on the compiler. This PR moves `snap`, our test fixture compiler and evaluator, to use the bundled version of `babel-plugin-react-compiler`. This decouples the babel version used by `snap` with the version used by `babel-plugin-react-compiler`, which means that `snap` now can test features from newer babel versions (see #32742). --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32758). * #32759 * __->__ #32758
1 parent 5f232d7 commit 33999c4

File tree

11 files changed

+105
-85
lines changed

11 files changed

+105
-85
lines changed

compiler/packages/babel-plugin-react-compiler/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"build": "rimraf dist && tsup",
1313
"test": "./scripts/link-react-compiler-runtime.sh && yarn snap:ci",
1414
"jest": "yarn build && ts-node node_modules/.bin/jest",
15-
"snap": "node ../snap/dist/main.js",
15+
"snap": "yarn workspace snap run snap",
1616
"snap:build": "yarn workspace snap run build",
1717
"snap:ci": "yarn snap:build && yarn snap",
1818
"ts:analyze-trace": "scripts/ts-analyze-trace.sh",

compiler/packages/babel-plugin-react-compiler/src/HIR/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@ export {
3232
} from './HIRBuilder';
3333
export {mergeConsecutiveBlocks} from './MergeConsecutiveBlocks';
3434
export {mergeOverlappingReactiveScopesHIR} from './MergeOverlappingReactiveScopesHIR';
35-
export {printFunction, printHIR} from './PrintHIR';
35+
export {printFunction, printHIR, printFunctionWithOutlined} from './PrintHIR';
3636
export {pruneUnusedLabelsHIR} from './PruneUnusedLabelsHIR';

compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/index.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ export {extractScopeDeclarationsFromDestructuring} from './ExtractScopeDeclarati
1414
export {inferReactiveScopeVariables} from './InferReactiveScopeVariables';
1515
export {memoizeFbtAndMacroOperandsInSameScope} from './MemoizeFbtAndMacroOperandsInSameScope';
1616
export {mergeReactiveScopesThatInvalidateTogether} from './MergeReactiveScopesThatInvalidateTogether';
17-
export {printReactiveFunction} from './PrintReactiveFunction';
17+
export {
18+
printReactiveFunction,
19+
printReactiveFunctionWithOutlined,
20+
} from './PrintReactiveFunction';
1821
export {promoteUsedTemporaries} from './PromoteUsedTemporaries';
1922
export {propagateEarlyReturns} from './PropagateEarlyReturns';
2023
export {pruneAllReactiveScopes} from './PruneAllReactiveScopes';

compiler/packages/babel-plugin-react-compiler/src/index.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,17 @@ export {
3232
ValueKind,
3333
parseConfigPragmaForTests,
3434
printHIR,
35+
printFunctionWithOutlined,
3536
validateEnvironmentConfig,
3637
type EnvironmentConfig,
3738
type ExternalFunction,
3839
type Hook,
3940
type SourceLocation,
4041
} from './HIR';
41-
export {printReactiveFunction} from './ReactiveScopes';
42+
export {
43+
printReactiveFunction,
44+
printReactiveFunctionWithOutlined,
45+
} from './ReactiveScopes';
4246
declare global {
4347
let __DEV__: boolean | null | undefined;
4448
}

compiler/packages/babel-plugin-react-compiler/tsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"module": "ES2015",
55
"moduleResolution": "Bundler",
66
"rootDir": "src",
7-
"outDir": "dist",
7+
"noEmit": true,
88
"jsx": "react-jsxdev",
99
// weaken strictness from preset
1010
"importsNotUsedAsValues": "remove",

compiler/packages/snap/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"scripts": {
1212
"postinstall": "./scripts/link-react-compiler-runtime.sh && perl -p -i -e 's/react\\.element/react.transitional.element/' ../../node_modules/fbt/lib/FbtReactUtil.js && perl -p -i -e 's/didWarnAboutUsingAct = false;/didWarnAboutUsingAct = true;/' ../../node_modules/react-dom/cjs/react-dom-test-utils.development.js",
1313
"build": "rimraf dist && concurrently -n snap,runtime \"tsc --build\" \"yarn --silent workspace react-compiler-runtime build\"",
14+
"snap": "node dist/main.js",
1415
"test": "echo 'no tests'",
1516
"prettier": "prettier --write 'src/**/*.ts'"
1617
},
@@ -40,8 +41,7 @@
4041
},
4142
"devDependencies": {
4243
"@babel/core": "^7.19.1",
43-
"@babel/parser": "^7.19.1",
44-
"@babel/plugin-syntax-typescript": "^7.18.6",
44+
"@babel/parser": "^7.20.15",
4545
"@babel/plugin-transform-modules-commonjs": "^7.18.6",
4646
"@babel/preset-react": "^7.18.6",
4747
"@babel/traverse": "^7.19.1",

compiler/packages/snap/src/constants.ts

+9-27
Original file line numberDiff line numberDiff line change
@@ -9,40 +9,22 @@ import path from 'path';
99

1010
// We assume this is run from `babel-plugin-react-compiler`
1111
export const PROJECT_ROOT = path.normalize(
12-
path.join(process.cwd(), '..', '..'),
12+
path.join(process.cwd(), '..', 'babel-plugin-react-compiler'),
1313
);
14-
export const COMPILER_PATH = path.join(
15-
process.cwd(),
16-
'dist',
17-
'Babel',
18-
'BabelPlugin.js',
19-
);
20-
export const COMPILER_INDEX_PATH = path.join(process.cwd(), 'dist', 'index');
21-
export const PRINT_HIR_PATH = path.join(
22-
process.cwd(),
23-
'dist',
24-
'HIR',
25-
'PrintHIR.js',
26-
);
27-
export const PRINT_REACTIVE_IR_PATH = path.join(
28-
process.cwd(),
29-
'dist',
30-
'ReactiveScopes',
31-
'PrintReactiveFunction.js',
32-
);
33-
export const PARSE_CONFIG_PRAGMA_PATH = path.join(
34-
process.cwd(),
35-
'dist',
36-
'HIR',
37-
'Environment.js',
14+
15+
export const PROJECT_SRC = path.normalize(
16+
path.join(PROJECT_ROOT, 'dist', 'index.js'),
3817
);
18+
export const PRINT_HIR_IMPORT = 'printFunctionWithOutlined';
19+
export const PRINT_REACTIVE_IR_IMPORT = 'printReactiveFunction';
20+
export const PARSE_CONFIG_PRAGMA_IMPORT = 'parseConfigPragmaForTests';
3921
export const FIXTURES_PATH = path.join(
40-
process.cwd(),
22+
PROJECT_ROOT,
4123
'src',
4224
'__tests__',
4325
'fixtures',
4426
'compiler',
4527
);
4628
export const SNAPSHOT_EXTENSION = '.expect.md';
4729
export const FILTER_FILENAME = 'testfilter.txt';
48-
export const FILTER_PATH = path.join(process.cwd(), FILTER_FILENAME);
30+
export const FILTER_PATH = path.join(PROJECT_ROOT, FILTER_FILENAME);

compiler/packages/snap/src/runner-watch.ts

+21-11
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,16 @@
88
import watcher from '@parcel/watcher';
99
import path from 'path';
1010
import ts from 'typescript';
11-
import {FILTER_FILENAME, FIXTURES_PATH} from './constants';
11+
import {FILTER_FILENAME, FIXTURES_PATH, PROJECT_ROOT} from './constants';
1212
import {TestFilter, readTestFilter} from './fixture-utils';
13+
import {execSync} from 'child_process';
1314

1415
export function watchSrc(
1516
onStart: () => void,
1617
onComplete: (isSuccess: boolean) => void,
1718
): ts.WatchOfConfigFile<ts.SemanticDiagnosticsBuilderProgram> {
1819
const configPath = ts.findConfigFile(
19-
/*searchPath*/ './',
20+
/*searchPath*/ PROJECT_ROOT,
2021
ts.sys.fileExists,
2122
'tsconfig.json',
2223
);
@@ -26,10 +27,7 @@ export function watchSrc(
2627
const createProgram = ts.createSemanticDiagnosticsBuilderProgram;
2728
const host = ts.createWatchCompilerHost(
2829
configPath,
29-
ts.convertCompilerOptionsFromJson(
30-
{module: 'commonjs', outDir: 'dist', sourceMap: true},
31-
'.',
32-
).options,
30+
undefined,
3331
ts.sys,
3432
createProgram,
3533
() => {}, // we manually report errors in afterProgramCreate
@@ -41,9 +39,11 @@ export function watchSrc(
4139
onStart();
4240
return origCreateProgram(rootNames, options, host, oldProgram);
4341
};
44-
const origPostProgramCreate = host.afterProgramCreate;
4542
host.afterProgramCreate = program => {
46-
origPostProgramCreate!(program);
43+
/**
44+
* Avoid calling original postProgramCreate because it always emits tsc
45+
* compilation output
46+
*/
4747

4848
// syntactic diagnostics refer to javascript syntax
4949
const errors = program
@@ -172,13 +172,23 @@ function subscribeTsc(
172172
// Notify the user when compilation starts but don't clear the screen yet
173173
console.log('\nCompiling...');
174174
},
175-
isSuccess => {
175+
isTypecheckSuccess => {
176+
let isCompilerBuildValid = false;
177+
if (isTypecheckSuccess) {
178+
try {
179+
execSync('yarn build', {cwd: PROJECT_ROOT});
180+
console.log('Built compiler successfully with tsup');
181+
isCompilerBuildValid = true;
182+
} catch (e) {
183+
console.warn('Failed to build compiler with tsup:', e);
184+
}
185+
}
176186
// Bump the compiler version after a build finishes
177187
// and re-run tests
178-
if (isSuccess) {
188+
if (isCompilerBuildValid) {
179189
state.compilerVersion++;
180190
}
181-
state.isCompilerBuildValid = isSuccess;
191+
state.isCompilerBuildValid = isCompilerBuildValid;
182192
state.mode.action = RunnerAction.Test;
183193
onChange(state);
184194
},

compiler/packages/snap/src/runner-worker.ts

+30-23
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,19 @@ import type {printFunctionWithOutlined as PrintFunctionWithOutlined} from 'babel
1212
import type {printReactiveFunctionWithOutlined as PrintReactiveFunctionWithOutlined} from 'babel-plugin-react-compiler/src/ReactiveScopes/PrintReactiveFunction';
1313
import {TransformResult, transformFixtureInput} from './compiler';
1414
import {
15-
COMPILER_PATH,
16-
COMPILER_INDEX_PATH,
17-
PARSE_CONFIG_PRAGMA_PATH,
18-
PRINT_HIR_PATH,
19-
PRINT_REACTIVE_IR_PATH,
15+
PARSE_CONFIG_PRAGMA_IMPORT,
16+
PRINT_HIR_IMPORT,
17+
PRINT_REACTIVE_IR_IMPORT,
18+
PROJECT_SRC,
2019
} from './constants';
2120
import {TestFixture, getBasename, isExpectError} from './fixture-utils';
2221
import {TestResult, writeOutputToString} from './reporter';
2322
import {runSprout} from './sprout';
24-
import {CompilerPipelineValue} from 'babel-plugin-react-compiler/src';
23+
import type {
24+
CompilerPipelineValue,
25+
Effect,
26+
ValueKind,
27+
} from 'babel-plugin-react-compiler/src';
2528
import chalk from 'chalk';
2629

2730
const originalConsoleError = console.error;
@@ -61,22 +64,29 @@ async function compile(
6164
let compileResult: TransformResult | null = null;
6265
let error: string | null = null;
6366
try {
67+
const importedCompilerPlugin = require(PROJECT_SRC) as Record<
68+
string,
69+
unknown
70+
>;
71+
6472
// NOTE: we intentionally require lazily here so that we can clear the require cache
6573
// and load fresh versions of the compiler when `compilerVersion` changes.
66-
const {default: BabelPluginReactCompiler} = require(COMPILER_PATH) as {
67-
default: PluginObj;
68-
};
69-
const {Effect: EffectEnum, ValueKind: ValueKindEnum} = require(
70-
COMPILER_INDEX_PATH,
71-
);
72-
const {printFunctionWithOutlined} = require(PRINT_HIR_PATH) as {
73-
printFunctionWithOutlined: typeof PrintFunctionWithOutlined;
74-
};
75-
const {printReactiveFunctionWithOutlined} = require(
76-
PRINT_REACTIVE_IR_PATH,
77-
) as {
78-
printReactiveFunctionWithOutlined: typeof PrintReactiveFunctionWithOutlined;
79-
};
74+
const BabelPluginReactCompiler = importedCompilerPlugin[
75+
'default'
76+
] as PluginObj;
77+
const EffectEnum = importedCompilerPlugin['Effect'] as typeof Effect;
78+
const ValueKindEnum = importedCompilerPlugin[
79+
'ValueKind'
80+
] as typeof ValueKind;
81+
const printFunctionWithOutlined = importedCompilerPlugin[
82+
PRINT_HIR_IMPORT
83+
] as typeof PrintFunctionWithOutlined;
84+
const printReactiveFunctionWithOutlined = importedCompilerPlugin[
85+
PRINT_REACTIVE_IR_IMPORT
86+
] as typeof PrintReactiveFunctionWithOutlined;
87+
const parseConfigPragmaForTests = importedCompilerPlugin[
88+
PARSE_CONFIG_PRAGMA_IMPORT
89+
] as typeof ParseConfigPragma;
8090

8191
let lastLogged: string | null = null;
8292
const debugIRLogger = shouldLog
@@ -106,9 +116,6 @@ async function compile(
106116
}
107117
}
108118
: () => {};
109-
const {parseConfigPragmaForTests} = require(PARSE_CONFIG_PRAGMA_PATH) as {
110-
parseConfigPragmaForTests: typeof ParseConfigPragma;
111-
};
112119

113120
// only try logging if we filtered out all but one fixture,
114121
// since console log order is non-deterministic

compiler/packages/snap/src/runner.ts

+22-15
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import * as readline from 'readline';
1212
import ts from 'typescript';
1313
import yargs from 'yargs';
1414
import {hideBin} from 'yargs/helpers';
15-
import {FILTER_PATH} from './constants';
15+
import {FILTER_PATH, PROJECT_ROOT} from './constants';
1616
import {TestFilter, getFixtures, readTestFilter} from './fixture-utils';
1717
import {TestResult, TestResults, report, update} from './reporter';
1818
import {
@@ -22,6 +22,7 @@ import {
2222
watchSrc,
2323
} from './runner-watch';
2424
import * as runnerWorker from './runner-worker';
25+
import {execSync} from 'child_process';
2526

2627
const WORKER_PATH = require.resolve('./runner-worker.js');
2728
const NUM_WORKERS = cpus().length - 1;
@@ -205,23 +206,29 @@ export async function main(opts: RunnerOptions): Promise<void> {
205206
const tsWatch: ts.WatchOfConfigFile<ts.SemanticDiagnosticsBuilderProgram> =
206207
watchSrc(
207208
() => {},
208-
async (compileSuccess: boolean) => {
209-
let isSuccess = compileSuccess;
210-
if (compileSuccess) {
211-
const testFilter = opts.filter ? await readTestFilter() : null;
212-
const results = await runFixtures(worker, testFilter, 0);
213-
if (opts.update) {
214-
update(results);
215-
} else {
216-
const testSuccess = report(results);
217-
isSuccess &&= testSuccess;
218-
}
219-
} else {
209+
async (isTypecheckSuccess: boolean) => {
210+
let isSuccess = false;
211+
if (!isTypecheckSuccess) {
220212
console.error(
221-
'Found errors in Forget source code, skipping test fixtures.',
213+
'Found typescript errors in Forget source code, skipping test fixtures.',
222214
);
215+
} else {
216+
try {
217+
execSync('yarn build', {cwd: PROJECT_ROOT});
218+
console.log('Built compiler successfully with tsup');
219+
const testFilter = opts.filter ? await readTestFilter() : null;
220+
const results = await runFixtures(worker, testFilter, 0);
221+
if (opts.update) {
222+
update(results);
223+
isSuccess = true;
224+
} else {
225+
isSuccess = report(results);
226+
}
227+
} catch (e) {
228+
console.warn('Failed to build compiler with tsup:', e);
229+
}
223230
}
224-
tsWatch.close();
231+
tsWatch?.close();
225232
await worker.end();
226233
process.exit(isSuccess ? 0 : 1);
227234
},

compiler/yarn.lock

+9-2
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@
657657
js-tokens "^4.0.0"
658658
picocolors "^1.0.0"
659659

660-
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.10", "@babel/parser@^7.19.1", "@babel/parser@^7.2.0":
660+
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.10", "@babel/parser@^7.2.0":
661661
version "7.19.1"
662662
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.1.tgz#6f6d6c2e621aad19a92544cc217ed13f1aac5b4c"
663663
integrity sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==
@@ -667,6 +667,13 @@
667667
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.3.tgz#8dd36d17c53ff347f9e55c328710321b49479a9a"
668668
integrity sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==
669669

670+
"@babel/parser@^7.20.15":
671+
version "7.27.0"
672+
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.27.0.tgz#3d7d6ee268e41d2600091cbd4e145ffee85a44ec"
673+
integrity sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==
674+
dependencies:
675+
"@babel/types" "^7.27.0"
676+
670677
"@babel/parser@^7.20.7":
671678
version "7.21.2"
672679
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.2.tgz#dacafadfc6d7654c3051a66d6fe55b6cb2f2a0b3"
@@ -1696,7 +1703,7 @@
16961703
debug "^4.3.1"
16971704
globals "^11.1.0"
16981705

1699-
"@babel/[email protected]", "@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.20.7", "@babel/types@^7.21.2", "@babel/types@^7.21.4", "@babel/types@^7.21.5", "@babel/types@^7.22.0", "@babel/types@^7.22.3", "@babel/types@^7.22.4", "@babel/types@^7.22.5", "@babel/types@^7.24.7", "@babel/types@^7.25.0", "@babel/types@^7.25.6", "@babel/types@^7.25.9", "@babel/types@^7.26.0", "@babel/types@^7.26.10", "@babel/types@^7.26.3", "@babel/types@^7.26.9", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.4":
1706+
"@babel/[email protected]", "@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.20.7", "@babel/types@^7.21.2", "@babel/types@^7.21.4", "@babel/types@^7.21.5", "@babel/types@^7.22.0", "@babel/types@^7.22.3", "@babel/types@^7.22.4", "@babel/types@^7.22.5", "@babel/types@^7.24.7", "@babel/types@^7.25.0", "@babel/types@^7.25.6", "@babel/types@^7.25.9", "@babel/types@^7.26.0", "@babel/types@^7.26.10", "@babel/types@^7.26.3", "@babel/types@^7.26.9", "@babel/types@^7.27.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.4":
17001707
version "7.26.3"
17011708
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.3.tgz#37e79830f04c2b5687acc77db97fbc75fb81f3c0"
17021709
integrity sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==

0 commit comments

Comments
 (0)