Skip to content

Commit

Permalink
Test the node-register hooks in unit tests (#25132)
Browse files Browse the repository at this point in the history
  • Loading branch information
sebmarkbage committed Aug 24, 2022
1 parent 3f70e68 commit 38c5d8a
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 62 deletions.
2 changes: 1 addition & 1 deletion packages/react-server-dom-webpack/node-register.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@
* @flow
*/

export * from './src/ReactFlightWebpackNodeRegister';
module.exports = require('./src/ReactFlightWebpackNodeRegister');
1 change: 1 addition & 0 deletions packages/react-server-dom-webpack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"./writer.browser.server": "./writer.browser.server.js",
"./node-loader": "./esm/react-server-dom-webpack-node-loader.js",
"./node-register": "./node-register.js",
"./src/*": "./src/*",
"./package.json": "./package.json"
},
"main": "index.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ module.exports = function register() {
},
};

(require: any).extensions['.client.js'] = function(module, path) {
Module._extensions['.client.js'] = function(module, path) {
const moduleId = url.pathToFileURL(path).href;
const moduleReference: {[string]: any} = {
$$typeof: MODULE_REFERENCE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,9 @@ global.TextDecoder = require('util').TextDecoder;
// TODO: we can replace this with FlightServer.act().
global.setImmediate = cb => cb();

let webpackModuleIdx = 0;
let webpackModules = {};
let webpackMap = {};
global.__webpack_require__ = function(id) {
return webpackModules[id];
};

let act;
let clientExports;
let webpackMap;
let Stream;
let React;
let ReactDOMClient;
Expand All @@ -35,15 +30,17 @@ let Suspense;
describe('ReactFlightDOM', () => {
beforeEach(() => {
jest.resetModules();
webpackModules = {};
webpackMap = {};
act = require('jest-react').act;
const WebpackMock = require('./utils/WebpackMock');
clientExports = WebpackMock.clientExports;
webpackMap = WebpackMock.webpackMap;

Stream = require('stream');
React = require('react');
Suspense = React.Suspense;
ReactDOMClient = require('react-dom/client');
ReactServerDOMWriter = require('react-server-dom-webpack/writer.node.server');
ReactServerDOMReader = require('react-server-dom-webpack');
Suspense = React.Suspense;
});

function getTestStream() {
Expand All @@ -64,22 +61,6 @@ describe('ReactFlightDOM', () => {
};
}

function moduleReference(moduleExport) {
const idx = webpackModuleIdx++;
webpackModules[idx] = {
d: moduleExport,
};
webpackMap['path/' + idx] = {
default: {
id: '' + idx,
chunks: [],
name: 'd',
},
};
const MODULE_TAG = Symbol.for('react.module.reference');
return {$$typeof: MODULE_TAG, filepath: 'path/' + idx, name: 'default'};
}

async function waitForSuspense(fn) {
while (true) {
try {
Expand Down Expand Up @@ -345,7 +326,7 @@ describe('ReactFlightDOM', () => {
return <div>{games}</div>;
}

const MyErrorBoundaryClient = moduleReference(MyErrorBoundary);
const MyErrorBoundaryClient = clientExports(MyErrorBoundary);

function ProfileContent() {
return (
Expand Down Expand Up @@ -470,7 +451,7 @@ describe('ReactFlightDOM', () => {
return <input />;
}

const InputClient = moduleReference(Input);
const InputClient = clientExports(Input);

// Server

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,9 @@ global.ReadableStream = require('web-streams-polyfill/ponyfill/es6').ReadableStr
global.TextEncoder = require('util').TextEncoder;
global.TextDecoder = require('util').TextDecoder;

let webpackModuleIdx = 0;
let webpackModules = {};
let webpackMap = {};
global.__webpack_require__ = function(id) {
return webpackModules[id];
};

let clientExports;
let webpackMap;
let webpackModules;
let act;
let React;
let ReactDOMClient;
Expand All @@ -32,9 +28,11 @@ let Suspense;
describe('ReactFlightDOMBrowser', () => {
beforeEach(() => {
jest.resetModules();
webpackModules = {};
webpackMap = {};
act = require('jest-react').act;
const WebpackMock = require('./utils/WebpackMock');
clientExports = WebpackMock.clientExports;
webpackMap = WebpackMock.webpackMap;
webpackModules = WebpackMock.webpackModules;
React = require('react');
ReactDOMClient = require('react-dom/client');
ReactDOMServer = require('react-dom/server.browser');
Expand All @@ -43,22 +41,6 @@ describe('ReactFlightDOMBrowser', () => {
Suspense = React.Suspense;
});

function moduleReference(moduleExport) {
const idx = webpackModuleIdx++;
webpackModules[idx] = {
d: moduleExport,
};
webpackMap['path/' + idx] = {
default: {
id: '' + idx,
chunks: [],
name: 'd',
},
};
const MODULE_TAG = Symbol.for('react.module.reference');
return {$$typeof: MODULE_TAG, filepath: 'path/' + idx, name: 'default'};
}

async function waitForSuspense(fn) {
while (true) {
try {
Expand Down Expand Up @@ -249,7 +231,7 @@ describe('ReactFlightDOMBrowser', () => {
return <div>{games}</div>;
}

const MyErrorBoundaryClient = moduleReference(MyErrorBoundary);
const MyErrorBoundaryClient = clientExports(MyErrorBoundary);

function ProfileContent() {
return (
Expand Down Expand Up @@ -478,19 +460,19 @@ describe('ReactFlightDOMBrowser', () => {
}
// The Client build may not have the same IDs as the Server bundles for the same
// component.
const ClientComponentOnTheClient = moduleReference(ClientComponent);
const ClientComponentOnTheServer = moduleReference(ClientComponent);
const ClientComponentOnTheClient = clientExports(ClientComponent);
const ClientComponentOnTheServer = clientExports(ClientComponent);

// In the SSR bundle this module won't exist. We simulate this by deleting it.
const clientId = webpackMap[ClientComponentOnTheClient.filepath].default.id;
const clientId = webpackMap[ClientComponentOnTheClient.filepath]['*'].id;
delete webpackModules[clientId];

// Instead, we have to provide a translation from the client meta data to the SSR
// meta data.
const ssrMetaData = webpackMap[ClientComponentOnTheServer.filepath].default;
const ssrMetaData = webpackMap[ClientComponentOnTheServer.filepath]['*'];
const translationMap = {
[clientId]: {
d: ssrMetaData,
'*': ssrMetaData,
},
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

const url = require('url');
const Module = require('module');

let webpackModuleIdx = 0;
const webpackModules = {};
const webpackMap = {};
global.__webpack_require__ = function(id) {
return webpackModules[id];
};

const previousLoader = Module._extensions['.client.js'];

const register = require('react-server-dom-webpack/node-register');
// Register node loader
register();

const nodeLoader = Module._extensions['.client.js'];

if (previousLoader === nodeLoader) {
throw new Error(
'Expected the Node loader to register the .client.js extension',
);
}

Module._extensions['.client.js'] = previousLoader;

exports.webpackMap = webpackMap;
exports.webpackModules = webpackModules;

exports.clientExports = function clientExports(moduleExports) {
const idx = '' + webpackModuleIdx++;
webpackModules[idx] = moduleExports;
const path = url.pathToFileURL(idx).href;
webpackMap[path] = {
'': {
id: idx,
chunks: [],
name: '',
},
'*': {
id: idx,
chunks: [],
name: '*',
},
};
for (const name in moduleExports) {
webpackMap[path] = {
[name]: {
id: idx,
chunks: [],
name: name,
},
};
}
const mod = {exports: {}};
nodeLoader(mod, idx);
return mod.exports;
};
3 changes: 2 additions & 1 deletion scripts/rollup/bundles.js
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,8 @@ const bundles = [
{
bundleTypes: [NODE_ES2015],
moduleType: RENDERER_UTILS,
entry: 'react-server-dom-webpack/node-register',
entry: 'react-server-dom-webpack/src/ReactFlightWebpackNodeRegister.js',
name: 'react-server-dom-webpack-node-register',
global: 'ReactFlightWebpackNodeRegister',
minifyWithProdErrorCodes: false,
wrapWithModuleBoundaries: false,
Expand Down

0 comments on commit 38c5d8a

Please sign in to comment.