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,