@samitouri / QOS-React-2 / commits / 54f0e0f730

Scaffolding for react-dom/unstable_external-server-runtime (#25482)

* 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>

Andrew Clark committed Oct 14, 2022 at 23:29 UTC 54f0e0f7308b4d0d51e52e149d3f7e5a207991ee
7 files changed +90 -23
packages/react-dom/package.json
+1
@@ -38,6 +38,7 @@
38 "server-rendering-stub.js",
39 "test-utils.js",
40 "unstable_testing.js",
41 + "unstable_server-external-runtime.js",
42 "cjs/",
43 "umd/"
44 ],
packages/react-dom/src/server/ReactDOMServerExternalRuntime.js new
+18
@@ -0,0 +1,18 @@
1 +// TODO: Add Flow types
2 +import {
3 + clientRenderBoundary,
4 + completeBoundaryWithStyles,
5 + completeBoundary,
6 + completeSegment,
7 +} from 'react-dom-bindings/src/server/fizz-instruction-set/ReactDOMFizzInstructionSet';
8 +
9 +// Intentionally does nothing. Implementation will be added in future PR.
10 +// eslint-disable-next-line no-unused-vars
11 +const observer = new MutationObserver(mutations => {
12 + // These are only called so I can check what the module output looks like. The
13 + // code is unreachable.
14 + clientRenderBoundary();
15 + completeBoundaryWithStyles();
16 + completeBoundary();
17 + completeSegment();
18 +});
scripts/rollup/build.js
+26 -22
@@ -60,6 +60,7 @@ const {
60 RN_FB_DEV,
61 RN_FB_PROD,
62 RN_FB_PROFILING,
63 + BROWSER_SCRIPT,
64 } = Bundles.bundleTypes;
65
66 const {getFilename} = Bundles;
@@ -93,19 +94,6 @@ const isWatchMode = argv.watch;
94 const syncFBSourcePath = argv['sync-fbsource'];
95 const syncWWWPath = argv['sync-www'];
96
96 -const closureOptions = {
97 - compilation_level: 'SIMPLE',
98 - language_in: 'ECMASCRIPT_2015',
99 - language_out: 'ECMASCRIPT5_STRICT',
100 - env: 'CUSTOM',
101 - warning_level: 'QUIET',
102 - apply_input_source_maps: false,
103 - use_types_for_optimization: false,
104 - process_common_js_modules: false,
105 - rewrite_polyfills: false,
106 - inject_libraries: false,
107 -};
108 -
97 // Non-ES2015 stuff applied before closure compiler.
98 const babelPlugins = [
99 // These plugins filter out non-ES2015.
@@ -224,6 +212,8 @@ function getFormat(bundleType) {
212 return `cjs`;
213 case NODE_ESM:
214 return `es`;
215 + case BROWSER_SCRIPT:
216 + return `iife`;
217 }
218 }
219
@@ -247,6 +237,7 @@ function isProductionBundleType(bundleType) {
237 case RN_OSS_PROFILING:
238 case RN_FB_PROD:
239 case RN_FB_PROFILING:
240 + case BROWSER_SCRIPT:
241 return true;
242 default:
243 throw new Error(`Unknown type: ${bundleType}`);
@@ -267,6 +258,7 @@ function isProfilingBundleType(bundleType) {
258 case RN_OSS_PROD:
259 case UMD_DEV:
260 case UMD_PROD:
261 + case BROWSER_SCRIPT:
262 return false;
263 case FB_WWW_PROFILING:
264 case NODE_PROFILING:
@@ -371,14 +363,24 @@ function getPlugins(
363 isUMDBundle && entry === 'react-art' && commonjs(),
364 // Apply dead code elimination and/or minification.
365 isProduction &&
374 - closure(
375 - Object.assign({}, closureOptions, {
376 - // Don't let it create global variables in the browser.
377 - // https://github.com/facebook/react/issues/10909
378 - assume_function_wrapper: !isUMDBundle,
379 - renaming: !shouldStayReadable,
380 - })
381 - ),
366 + closure({
367 + compilation_level: 'SIMPLE',
368 + language_in: 'ECMASCRIPT_2015',
369 + language_out:
370 + bundleType === BROWSER_SCRIPT ? 'ECMASCRIPT5' : 'ECMASCRIPT5_STRICT',
371 + env: 'CUSTOM',
372 + warning_level: 'QUIET',
373 + apply_input_source_maps: false,
374 + use_types_for_optimization: false,
375 + process_common_js_modules: false,
376 + rewrite_polyfills: false,
377 + inject_libraries: false,
378 +
379 + // Don't let it create global variables in the browser.
380 + // https://github.com/facebook/react/issues/10909
381 + assume_function_wrapper: !isUMDBundle,
382 + renaming: !shouldStayReadable,
383 + }),
384 // HACK to work around the fact that Rollup isn't removing unused, pure-module imports.
385 // Note that this plugin must be called after closure applies DCE.
386 isProduction && stripUnusedImports(pureExternalModules),
@@ -582,6 +584,7 @@ async function createBundle(bundle, bundleType) {
584 },
585 };
586 const mainOutputPath = Packaging.getBundleOutputPath(
587 + bundle,
588 bundleType,
589 filename,
590 packageName
@@ -724,7 +727,8 @@ async function buildEverything() {
727 [bundle, RN_OSS_PROFILING],
728 [bundle, RN_FB_DEV],
729 [bundle, RN_FB_PROD],
727 - [bundle, RN_FB_PROFILING]
730 + [bundle, RN_FB_PROFILING],
731 + [bundle, BROWSER_SCRIPT]
732 );
733 }
734
scripts/rollup/bundles.js
+16
@@ -25,6 +25,7 @@ const bundleTypes = {
25 RN_FB_DEV: 'RN_FB_DEV',
26 RN_FB_PROD: 'RN_FB_PROD',
27 RN_FB_PROFILING: 'RN_FB_PROFILING',
28 + BROWSER_SCRIPT: 'BROWSER_SCRIPT',
29 };
30
31 const {
@@ -45,6 +46,7 @@ const {
46 RN_FB_DEV,
47 RN_FB_PROD,
48 RN_FB_PROFILING,
49 + BROWSER_SCRIPT,
50 } = bundleTypes;
51
52 const moduleTypes = {
@@ -351,6 +353,18 @@ const bundles = [
353 externals: ['react', 'util', 'stream', 'react-dom'],
354 },
355
356 + /******* React DOM Fizz Server External Runtime *******/
357 + {
358 + bundleTypes: [BROWSER_SCRIPT],
359 + moduleType: RENDERER,
360 + entry: 'react-dom/src/server/ReactDOMServerExternalRuntime.js',
361 + outputPath: 'unstable_server-external-runtime.js',
362 + global: 'ReactDOMServerExternalRuntime',
363 + minifyWithProdErrorCodes: false,
364 + wrapWithModuleBoundaries: false,
365 + externals: [],
366 + },
367 +
368 /******* React DOM Server Render Stub *******/
369 {
370 bundleTypes: [NODE_DEV, NODE_PROD, UMD_DEV, UMD_PROD],
@@ -1030,6 +1044,8 @@ function getOriginalFilename(bundle, bundleType) {
1044 case RN_FB_PROFILING:
1045 case RN_OSS_PROFILING:
1046 return `${globalName}-profiling.js`;
1047 + case BROWSER_SCRIPT:
1048 + return `${name}.js`;
1049 }
1050 }
1051
scripts/rollup/packaging.js
+19 -1
@@ -33,6 +33,7 @@ const {
33 RN_FB_DEV,
34 RN_FB_PROD,
35 RN_FB_PROFILING,
36 + BROWSER_SCRIPT,
37 } = Bundles.bundleTypes;
38
39 function getPackageName(name) {
@@ -42,7 +43,7 @@ function getPackageName(name) {
43 return name;
44 }
45
45 -function getBundleOutputPath(bundleType, filename, packageName) {
46 +function getBundleOutputPath(bundle, bundleType, filename, packageName) {
47 switch (bundleType) {
48 case NODE_ES2015:
49 return `build/node_modules/${packageName}/cjs/${filename}`;
@@ -88,6 +89,23 @@ function getBundleOutputPath(bundleType, filename, packageName) {
89 default:
90 throw new Error('Unknown RN package.');
91 }
92 + case BROWSER_SCRIPT: {
93 + // Bundles that are served as browser scripts need to be able to be sent
94 + // straight to the browser with any additional bundling. We shouldn't use
95 + // a module to re-export. Depending on how they are served, they also may
96 + // not go through package.json module resolution, so we shouldn't rely on
97 + // that either. We should consider the output path as part of the public
98 + // contract, and explicitly specify its location within the package's
99 + // directory structure.
100 + const outputPath = bundle.outputPath;
101 + if (!outputPath) {
102 + throw new Error(
103 + 'Bundles with type BROWSER_SCRIPT must specific an explicit ' +
104 + 'output path.'
105 + );
106 + }
107 + return `build/node_modules/${packageName}/${outputPath}`;
108 + }
109 default:
110 throw new Error('Unknown bundle type.');
111 }
scripts/rollup/wrappers.js
+8
@@ -22,6 +22,7 @@ const {
22 RN_FB_DEV,
23 RN_FB_PROD,
24 RN_FB_PROFILING,
25 + BROWSER_SCRIPT,
26 } = bundleTypes;
27
28 const {RECONCILER} = moduleTypes;
@@ -384,6 +385,12 @@ function wrapBundle(
385 }
386 }
387
388 + if (bundleType === BROWSER_SCRIPT) {
389 + // Bundles of type BROWSER_SCRIPT get sent straight to the browser without
390 + // additional processing. So we should exclude any extra wrapper comments.
391 + return source;
392 + }
393 +
394 if (moduleType === RECONCILER) {
395 // Standalone reconciler is only used by third-party renderers.
396 // It is handled separately.
@@ -395,6 +402,7 @@ function wrapBundle(
402 }
403 return wrapper(source, globalName, filename, moduleType);
404 }
405 +
406 // All the other packages.
407 const wrapper = wrappers[bundleType];
408 if (typeof wrapper !== 'function') {
scripts/shared/inlinedHostConfigs.js
+2
@@ -15,6 +15,7 @@ module.exports = [
15 'react-dom/src/server/ReactDOMFizzServerNode.js',
16 'react-dom/static.node',
17 'react-dom/server-rendering-stub',
18 + 'react-dom/src/server/ReactDOMServerExternalRuntime.js',
19 'react-server-dom-webpack/writer.node.server',
20 'react-server-dom-webpack',
21 ],
@@ -51,6 +52,7 @@ module.exports = [
52 'react-dom/src/server/ReactDOMFizzServerBrowser.js',
53 'react-dom/static.browser',
54 'react-dom/server-rendering-stub',
55 + 'react-dom/src/server/ReactDOMServerExternalRuntime.js',
56 'react-server-dom-webpack/writer.browser.server',
57 'react-server-dom-webpack',
58 ],