Skip to content

Commit 38c5d8a

Browse files
authored
Test the node-register hooks in unit tests (#25132)
1 parent 3f70e68 commit 38c5d8a

File tree

7 files changed

+94
-62
lines changed

7 files changed

+94
-62
lines changed

packages/react-server-dom-webpack/node-register.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77
* @flow
88
*/
99

10-
export * from './src/ReactFlightWebpackNodeRegister';
10+
module.exports = require('./src/ReactFlightWebpackNodeRegister');

packages/react-server-dom-webpack/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"./writer.browser.server": "./writer.browser.server.js",
3636
"./node-loader": "./esm/react-server-dom-webpack-node-loader.js",
3737
"./node-register": "./node-register.js",
38+
"./src/*": "./src/*",
3839
"./package.json": "./package.json"
3940
},
4041
"main": "index.js",

packages/react-server-dom-webpack/src/ReactFlightWebpackNodeRegister.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ module.exports = function register() {
5757
},
5858
};
5959

60-
(require: any).extensions['.client.js'] = function(module, path) {
60+
Module._extensions['.client.js'] = function(module, path) {
6161
const moduleId = url.pathToFileURL(path).href;
6262
const moduleReference: {[string]: any} = {
6363
$$typeof: MODULE_REFERENCE,

packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js

+9-28
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,9 @@ global.TextDecoder = require('util').TextDecoder;
1717
// TODO: we can replace this with FlightServer.act().
1818
global.setImmediate = cb => cb();
1919

20-
let webpackModuleIdx = 0;
21-
let webpackModules = {};
22-
let webpackMap = {};
23-
global.__webpack_require__ = function(id) {
24-
return webpackModules[id];
25-
};
26-
2720
let act;
21+
let clientExports;
22+
let webpackMap;
2823
let Stream;
2924
let React;
3025
let ReactDOMClient;
@@ -35,15 +30,17 @@ let Suspense;
3530
describe('ReactFlightDOM', () => {
3631
beforeEach(() => {
3732
jest.resetModules();
38-
webpackModules = {};
39-
webpackMap = {};
4033
act = require('jest-react').act;
34+
const WebpackMock = require('./utils/WebpackMock');
35+
clientExports = WebpackMock.clientExports;
36+
webpackMap = WebpackMock.webpackMap;
37+
4138
Stream = require('stream');
4239
React = require('react');
40+
Suspense = React.Suspense;
4341
ReactDOMClient = require('react-dom/client');
4442
ReactServerDOMWriter = require('react-server-dom-webpack/writer.node.server');
4543
ReactServerDOMReader = require('react-server-dom-webpack');
46-
Suspense = React.Suspense;
4744
});
4845

4946
function getTestStream() {
@@ -64,22 +61,6 @@ describe('ReactFlightDOM', () => {
6461
};
6562
}
6663

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-
8364
async function waitForSuspense(fn) {
8465
while (true) {
8566
try {
@@ -345,7 +326,7 @@ describe('ReactFlightDOM', () => {
345326
return <div>{games}</div>;
346327
}
347328

348-
const MyErrorBoundaryClient = moduleReference(MyErrorBoundary);
329+
const MyErrorBoundaryClient = clientExports(MyErrorBoundary);
349330

350331
function ProfileContent() {
351332
return (
@@ -470,7 +451,7 @@ describe('ReactFlightDOM', () => {
470451
return <input />;
471452
}
472453

473-
const InputClient = moduleReference(Input);
454+
const InputClient = clientExports(Input);
474455

475456
// Server
476457

packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js

+13-31
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,9 @@ global.ReadableStream = require('web-streams-polyfill/ponyfill/es6').ReadableStr
1414
global.TextEncoder = require('util').TextEncoder;
1515
global.TextDecoder = require('util').TextDecoder;
1616

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;
2420
let act;
2521
let React;
2622
let ReactDOMClient;
@@ -32,9 +28,11 @@ let Suspense;
3228
describe('ReactFlightDOMBrowser', () => {
3329
beforeEach(() => {
3430
jest.resetModules();
35-
webpackModules = {};
36-
webpackMap = {};
3731
act = require('jest-react').act;
32+
const WebpackMock = require('./utils/WebpackMock');
33+
clientExports = WebpackMock.clientExports;
34+
webpackMap = WebpackMock.webpackMap;
35+
webpackModules = WebpackMock.webpackModules;
3836
React = require('react');
3937
ReactDOMClient = require('react-dom/client');
4038
ReactDOMServer = require('react-dom/server.browser');
@@ -43,22 +41,6 @@ describe('ReactFlightDOMBrowser', () => {
4341
Suspense = React.Suspense;
4442
});
4543

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-
6244
async function waitForSuspense(fn) {
6345
while (true) {
6446
try {
@@ -249,7 +231,7 @@ describe('ReactFlightDOMBrowser', () => {
249231
return <div>{games}</div>;
250232
}
251233

252-
const MyErrorBoundaryClient = moduleReference(MyErrorBoundary);
234+
const MyErrorBoundaryClient = clientExports(MyErrorBoundary);
253235

254236
function ProfileContent() {
255237
return (
@@ -478,19 +460,19 @@ describe('ReactFlightDOMBrowser', () => {
478460
}
479461
// The Client build may not have the same IDs as the Server bundles for the same
480462
// component.
481-
const ClientComponentOnTheClient = moduleReference(ClientComponent);
482-
const ClientComponentOnTheServer = moduleReference(ClientComponent);
463+
const ClientComponentOnTheClient = clientExports(ClientComponent);
464+
const ClientComponentOnTheServer = clientExports(ClientComponent);
483465

484466
// 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;
486468
delete webpackModules[clientId];
487469

488470
// Instead, we have to provide a translation from the client meta data to the SSR
489471
// meta data.
490-
const ssrMetaData = webpackMap[ClientComponentOnTheServer.filepath].default;
472+
const ssrMetaData = webpackMap[ClientComponentOnTheServer.filepath]['*'];
491473
const translationMap = {
492474
[clientId]: {
493-
d: ssrMetaData,
475+
'*': ssrMetaData,
494476
},
495477
};
496478

Original file line numberDiff line numberDiff line change
@@ -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
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,8 @@ const bundles = [
408408
{
409409
bundleTypes: [NODE_ES2015],
410410
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',
412413
global: 'ReactFlightWebpackNodeRegister',
413414
minifyWithProdErrorCodes: false,
414415
wrapWithModuleBoundaries: false,

0 commit comments

Comments
 (0)