Skip to content

Commit

Permalink
Add Node ESM Loader and Register Entrypoints (#20274)
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
sebmarkbage committed Nov 17, 2020
1 parent bf7b7ae commit 82e99e1
Show file tree
Hide file tree
Showing 18 changed files with 181 additions and 84 deletions.
24 changes: 24 additions & 0 deletions fixtures/flight/loader/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {resolve, getSource} from 'react-transport-dom-webpack/node-loader';

export {resolve, getSource};

import babel from '@babel/core';

const babelOptions = {
babelrc: false,
ignore: [/\/(build|node_modules)\//],
plugins: [
'@babel/plugin-syntax-import-meta',
'@babel/plugin-transform-react-jsx',
],
};

export async function transformSource(source, context, defaultTransformSource) {
const {format} = context;
if (format === 'module') {
const opt = Object.assign({filename: context.url}, babelOptions);
const {code} = await babel.transformAsync(source, opt);
return {source: code};
}
return defaultTransformSource(source, context, defaultTransformSource);
}
3 changes: 3 additions & 0 deletions fixtures/flight/loader/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "module"
}
2 changes: 1 addition & 1 deletion fixtures/flight/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
"prebuild": "cp -r ../../build/node_modules/* ./node_modules/",
"start": "concurrently \"npm run start:server\" \"npm run start:client\"",
"start:client": "node scripts/start.js",
"start:server": "NODE_ENV=development node --experimental-loader ./server/loader.mjs server",
"start:server": "NODE_ENV=development node --experimental-loader ./loader/index.js server",
"start:prod": "node scripts/build.js && NODE_ENV=production node server",
"build": "node scripts/build.js",
"test": "node scripts/test.js --env=jsdom"
Expand Down
16 changes: 12 additions & 4 deletions fixtures/flight/server/handler.server.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,26 @@

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

module.exports = function(req, res) {
import url from 'url';

function resolve(path) {
return url.pathToFileURL(require.resolve(path)).href;
}

module.exports = async function(req, res) {
res.setHeader('Access-Control-Allow-Origin', '*');
const m = await import('../src/App.server.js');
// const m = require('../src/App.server.js');
const App = m.default.default || m.default;
pipeToNodeWritable(<App />, res, {
// TODO: Read from a map on the disk.
[require.resolve('../src/Counter.client.js')]: {
[resolve('../src/Counter.client.js')]: {
id: './src/Counter.client.js',
chunks: ['1'],
name: 'default',
},
[require.resolve('../src/ShowMore.client.js')]: {
[resolve('../src/ShowMore.client.js')]: {
id: './src/ShowMore.client.js',
chunks: ['2'],
name: 'default',
Expand Down
27 changes: 0 additions & 27 deletions fixtures/flight/server/handler.server.mjs

This file was deleted.

11 changes: 3 additions & 8 deletions fixtures/flight/server/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
'use strict';

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

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

Expand All @@ -25,8 +21,7 @@ app.get('/', function(req, res) {
delete require.cache[key];
}
}
import('./handler.server.mjs').then(m => m.default(req, res));
// require('./handler.server.js')(req, res);
require('./handler.server.js')(req, res);
});

app.listen(3001, () => {
Expand Down
42 changes: 0 additions & 42 deletions fixtures/flight/server/loader.mjs

This file was deleted.

3 changes: 3 additions & 0 deletions packages/react-transport-dom-webpack/esm/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "module"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* 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.
*
* @flow
*/

export * from '../src/ReactFlightWebpackNodeLoader.js';
10 changes: 10 additions & 0 deletions packages/react-transport-dom-webpack/node-register.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* 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.
*
* @flow
*/

export * from './src/ReactFlightWebpackNodeRegister';
3 changes: 3 additions & 0 deletions packages/react-transport-dom-webpack/npm/esm/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "module"
}
3 changes: 3 additions & 0 deletions packages/react-transport-dom-webpack/npm/node-register.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
'use strict';

module.exports = require('./cjs/react-transport-dom-webpack-node-register.js');
14 changes: 13 additions & 1 deletion packages/react-transport-dom-webpack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,21 @@
"server.js",
"server.browser.js",
"server.node.js",
"node-register.js",
"cjs/",
"umd/"
"umd/",
"esm/"
],
"exports": {
".": "./index.js",
"./plugin": "./plugin.js",
"./server": "./server.js",
"./server.browser": "./server.browser.js",
"./server.node": "./server.node.js",
"./node-loader": "./esm/react-transport-dom-webpack-node-loader.js",
"./node-register": "./node-register.js",
"./package.json": "./package.json"
},
"browser": {
"./server.js": "./server.browser.js"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* 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.
*
* @flow
*/

type ResolveContext = {
conditions: Array<string>,
parentURL: string | void,
};

type ResolveFunction = (
string,
ResolveContext,
ResolveFunction,
) => Promise<string>;

type GetSourceContext = {
format: string,
url: string,
};

type GetSourceFunction = (
string,
GetSourceContext,
GetSourceFunction,
) => Promise<{source: Source}>;

type Source = string | ArrayBuffer | Uint8Array;

export async function resolve(
specifier: string,
context: ResolveContext,
defaultResolve: ResolveFunction,
): Promise<string> {
// TODO: Resolve server-only files.
return defaultResolve(specifier, context, defaultResolve);
}

export async function getSource(
url: string,
context: GetSourceContext,
defaultGetSource: GetSourceFunction,
): Promise<{source: Source}> {
if (url.endsWith('.client.js')) {
// TODO: Named exports.
const src =
"export default { $$typeof: Symbol.for('react.module.reference'), name: " +
JSON.stringify(url) +
'}';
return {source: src};
}
return defaultGetSource(url, context, defaultGetSource);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* 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.
*
* @flow
*/

const url = require('url');

module.exports = function register() {
(require: any).extensions['.client.js'] = function(module, path) {
module.exports = {
$$typeof: Symbol.for('react.module.reference'),
name: url.pathToFileURL(path).href,
};
};
};
18 changes: 18 additions & 0 deletions scripts/rollup/bundles.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,24 @@ const bundles = [
externals: [],
},

/******* React Transport DOM Webpack Node.js Loader *******/
{
bundleTypes: [NODE_ESM],
moduleType: RENDERER_UTILS,
entry: 'react-transport-dom-webpack/node-loader',
global: 'ReactFlightWebpackNodeLoader',
externals: [],
},

/******* React Transport DOM Webpack Node.js CommonJS Loader *******/
{
bundleTypes: [NODE_ES2015],
moduleType: RENDERER_UTILS,
entry: 'react-transport-dom-webpack/node-register',
global: 'ReactFlightWebpackNodeRegister',
externals: ['url'],
},

/******* React Transport DOM Server Relay *******/
{
bundleTypes: [FB_WWW_DEV, FB_WWW_PROD],
Expand Down
2 changes: 1 addition & 1 deletion scripts/rollup/validate/eslintrc.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ module.exports = {
jest: true,
},
parserOptions: {
ecmaVersion: 2015,
ecmaVersion: 2017,
sourceType: 'module',
},
rules: {
Expand Down
1 change: 1 addition & 0 deletions scripts/shared/pathsByLanguageVersion.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
const esNextPaths = [
// Internal forwarding modules
'packages/*/*.js',
'packages/*/esm/*.js',
// Source files
'packages/*/src/**/*.js',
'packages/dom-event-testing-library/**/*.js',
Expand Down

0 comments on commit 82e99e1

Please sign in to comment.