react/scripts/rollup/plugins/external-runtime-plugin.js
Sebastian Markbåge bb57fa7351
[Fizz] Share code between inline and external runtime (#33066)
Stacked on #33065.

The runtime is about to be a lot more complicated so we need to start
sharing some more code.

The problem with sharing code is that we want the inline runtime to as
much as possible be isolated in its scope using only a few global
variables to refer across runtimes.

A problem with Closure Compiler is that it refuses to inline functions
if they have closures inside of them. Which makes sense because of how
VMs work it can cause memory leaks. However, in our cases this doesn't
matter and code size matters more. So we can't use many clever tricks.

So this just favors writing the source in the inline form. Then we add
an extra compiler pass to turn those global variables into local
variables in the external runtime.
2025-05-01 14:25:10 -04:00

47 lines
1.5 KiB
JavaScript

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
module.exports = function externalRuntime() {
// When generating the source code for the Fizz runtime chunks we use global identifiers to refer
// to different parts of the implementation. When generating the external runtime we need to
// replace those with local identifiers instead.
return {
name: 'scripts/rollup/plugins/dynamic-imports',
renderChunk(source) {
// This replaces "window['$globalVar']" with "$globalVar".
const variables = new Set();
source = source.replace(
/window\[['"](\$[A-z0-9_]*)['"]\]/g,
(_, variableName) => {
variables.add(variableName);
return variableName;
}
);
const startOfFn = 'use strict';
let index = source.indexOf(startOfFn);
if (index === -1) {
return source;
}
index += startOfFn.length + 2;
// Insert the declarations in the beginning of the function closure
// to scope them to inside the runtime.
let declarations = 'let ';
variables.forEach(variable => {
if (declarations !== 'let ') {
declarations += ', ';
}
declarations += variable;
});
declarations += ';';
source = source.slice(0, index) + declarations + source.slice(index);
return source;
},
};
};