Skip to content

Commit 82e99e1

Browse files
authored
Add Node ESM Loader and Register Entrypoints (#20274)
* Add Node ESM loader build This adds a loader build as a first-class export. This will grow in complexity so it deserves its own module. * Add Node CommonJS regiter build This adds a build as a first-class export for legacy CommonJS registration in Node.js. This will grow in complexity so it deserves its own module. * Simplify fixture a bit to easier show usage with or without esm * Bump es version We leave async function in here which are newer than ES2015.
1 parent bf7b7ae commit 82e99e1

18 files changed

+181
-84
lines changed

fixtures/flight/loader/index.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import {resolve, getSource} from 'react-transport-dom-webpack/node-loader';
2+
3+
export {resolve, getSource};
4+
5+
import babel from '@babel/core';
6+
7+
const babelOptions = {
8+
babelrc: false,
9+
ignore: [/\/(build|node_modules)\//],
10+
plugins: [
11+
'@babel/plugin-syntax-import-meta',
12+
'@babel/plugin-transform-react-jsx',
13+
],
14+
};
15+
16+
export async function transformSource(source, context, defaultTransformSource) {
17+
const {format} = context;
18+
if (format === 'module') {
19+
const opt = Object.assign({filename: context.url}, babelOptions);
20+
const {code} = await babel.transformAsync(source, opt);
21+
return {source: code};
22+
}
23+
return defaultTransformSource(source, context, defaultTransformSource);
24+
}

fixtures/flight/loader/package.json

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"type": "module"
3+
}

fixtures/flight/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
"prebuild": "cp -r ../../build/node_modules/* ./node_modules/",
6868
"start": "concurrently \"npm run start:server\" \"npm run start:client\"",
6969
"start:client": "node scripts/start.js",
70-
"start:server": "NODE_ENV=development node --experimental-loader ./server/loader.mjs server",
70+
"start:server": "NODE_ENV=development node --experimental-loader ./loader/index.js server",
7171
"start:prod": "node scripts/build.js && NODE_ENV=production node server",
7272
"build": "node scripts/build.js",
7373
"test": "node scripts/test.js --env=jsdom"

fixtures/flight/server/handler.server.js

+12-4
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,26 @@
22

33
import {pipeToNodeWritable} from 'react-transport-dom-webpack/server';
44
import * as React from 'react';
5-
import App from '../src/App.server';
65

7-
module.exports = function(req, res) {
6+
import url from 'url';
7+
8+
function resolve(path) {
9+
return url.pathToFileURL(require.resolve(path)).href;
10+
}
11+
12+
module.exports = async function(req, res) {
813
res.setHeader('Access-Control-Allow-Origin', '*');
14+
const m = await import('../src/App.server.js');
15+
// const m = require('../src/App.server.js');
16+
const App = m.default.default || m.default;
917
pipeToNodeWritable(<App />, res, {
1018
// TODO: Read from a map on the disk.
11-
[require.resolve('../src/Counter.client.js')]: {
19+
[resolve('../src/Counter.client.js')]: {
1220
id: './src/Counter.client.js',
1321
chunks: ['1'],
1422
name: 'default',
1523
},
16-
[require.resolve('../src/ShowMore.client.js')]: {
24+
[resolve('../src/ShowMore.client.js')]: {
1725
id: './src/ShowMore.client.js',
1826
chunks: ['2'],
1927
name: 'default',

fixtures/flight/server/handler.server.mjs

-27
This file was deleted.

fixtures/flight/server/index.js

+3-8
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
'use strict';
22

3-
require.extensions['.client.js'] = function(module, path) {
4-
module.exports = {
5-
$$typeof: Symbol.for('react.module.reference'),
6-
name: path,
7-
};
8-
};
3+
const register = require('react-transport-dom-webpack/node-register');
4+
register();
95

106
const babelRegister = require('@babel/register');
117

@@ -25,8 +21,7 @@ app.get('/', function(req, res) {
2521
delete require.cache[key];
2622
}
2723
}
28-
import('./handler.server.mjs').then(m => m.default(req, res));
29-
// require('./handler.server.js')(req, res);
24+
require('./handler.server.js')(req, res);
3025
});
3126

3227
app.listen(3001, () => {

fixtures/flight/server/loader.mjs

-42
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"type": "module"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
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+
* @flow
8+
*/
9+
10+
export * from '../src/ReactFlightWebpackNodeLoader.js';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
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+
* @flow
8+
*/
9+
10+
export * from './src/ReactFlightWebpackNodeRegister';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"type": "module"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
'use strict';
2+
3+
module.exports = require('./cjs/react-transport-dom-webpack-node-register.js');

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

+13-1
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,21 @@
1717
"server.js",
1818
"server.browser.js",
1919
"server.node.js",
20+
"node-register.js",
2021
"cjs/",
21-
"umd/"
22+
"umd/",
23+
"esm/"
2224
],
25+
"exports": {
26+
".": "./index.js",
27+
"./plugin": "./plugin.js",
28+
"./server": "./server.js",
29+
"./server.browser": "./server.browser.js",
30+
"./server.node": "./server.node.js",
31+
"./node-loader": "./esm/react-transport-dom-webpack-node-loader.js",
32+
"./node-register": "./node-register.js",
33+
"./package.json": "./package.json"
34+
},
2335
"browser": {
2436
"./server.js": "./server.browser.js"
2537
},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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+
* @flow
8+
*/
9+
10+
type ResolveContext = {
11+
conditions: Array<string>,
12+
parentURL: string | void,
13+
};
14+
15+
type ResolveFunction = (
16+
string,
17+
ResolveContext,
18+
ResolveFunction,
19+
) => Promise<string>;
20+
21+
type GetSourceContext = {
22+
format: string,
23+
url: string,
24+
};
25+
26+
type GetSourceFunction = (
27+
string,
28+
GetSourceContext,
29+
GetSourceFunction,
30+
) => Promise<{source: Source}>;
31+
32+
type Source = string | ArrayBuffer | Uint8Array;
33+
34+
export async function resolve(
35+
specifier: string,
36+
context: ResolveContext,
37+
defaultResolve: ResolveFunction,
38+
): Promise<string> {
39+
// TODO: Resolve server-only files.
40+
return defaultResolve(specifier, context, defaultResolve);
41+
}
42+
43+
export async function getSource(
44+
url: string,
45+
context: GetSourceContext,
46+
defaultGetSource: GetSourceFunction,
47+
): Promise<{source: Source}> {
48+
if (url.endsWith('.client.js')) {
49+
// TODO: Named exports.
50+
const src =
51+
"export default { $$typeof: Symbol.for('react.module.reference'), name: " +
52+
JSON.stringify(url) +
53+
'}';
54+
return {source: src};
55+
}
56+
return defaultGetSource(url, context, defaultGetSource);
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
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+
* @flow
8+
*/
9+
10+
const url = require('url');
11+
12+
module.exports = function register() {
13+
(require: any).extensions['.client.js'] = function(module, path) {
14+
module.exports = {
15+
$$typeof: Symbol.for('react.module.reference'),
16+
name: url.pathToFileURL(path).href,
17+
};
18+
};
19+
};

scripts/rollup/bundles.js

+18
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,24 @@ const bundles = [
286286
externals: [],
287287
},
288288

289+
/******* React Transport DOM Webpack Node.js Loader *******/
290+
{
291+
bundleTypes: [NODE_ESM],
292+
moduleType: RENDERER_UTILS,
293+
entry: 'react-transport-dom-webpack/node-loader',
294+
global: 'ReactFlightWebpackNodeLoader',
295+
externals: [],
296+
},
297+
298+
/******* React Transport DOM Webpack Node.js CommonJS Loader *******/
299+
{
300+
bundleTypes: [NODE_ES2015],
301+
moduleType: RENDERER_UTILS,
302+
entry: 'react-transport-dom-webpack/node-register',
303+
global: 'ReactFlightWebpackNodeRegister',
304+
externals: ['url'],
305+
},
306+
289307
/******* React Transport DOM Server Relay *******/
290308
{
291309
bundleTypes: [FB_WWW_DEV, FB_WWW_PROD],

scripts/rollup/validate/eslintrc.esm.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ module.exports = {
4545
jest: true,
4646
},
4747
parserOptions: {
48-
ecmaVersion: 2015,
48+
ecmaVersion: 2017,
4949
sourceType: 'module',
5050
},
5151
rules: {

scripts/shared/pathsByLanguageVersion.js

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
const esNextPaths = [
1111
// Internal forwarding modules
1212
'packages/*/*.js',
13+
'packages/*/esm/*.js',
1314
// Source files
1415
'packages/*/src/**/*.js',
1516
'packages/dom-event-testing-library/**/*.js',

0 commit comments

Comments
 (0)