diff --git a/fixtures/flight/loader/index.js b/fixtures/flight/loader/index.js new file mode 100644 index 000000000000..b9cfa5b73eee --- /dev/null +++ b/fixtures/flight/loader/index.js @@ -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); +} diff --git a/fixtures/flight/loader/package.json b/fixtures/flight/loader/package.json new file mode 100644 index 000000000000..3dbc1ca591c0 --- /dev/null +++ b/fixtures/flight/loader/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/fixtures/flight/package.json b/fixtures/flight/package.json index 92c41ebfe47a..e8e30736f3fb 100644 --- a/fixtures/flight/package.json +++ b/fixtures/flight/package.json @@ -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" diff --git a/fixtures/flight/server/handler.server.js b/fixtures/flight/server/handler.server.js index f3b899d498d7..d7715af9cc75 100644 --- a/fixtures/flight/server/handler.server.js +++ b/fixtures/flight/server/handler.server.js @@ -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(, 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', diff --git a/fixtures/flight/server/handler.server.mjs b/fixtures/flight/server/handler.server.mjs deleted file mode 100644 index 0d21c80eebfd..000000000000 --- a/fixtures/flight/server/handler.server.mjs +++ /dev/null @@ -1,27 +0,0 @@ -import {pipeToNodeWritable} from 'react-transport-dom-webpack/server.js'; -import * as React from 'react'; -import App from '../src/App.server.js'; - -import {URL} from 'url'; - -const rootPath = import.meta.url; -function resolve(relative) { - return new URL(relative, rootPath).href; -} - -export default function(req, res) { - res.setHeader('Access-Control-Allow-Origin', '*'); - pipeToNodeWritable(, res, { - // TODO: Read from a map on the disk. - [resolve('../src/Counter.client.js')]: { - id: './src/Counter.client.js', - chunks: ['1'], - name: 'default', - }, - [resolve('../src/ShowMore.client.js')]: { - id: './src/ShowMore.client.js', - chunks: ['2'], - name: 'default', - }, - }); -}; diff --git a/fixtures/flight/server/index.js b/fixtures/flight/server/index.js index ffa1a8628b8e..00dc4815b728 100644 --- a/fixtures/flight/server/index.js +++ b/fixtures/flight/server/index.js @@ -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'); @@ -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, () => { diff --git a/fixtures/flight/server/loader.mjs b/fixtures/flight/server/loader.mjs deleted file mode 100644 index f2d109ce8179..000000000000 --- a/fixtures/flight/server/loader.mjs +++ /dev/null @@ -1,42 +0,0 @@ -import babel from '@babel/core'; - -const options = { - babelrc: false, - ignore: [/\/(build|node_modules)\//], - plugins: [ - '@babel/plugin-syntax-import-meta', - '@babel/plugin-transform-react-jsx', - ], -}; - -const optionsCommonJS = { - ignore: [/\/(build|node_modules)\//], - presets: ['react-app'], - plugins: ['@babel/transform-modules-commonjs'], -}; - -export async function transformSource(source, context, defaultTransformSource) { - const {format} = context; - if (format === 'module' || format === 'commonjs') { - const opt = Object.assign( - {filename: context.url}, - format === 'commonjs' ? optionsCommonJS : options - ); - const {code} = await babel.transformAsync(source, opt); - return {source: code}; - } - return defaultTransformSource(source, context); -} - -export async function getSource(url, context, defaultGetSource) { - if (url.endsWith('.client.js')) { - const name = url; - return { - source: - "export default { $$typeof: Symbol.for('react.module.reference'), name: " + - JSON.stringify(name) + - '}', - }; - } - return defaultGetSource(url, context, defaultGetSource); -} diff --git a/packages/react-transport-dom-webpack/esm/package.json b/packages/react-transport-dom-webpack/esm/package.json new file mode 100644 index 000000000000..3dbc1ca591c0 --- /dev/null +++ b/packages/react-transport-dom-webpack/esm/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/packages/react-transport-dom-webpack/esm/react-transport-dom-webpack-node-loader.js b/packages/react-transport-dom-webpack/esm/react-transport-dom-webpack-node-loader.js new file mode 100644 index 000000000000..d7a01f6f221d --- /dev/null +++ b/packages/react-transport-dom-webpack/esm/react-transport-dom-webpack-node-loader.js @@ -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'; diff --git a/packages/react-transport-dom-webpack/node-register.js b/packages/react-transport-dom-webpack/node-register.js new file mode 100644 index 000000000000..03754438bf33 --- /dev/null +++ b/packages/react-transport-dom-webpack/node-register.js @@ -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'; diff --git a/packages/react-transport-dom-webpack/npm/esm/package.json b/packages/react-transport-dom-webpack/npm/esm/package.json new file mode 100644 index 000000000000..3dbc1ca591c0 --- /dev/null +++ b/packages/react-transport-dom-webpack/npm/esm/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/packages/react-transport-dom-webpack/npm/node-register.js b/packages/react-transport-dom-webpack/npm/node-register.js new file mode 100644 index 000000000000..87a431afe198 --- /dev/null +++ b/packages/react-transport-dom-webpack/npm/node-register.js @@ -0,0 +1,3 @@ +'use strict'; + +module.exports = require('./cjs/react-transport-dom-webpack-node-register.js'); diff --git a/packages/react-transport-dom-webpack/package.json b/packages/react-transport-dom-webpack/package.json index b362d0847afa..a71a558f5160 100644 --- a/packages/react-transport-dom-webpack/package.json +++ b/packages/react-transport-dom-webpack/package.json @@ -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" }, diff --git a/packages/react-transport-dom-webpack/src/ReactFlightWebpackNodeLoader.js b/packages/react-transport-dom-webpack/src/ReactFlightWebpackNodeLoader.js new file mode 100644 index 000000000000..f9fd2a54e24f --- /dev/null +++ b/packages/react-transport-dom-webpack/src/ReactFlightWebpackNodeLoader.js @@ -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, + parentURL: string | void, +}; + +type ResolveFunction = ( + string, + ResolveContext, + ResolveFunction, +) => Promise; + +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 { + // 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); +} diff --git a/packages/react-transport-dom-webpack/src/ReactFlightWebpackNodeRegister.js b/packages/react-transport-dom-webpack/src/ReactFlightWebpackNodeRegister.js new file mode 100644 index 000000000000..f5149be1c42c --- /dev/null +++ b/packages/react-transport-dom-webpack/src/ReactFlightWebpackNodeRegister.js @@ -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, + }; + }; +}; diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index 6a04d6aa4b06..15bbc68d364d 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -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], diff --git a/scripts/rollup/validate/eslintrc.esm.js b/scripts/rollup/validate/eslintrc.esm.js index e7f8d1ca0955..3b644b6274e4 100644 --- a/scripts/rollup/validate/eslintrc.esm.js +++ b/scripts/rollup/validate/eslintrc.esm.js @@ -45,7 +45,7 @@ module.exports = { jest: true, }, parserOptions: { - ecmaVersion: 2015, + ecmaVersion: 2017, sourceType: 'module', }, rules: { diff --git a/scripts/shared/pathsByLanguageVersion.js b/scripts/shared/pathsByLanguageVersion.js index f1b19a8893a3..af6963f78949 100644 --- a/scripts/shared/pathsByLanguageVersion.js +++ b/scripts/shared/pathsByLanguageVersion.js @@ -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',