Skip to content

Commit

Permalink
Scaffolding for react-dom/unstable_external-server-runtime (#25482)
Browse files Browse the repository at this point in the history
* Scaffolding for react-dom/unstable_external-server-runtime

Implements a new bundle type for in our build config called
BROWSER_SCRIPT. This is intended for scripts that get delivered straight
to the browser without needing to be processed by a bundler. (And also
doesn't include any extra UMD crap.)

Right now there's only a single use case so I didn't stress about making
it general purpose.

The use case is: a script that loads the Fizz browser runtime, and sets
up a MutationObserver to receive instructions as HTML streams in. This
will be an alternative option to the default Fizz behavior of sending
the runtime down as inline script tags, to accommodate environments
where inline script tags are not allowed.

There's no development version of this bundle because it doesn't contain
any warnings or run any user code.

None of the actual implementation is in this PR; it just sets up the
build infra.

Co-authored-by: Mofei Zhang <feifei0@fb.com>

* Set BUNDLE_SCRIPT's GCC output format to ES5

This removes the automatic 'use strict' directive, which we don't need.

Co-authored-by: Mofei Zhang <feifei0@fb.com>
  • Loading branch information
acdlite and mofeiZ authored Oct 15, 2022
1 parent 0eaca37 commit 54f0e0f
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 23 deletions.
1 change: 1 addition & 0 deletions packages/react-dom/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"server-rendering-stub.js",
"test-utils.js",
"unstable_testing.js",
"unstable_server-external-runtime.js",
"cjs/",
"umd/"
],
Expand Down
18 changes: 18 additions & 0 deletions packages/react-dom/src/server/ReactDOMServerExternalRuntime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// TODO: Add Flow types
import {
clientRenderBoundary,
completeBoundaryWithStyles,
completeBoundary,
completeSegment,
} from 'react-dom-bindings/src/server/fizz-instruction-set/ReactDOMFizzInstructionSet';

// Intentionally does nothing. Implementation will be added in future PR.
// eslint-disable-next-line no-unused-vars
const observer = new MutationObserver(mutations => {
// These are only called so I can check what the module output looks like. The
// code is unreachable.
clientRenderBoundary();
completeBoundaryWithStyles();
completeBoundary();
completeSegment();
});
48 changes: 26 additions & 22 deletions scripts/rollup/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ const {
RN_FB_DEV,
RN_FB_PROD,
RN_FB_PROFILING,
BROWSER_SCRIPT,
} = Bundles.bundleTypes;

const {getFilename} = Bundles;
Expand Down Expand Up @@ -93,19 +94,6 @@ const isWatchMode = argv.watch;
const syncFBSourcePath = argv['sync-fbsource'];
const syncWWWPath = argv['sync-www'];

const closureOptions = {
compilation_level: 'SIMPLE',
language_in: 'ECMASCRIPT_2015',
language_out: 'ECMASCRIPT5_STRICT',
env: 'CUSTOM',
warning_level: 'QUIET',
apply_input_source_maps: false,
use_types_for_optimization: false,
process_common_js_modules: false,
rewrite_polyfills: false,
inject_libraries: false,
};

// Non-ES2015 stuff applied before closure compiler.
const babelPlugins = [
// These plugins filter out non-ES2015.
Expand Down Expand Up @@ -224,6 +212,8 @@ function getFormat(bundleType) {
return `cjs`;
case NODE_ESM:
return `es`;
case BROWSER_SCRIPT:
return `iife`;
}
}

Expand All @@ -247,6 +237,7 @@ function isProductionBundleType(bundleType) {
case RN_OSS_PROFILING:
case RN_FB_PROD:
case RN_FB_PROFILING:
case BROWSER_SCRIPT:
return true;
default:
throw new Error(`Unknown type: ${bundleType}`);
Expand All @@ -267,6 +258,7 @@ function isProfilingBundleType(bundleType) {
case RN_OSS_PROD:
case UMD_DEV:
case UMD_PROD:
case BROWSER_SCRIPT:
return false;
case FB_WWW_PROFILING:
case NODE_PROFILING:
Expand Down Expand Up @@ -371,14 +363,24 @@ function getPlugins(
isUMDBundle && entry === 'react-art' && commonjs(),
// Apply dead code elimination and/or minification.
isProduction &&
closure(
Object.assign({}, closureOptions, {
// Don't let it create global variables in the browser.
// https://github.com/facebook/react/issues/10909
assume_function_wrapper: !isUMDBundle,
renaming: !shouldStayReadable,
})
),
closure({
compilation_level: 'SIMPLE',
language_in: 'ECMASCRIPT_2015',
language_out:
bundleType === BROWSER_SCRIPT ? 'ECMASCRIPT5' : 'ECMASCRIPT5_STRICT',
env: 'CUSTOM',
warning_level: 'QUIET',
apply_input_source_maps: false,
use_types_for_optimization: false,
process_common_js_modules: false,
rewrite_polyfills: false,
inject_libraries: false,

// Don't let it create global variables in the browser.
// https://github.com/facebook/react/issues/10909
assume_function_wrapper: !isUMDBundle,
renaming: !shouldStayReadable,
}),
// HACK to work around the fact that Rollup isn't removing unused, pure-module imports.
// Note that this plugin must be called after closure applies DCE.
isProduction && stripUnusedImports(pureExternalModules),
Expand Down Expand Up @@ -582,6 +584,7 @@ async function createBundle(bundle, bundleType) {
},
};
const mainOutputPath = Packaging.getBundleOutputPath(
bundle,
bundleType,
filename,
packageName
Expand Down Expand Up @@ -724,7 +727,8 @@ async function buildEverything() {
[bundle, RN_OSS_PROFILING],
[bundle, RN_FB_DEV],
[bundle, RN_FB_PROD],
[bundle, RN_FB_PROFILING]
[bundle, RN_FB_PROFILING],
[bundle, BROWSER_SCRIPT]
);
}

Expand Down
16 changes: 16 additions & 0 deletions scripts/rollup/bundles.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const bundleTypes = {
RN_FB_DEV: 'RN_FB_DEV',
RN_FB_PROD: 'RN_FB_PROD',
RN_FB_PROFILING: 'RN_FB_PROFILING',
BROWSER_SCRIPT: 'BROWSER_SCRIPT',
};

const {
Expand All @@ -45,6 +46,7 @@ const {
RN_FB_DEV,
RN_FB_PROD,
RN_FB_PROFILING,
BROWSER_SCRIPT,
} = bundleTypes;

const moduleTypes = {
Expand Down Expand Up @@ -351,6 +353,18 @@ const bundles = [
externals: ['react', 'util', 'stream', 'react-dom'],
},

/******* React DOM Fizz Server External Runtime *******/
{
bundleTypes: [BROWSER_SCRIPT],
moduleType: RENDERER,
entry: 'react-dom/src/server/ReactDOMServerExternalRuntime.js',
outputPath: 'unstable_server-external-runtime.js',
global: 'ReactDOMServerExternalRuntime',
minifyWithProdErrorCodes: false,
wrapWithModuleBoundaries: false,
externals: [],
},

/******* React DOM Server Render Stub *******/
{
bundleTypes: [NODE_DEV, NODE_PROD, UMD_DEV, UMD_PROD],
Expand Down Expand Up @@ -1030,6 +1044,8 @@ function getOriginalFilename(bundle, bundleType) {
case RN_FB_PROFILING:
case RN_OSS_PROFILING:
return `${globalName}-profiling.js`;
case BROWSER_SCRIPT:
return `${name}.js`;
}
}

Expand Down
20 changes: 19 additions & 1 deletion scripts/rollup/packaging.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const {
RN_FB_DEV,
RN_FB_PROD,
RN_FB_PROFILING,
BROWSER_SCRIPT,
} = Bundles.bundleTypes;

function getPackageName(name) {
Expand All @@ -42,7 +43,7 @@ function getPackageName(name) {
return name;
}

function getBundleOutputPath(bundleType, filename, packageName) {
function getBundleOutputPath(bundle, bundleType, filename, packageName) {
switch (bundleType) {
case NODE_ES2015:
return `build/node_modules/${packageName}/cjs/${filename}`;
Expand Down Expand Up @@ -88,6 +89,23 @@ function getBundleOutputPath(bundleType, filename, packageName) {
default:
throw new Error('Unknown RN package.');
}
case BROWSER_SCRIPT: {
// Bundles that are served as browser scripts need to be able to be sent
// straight to the browser with any additional bundling. We shouldn't use
// a module to re-export. Depending on how they are served, they also may
// not go through package.json module resolution, so we shouldn't rely on
// that either. We should consider the output path as part of the public
// contract, and explicitly specify its location within the package's
// directory structure.
const outputPath = bundle.outputPath;
if (!outputPath) {
throw new Error(
'Bundles with type BROWSER_SCRIPT must specific an explicit ' +
'output path.'
);
}
return `build/node_modules/${packageName}/${outputPath}`;
}
default:
throw new Error('Unknown bundle type.');
}
Expand Down
8 changes: 8 additions & 0 deletions scripts/rollup/wrappers.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const {
RN_FB_DEV,
RN_FB_PROD,
RN_FB_PROFILING,
BROWSER_SCRIPT,
} = bundleTypes;

const {RECONCILER} = moduleTypes;
Expand Down Expand Up @@ -384,6 +385,12 @@ function wrapBundle(
}
}

if (bundleType === BROWSER_SCRIPT) {
// Bundles of type BROWSER_SCRIPT get sent straight to the browser without
// additional processing. So we should exclude any extra wrapper comments.
return source;
}

if (moduleType === RECONCILER) {
// Standalone reconciler is only used by third-party renderers.
// It is handled separately.
Expand All @@ -395,6 +402,7 @@ function wrapBundle(
}
return wrapper(source, globalName, filename, moduleType);
}

// All the other packages.
const wrapper = wrappers[bundleType];
if (typeof wrapper !== 'function') {
Expand Down
2 changes: 2 additions & 0 deletions scripts/shared/inlinedHostConfigs.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module.exports = [
'react-dom/src/server/ReactDOMFizzServerNode.js',
'react-dom/static.node',
'react-dom/server-rendering-stub',
'react-dom/src/server/ReactDOMServerExternalRuntime.js',
'react-server-dom-webpack/writer.node.server',
'react-server-dom-webpack',
],
Expand Down Expand Up @@ -51,6 +52,7 @@ module.exports = [
'react-dom/src/server/ReactDOMFizzServerBrowser.js',
'react-dom/static.browser',
'react-dom/server-rendering-stub',
'react-dom/src/server/ReactDOMServerExternalRuntime.js',
'react-server-dom-webpack/writer.browser.server',
'react-server-dom-webpack',
],
Expand Down

0 comments on commit 54f0e0f

Please sign in to comment.