Skip to content

Commit bf0c510

Browse files
committed
ESM implementation of module preinitialization
1 parent bee5c3e commit bf0c510

18 files changed

+140
-43
lines changed

fixtures/flight-esm/.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
v18

fixtures/flight-esm/server/global.js

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const compress = require('compression');
1010
const chalk = require('chalk');
1111
const express = require('express');
1212
const http = require('http');
13+
const React = require('react');
1314

1415
const {renderToPipeableStream} = require('react-dom/server');
1516
const {createFromNodeStream} = require('react-server-dom-esm/client');
@@ -62,23 +63,39 @@ app.all('/', async function (req, res, next) {
6263
if (req.accepts('text/html')) {
6364
try {
6465
const rscResponse = await promiseForData;
65-
6666
const moduleBaseURL = '/src';
6767

6868
// For HTML, we're a "client" emulator that runs the client code,
6969
// so we start by consuming the RSC payload. This needs the local file path
7070
// to load the source files from as well as the URL path for preloads.
71-
const root = await createFromNodeStream(
72-
rscResponse,
73-
moduleBasePath,
74-
moduleBaseURL
75-
);
71+
72+
let root;
73+
let Root = () => {
74+
if (root) {
75+
return React.use(root);
76+
}
77+
78+
return React.use(
79+
(root = createFromNodeStream(
80+
rscResponse,
81+
moduleBasePath,
82+
moduleBaseURL
83+
))
84+
);
85+
};
7686
// Render it into HTML by resolving the client components
7787
res.set('Content-type', 'text/html');
78-
const {pipe} = renderToPipeableStream(root, {
79-
// TODO: bootstrapModules inserts a preload before the importmap which causes
80-
// the import map to be invalid. We need to fix that in Float somehow.
81-
// bootstrapModules: ['/src/index.js'],
88+
const {pipe} = renderToPipeableStream(React.createElement(Root), {
89+
importMap: {
90+
imports: {
91+
react: 'https://esm.sh/react@experimental?pin=v124&dev',
92+
'react-dom': 'https://esm.sh/react-dom@experimental?pin=v124&dev',
93+
'react-dom/': 'https://esm.sh/react-dom@experimental&pin=v124&dev/',
94+
'react-server-dom-esm/client':
95+
'/node_modules/react-server-dom-esm/esm/react-server-dom-esm-client.browser.development.js',
96+
},
97+
},
98+
bootstrapModules: ['/src/index.js'],
8299
});
83100
pipe(res);
84101
} catch (e) {
@@ -89,6 +106,7 @@ app.all('/', async function (req, res, next) {
89106
} else {
90107
try {
91108
const rscResponse = await promiseForData;
109+
92110
// For other request, we pass-through the RSC payload.
93111
res.set('Content-type', 'text/x-component');
94112
rscResponse.on('data', data => {

fixtures/flight-esm/server/region.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ async function renderApp(res, returnValue) {
3636
// For client-invoked server actions we refresh the tree and return a return value.
3737
const payload = returnValue ? {returnValue, root} : root;
3838
const {pipe} = renderToPipeableStream(payload, moduleBasePath);
39+
await new Promise(res => {
40+
setTimeout(res, 1000);
41+
});
3942
pipe(res);
4043
}
4144

fixtures/flight-esm/src/App.js

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,6 @@ import {getServerState} from './ServerState.js';
99

1010
const h = React.createElement;
1111

12-
const importMap = {
13-
imports: {
14-
react: 'https://esm.sh/react@experimental?pin=v124&dev',
15-
'react-dom': 'https://esm.sh/react-dom@experimental?pin=v124&dev',
16-
'react-dom/': 'https://esm.sh/react-dom@experimental&pin=v124&dev/',
17-
'react-server-dom-esm/client':
18-
'/node_modules/react-server-dom-esm/esm/react-server-dom-esm-client.browser.development.js',
19-
},
20-
};
21-
2212
export default async function App() {
2313
const res = await fetch('http://localhost:3001/todos');
2414
const todos = await res.json();
@@ -42,12 +32,6 @@ export default async function App() {
4232
rel: 'stylesheet',
4333
href: '/src/style.css',
4434
precedence: 'default',
45-
}),
46-
h('script', {
47-
type: 'importmap',
48-
dangerouslySetInnerHTML: {
49-
__html: JSON.stringify(importMap),
50-
},
5135
})
5236
),
5337
h(
@@ -84,9 +68,7 @@ export default async function App() {
8468
'Like'
8569
)
8670
)
87-
),
88-
// TODO: Move this to bootstrapModules.
89-
h('script', {type: 'module', src: '/src/index.js'})
71+
)
9072
)
9173
);
9274
}

fixtures/flight/server/global.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,17 @@ app.all('/', async function (req, res, next) {
147147
let root;
148148
let Root = () => {
149149
if (root) {
150-
return root;
150+
return React.use(root);
151151
}
152-
root = createFromNodeStream(rscResponse, ssrBundleConfig.ssrManifest, {
153-
moduleLoading: ssrBundleConfig.moduleLoading,
154-
});
155-
return root;
152+
return React.use(
153+
(root = createFromNodeStream(
154+
rscResponse,
155+
ssrBundleConfig.ssrManifest,
156+
{
157+
moduleLoading: ssrBundleConfig.moduleLoading,
158+
}
159+
))
160+
);
156161
};
157162
// Render it into HTML by resolving the client components
158163
res.set('Content-type', 'text/html');

fixtures/flight/server/region.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ async function renderApp(res, returnValue) {
9595
// For client-invoked server actions we refresh the tree and return a return value.
9696
const payload = returnValue ? {returnValue, root} : root;
9797
const {pipe} = renderToPipeableStream(payload, moduleMap);
98+
await new Promise(res => {
99+
setTimeout(res, 1000);
100+
});
98101
pipe(res);
99102
}
100103

packages/react-client/src/forks/ReactFlightClientConfig.custom.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
declare var $$$config: any;
2727

28+
export opaque type ModuleLoading = mixed;
2829
export opaque type SSRManifest = mixed;
2930
export opaque type ServerManifest = mixed;
3031
export opaque type ServerReferenceId = string;

packages/react-client/src/forks/ReactFlightClientConfig.dom-browser-esm.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99

1010
export * from 'react-client/src/ReactFlightClientConfigBrowser';
11-
export * from 'react-server-dom-esm/src/ReactFlightClientConfigESMBundler';
11+
export * from 'react-server-dom-esm/src/ReactFlightClientConfigBundlerESM';
12+
export * from 'react-server-dom-esm/src/ReactFlightClientConfigTargetESMBrowser';
1213
export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM';
1314
export const usedWithSSR = false;

packages/react-client/src/forks/ReactFlightClientConfig.dom-node-esm.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
* @flow
88
*/
99

10-
export * from 'react-client/src/ReactFlightClientConfigBrowser';
11-
export * from 'react-server-dom-esm/src/ReactFlightClientConfigESMBundler';
10+
export * from 'react-client/src/ReactFlightClientConfigNode';
11+
export * from 'react-server-dom-esm/src/ReactFlightClientConfigBundlerESM';
12+
export * from 'react-server-dom-esm/src/ReactFlightClientConfigTargetESMServer';
1213
export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM';
1314
export const usedWithSSR = true;

packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5328,6 +5328,7 @@ function preinit(href: string, options: PreinitOptions): void {
53285328
}
53295329
return;
53305330
}
5331+
case 'module':
53315332
case 'script': {
53325333
const src = href;
53335334
const key = getResourceKey(as, src);

0 commit comments

Comments
 (0)