Files
react/scripts/rollup/generate-inline-fizz-runtime.js
mofeiZ 0b974418c9 [Fizz] Fork Fizz instruction set for inline script and external runtime (#25862)
~~[Fizz] Duplicate completeBoundaryWithStyles to not reference globals~~

## Summary

Follow-up / cleanup PR to #25437 

- `completeBoundaryWithStylesInlineLocals` is used by the Fizz external
runtime, which bundles together all Fizz instruction functions (and is
able to reference / rename `completeBoundary` and `resourceMap` as
locals).
- `completeBoundaryWithStylesInlineGlobals` is used by the Fizz inline
script writer, which sends Fizz instruction functions on an as-needed
basis. This version needs to reference `completeBoundary($RC)` and
`resourceMap($RM)` as globals.

Ideally, Closure would take care of inlining a shared implementation,
but I couldn't figure out a zero-overhead inline due to lack of an
`@inline` compiler directive. It seems that Closure thinks that a shared
`completeBoundaryWithStyles` is too large and will always keep it as a
separate function. I've also tried currying / writing a higher order
function (`getCompleteBoundaryWithStyles`) with no luck



## How did you test this change?
- generated Fizz inline instructions should be unchanged
- bundle size for unstable_external_runtime should be slightly smaller
(due to lack of globals)
- `ReactDOMFizzServer-test.js` and `ReactDOMFloat-test.js` should be
unaffected
2023-01-06 14:28:55 -05:00

93 lines
2.9 KiB
JavaScript

'use strict';
const fs = require('fs');
const ClosureCompiler = require('google-closure-compiler').compiler;
const prettier = require('prettier');
const instructionDir =
'./packages/react-dom-bindings/src/server/fizz-instruction-set';
// This is the name of the generated file that exports the inline instruction
// set as strings.
const inlineCodeStringsFilename =
instructionDir + '/ReactDOMFizzInstructionSetInlineCodeStrings.js';
const config = [
{
entry: 'ReactDOMFizzInlineClientRenderBoundary.js',
exportName: 'clientRenderBoundary',
},
{
entry: 'ReactDOMFizzInlineCompleteBoundary.js',
exportName: 'completeBoundary',
},
{
entry: 'ReactDOMFizzInlineCompleteBoundaryWithStyles.js',
exportName: 'completeBoundaryWithStyles',
},
{
entry: 'ReactDOMFizzInlineCompleteSegment.js',
exportName: 'completeSegment',
},
];
const prettierConfig = require('../../.prettierrc.js');
async function main() {
const exportStatements = await Promise.all(
config.map(async ({entry, exportName}) => {
const fullEntryPath = instructionDir + '/' + entry;
const compiler = new ClosureCompiler({
entry_point: fullEntryPath,
js: [
fullEntryPath,
instructionDir + '/ReactDOMFizzInstructionSetInlineSource.js',
instructionDir + '/ReactDOMFizzInstructionSetShared.js',
],
compilation_level: 'ADVANCED',
module_resolution: 'NODE',
// This is necessary to prevent Closure from inlining a Promise polyfill
rewrite_polyfills: false,
});
const code = await new Promise((resolve, reject) => {
compiler.run((exitCode, stdOut, stdErr) => {
if (exitCode !== 0) {
reject(new Error(stdErr));
} else {
resolve(stdOut);
}
});
});
return `export const ${exportName} = ${JSON.stringify(code.trim())};`;
})
);
let outputCode = [
'// This is a generated file. The source files are in react-dom-bindings/src/server/fizz-instruction-set.',
'// The build script is at scripts/rollup/generate-inline-fizz-runtime.js.',
'// Run `yarn generate-inline-fizz-runtime` to generate.',
...exportStatements,
].join('\n');
// This replaces "window.$globalVar" with "$globalVar". There's probably a
// better way to do this with Closure, with externs or something, but I
// couldn't figure it out. Good enough for now. This only affects the inline
// Fizz runtime, and should break immediately if there were a mistake, so I'm
// not too worried about it.
outputCode = outputCode.replace(
/window\.(\$[A-z0-9_]*)/g,
(_, variableName) => variableName
);
const prettyOutputCode = prettier.format(outputCode, prettierConfig);
fs.writeFileSync(inlineCodeStringsFilename, prettyOutputCode, 'utf8');
}
main().catch(err => {
console.error(err);
process.exit(1);
});