@samitouri / QOS-React-2 / commits / 38c5d8a035

Test the node-register hooks in unit tests (#25132)

Sebastian Markbåge committed Aug 24, 2022 at 19:05 UTC 38c5d8a035c6e8070ab00d9cf7b9d2fae7752fdf
7 files changed +94 -62
packages/react-server-dom-webpack/node-register.js
+1 -1
@@ -7,4 +7,4 @@
7 * @flow
8 */
9
10 -export * from './src/ReactFlightWebpackNodeRegister';
10 +module.exports = require('./src/ReactFlightWebpackNodeRegister');
packages/react-server-dom-webpack/package.json
+1
@@ -35,6 +35,7 @@
35 "./writer.browser.server": "./writer.browser.server.js",
36 "./node-loader": "./esm/react-server-dom-webpack-node-loader.js",
37 "./node-register": "./node-register.js",
38 + "./src/*": "./src/*",
39 "./package.json": "./package.json"
40 },
41 "main": "index.js",
packages/react-server-dom-webpack/src/ReactFlightWebpackNodeRegister.js
+1 -1
@@ -57,7 +57,7 @@ module.exports = function register() {
57 },
58 };
59
60 - (require: any).extensions['.client.js'] = function(module, path) {
60 + Module._extensions['.client.js'] = function(module, path) {
61 const moduleId = url.pathToFileURL(path).href;
62 const moduleReference: {[string]: any} = {
63 $$typeof: MODULE_REFERENCE,
packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js
+9 -28
@@ -17,14 +17,9 @@ global.TextDecoder = require('util').TextDecoder;
17 // TODO: we can replace this with FlightServer.act().
18 global.setImmediate = cb => cb();
19
20 -let webpackModuleIdx = 0;
21 -let webpackModules = {};
22 -let webpackMap = {};
23 -global.__webpack_require__ = function(id) {
24 - return webpackModules[id];
25 -};
26 -
20 let act;
21 +let clientExports;
22 +let webpackMap;
23 let Stream;
24 let React;
25 let ReactDOMClient;
@@ -35,15 +30,17 @@ let Suspense;
30 describe('ReactFlightDOM', () => {
31 beforeEach(() => {
32 jest.resetModules();
38 - webpackModules = {};
39 - webpackMap = {};
33 act = require('jest-react').act;
34 + const WebpackMock = require('./utils/WebpackMock');
35 + clientExports = WebpackMock.clientExports;
36 + webpackMap = WebpackMock.webpackMap;
37 +
38 Stream = require('stream');
39 React = require('react');
40 + Suspense = React.Suspense;
41 ReactDOMClient = require('react-dom/client');
42 ReactServerDOMWriter = require('react-server-dom-webpack/writer.node.server');
43 ReactServerDOMReader = require('react-server-dom-webpack');
46 - Suspense = React.Suspense;
44 });
45
46 function getTestStream() {
@@ -64,22 +61,6 @@ describe('ReactFlightDOM', () => {
61 };
62 }
63
67 - function moduleReference(moduleExport) {
68 - const idx = webpackModuleIdx++;
69 - webpackModules[idx] = {
70 - d: moduleExport,
71 - };
72 - webpackMap['path/' + idx] = {
73 - default: {
74 - id: '' + idx,
75 - chunks: [],
76 - name: 'd',
77 - },
78 - };
79 - const MODULE_TAG = Symbol.for('react.module.reference');
80 - return {$$typeof: MODULE_TAG, filepath: 'path/' + idx, name: 'default'};
81 - }
82 -
64 async function waitForSuspense(fn) {
65 while (true) {
66 try {
@@ -345,7 +326,7 @@ describe('ReactFlightDOM', () => {
326 return <div>{games}</div>;
327 }
328
348 - const MyErrorBoundaryClient = moduleReference(MyErrorBoundary);
329 + const MyErrorBoundaryClient = clientExports(MyErrorBoundary);
330
331 function ProfileContent() {
332 return (
@@ -470,7 +451,7 @@ describe('ReactFlightDOM', () => {
451 return <input />;
452 }
453
473 - const InputClient = moduleReference(Input);
454 + const InputClient = clientExports(Input);
455
456 // Server
457
packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js
+13 -31
@@ -14,13 +14,9 @@ global.ReadableStream = require('web-streams-polyfill/ponyfill/es6').ReadableStr
14 global.TextEncoder = require('util').TextEncoder;
15 global.TextDecoder = require('util').TextDecoder;
16
17 -let webpackModuleIdx = 0;
18 -let webpackModules = {};
19 -let webpackMap = {};
20 -global.__webpack_require__ = function(id) {
21 - return webpackModules[id];
22 -};
23 -
17 +let clientExports;
18 +let webpackMap;
19 +let webpackModules;
20 let act;
21 let React;
22 let ReactDOMClient;
@@ -32,9 +28,11 @@ let Suspense;
28 describe('ReactFlightDOMBrowser', () => {
29 beforeEach(() => {
30 jest.resetModules();
35 - webpackModules = {};
36 - webpackMap = {};
31 act = require('jest-react').act;
32 + const WebpackMock = require('./utils/WebpackMock');
33 + clientExports = WebpackMock.clientExports;
34 + webpackMap = WebpackMock.webpackMap;
35 + webpackModules = WebpackMock.webpackModules;
36 React = require('react');
37 ReactDOMClient = require('react-dom/client');
38 ReactDOMServer = require('react-dom/server.browser');
@@ -43,22 +41,6 @@ describe('ReactFlightDOMBrowser', () => {
41 Suspense = React.Suspense;
42 });
43
46 - function moduleReference(moduleExport) {
47 - const idx = webpackModuleIdx++;
48 - webpackModules[idx] = {
49 - d: moduleExport,
50 - };
51 - webpackMap['path/' + idx] = {
52 - default: {
53 - id: '' + idx,
54 - chunks: [],
55 - name: 'd',
56 - },
57 - };
58 - const MODULE_TAG = Symbol.for('react.module.reference');
59 - return {$$typeof: MODULE_TAG, filepath: 'path/' + idx, name: 'default'};
60 - }
61 -
44 async function waitForSuspense(fn) {
45 while (true) {
46 try {
@@ -249,7 +231,7 @@ describe('ReactFlightDOMBrowser', () => {
231 return <div>{games}</div>;
232 }
233
252 - const MyErrorBoundaryClient = moduleReference(MyErrorBoundary);
234 + const MyErrorBoundaryClient = clientExports(MyErrorBoundary);
235
236 function ProfileContent() {
237 return (
@@ -478,19 +460,19 @@ describe('ReactFlightDOMBrowser', () => {
460 }
461 // The Client build may not have the same IDs as the Server bundles for the same
462 // component.
481 - const ClientComponentOnTheClient = moduleReference(ClientComponent);
482 - const ClientComponentOnTheServer = moduleReference(ClientComponent);
463 + const ClientComponentOnTheClient = clientExports(ClientComponent);
464 + const ClientComponentOnTheServer = clientExports(ClientComponent);
465
466 // In the SSR bundle this module won't exist. We simulate this by deleting it.
485 - const clientId = webpackMap[ClientComponentOnTheClient.filepath].default.id;
467 + const clientId = webpackMap[ClientComponentOnTheClient.filepath]['*'].id;
468 delete webpackModules[clientId];
469
470 // Instead, we have to provide a translation from the client meta data to the SSR
471 // meta data.
490 - const ssrMetaData = webpackMap[ClientComponentOnTheServer.filepath].default;
472 + const ssrMetaData = webpackMap[ClientComponentOnTheServer.filepath]['*'];
473 const translationMap = {
474 [clientId]: {
493 - d: ssrMetaData,
475 + '*': ssrMetaData,
476 },
477 };
478
packages/react-server-dom-webpack/src/__tests__/utils/WebpackMock.js new
+67
@@ -0,0 +1,67 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + */
7 +
8 +'use strict';
9 +
10 +const url = require('url');
11 +const Module = require('module');
12 +
13 +let webpackModuleIdx = 0;
14 +const webpackModules = {};
15 +const webpackMap = {};
16 +global.__webpack_require__ = function(id) {
17 + return webpackModules[id];
18 +};
19 +
20 +const previousLoader = Module._extensions['.client.js'];
21 +
22 +const register = require('react-server-dom-webpack/node-register');
23 +// Register node loader
24 +register();
25 +
26 +const nodeLoader = Module._extensions['.client.js'];
27 +
28 +if (previousLoader === nodeLoader) {
29 + throw new Error(
30 + 'Expected the Node loader to register the .client.js extension',
31 + );
32 +}
33 +
34 +Module._extensions['.client.js'] = previousLoader;
35 +
36 +exports.webpackMap = webpackMap;
37 +exports.webpackModules = webpackModules;
38 +
39 +exports.clientExports = function clientExports(moduleExports) {
40 + const idx = '' + webpackModuleIdx++;
41 + webpackModules[idx] = moduleExports;
42 + const path = url.pathToFileURL(idx).href;
43 + webpackMap[path] = {
44 + '': {
45 + id: idx,
46 + chunks: [],
47 + name: '',
48 + },
49 + '*': {
50 + id: idx,
51 + chunks: [],
52 + name: '*',
53 + },
54 + };
55 + for (const name in moduleExports) {
56 + webpackMap[path] = {
57 + [name]: {
58 + id: idx,
59 + chunks: [],
60 + name: name,
61 + },
62 + };
63 + }
64 + const mod = {exports: {}};
65 + nodeLoader(mod, idx);
66 + return mod.exports;
67 +};
scripts/rollup/bundles.js
+2 -1
@@ -408,7 +408,8 @@ const bundles = [
408 {
409 bundleTypes: [NODE_ES2015],
410 moduleType: RENDERER_UTILS,
411 - entry: 'react-server-dom-webpack/node-register',
411 + entry: 'react-server-dom-webpack/src/ReactFlightWebpackNodeRegister.js',
412 + name: 'react-server-dom-webpack-node-register',
413 global: 'ReactFlightWebpackNodeRegister',
414 minifyWithProdErrorCodes: false,
415 wrapWithModuleBoundaries: false,