Skip to content

Commit aa9988e

Browse files
authored
Server render fork for react-dom (#25436)
Publish an aliasable entry for `react-dom` top level package exports for use in server environments. This is a stub containing only the exports that we expect to retain in the top level once 19 is released
1 parent 513417d commit aa9988e

10 files changed

+169
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
'use strict';
2+
3+
if (process.env.NODE_ENV === 'production') {
4+
module.exports = require('./cjs/react-dom-server-rendering-stub.production.min.js');
5+
} else {
6+
module.exports = require('./cjs/react-dom-server-rendering-stub.development.js');
7+
}

packages/react-dom/package.json

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"static.js",
3636
"static.browser.js",
3737
"static.node.js",
38+
"server-rendering-stub.js",
3839
"test-utils.js",
3940
"unstable_testing.js",
4041
"cjs/",
@@ -59,6 +60,7 @@
5960
},
6061
"./static.browser": "./static.browser.js",
6162
"./static.node": "./static.node.js",
63+
"./server-rendering-stub": "./server-rendering-stub.js",
6264
"./profiling": "./profiling.js",
6365
"./test-utils": "./test-utils.js",
6466
"./unstable_testing": "./unstable_testing.js",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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 all exports so that they're available in tests.
11+
// We can't use export * from in Flow for some reason.
12+
13+
import ReactVersion from 'shared/ReactVersion';
14+
export {ReactVersion as version};
15+
16+
export {default as __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED} from './src/ReactDOMSharedInternals';
17+
18+
export {
19+
createPortal,
20+
flushSync,
21+
} from './src/server/ReactDOMServerRenderingStub';
22+
export {preinit, preload} from 'react-dom-bindings/src/shared/ReactDOMFloat';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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 all exports so that they're available in tests.
11+
// We can't use export * from in Flow for some reason.
12+
13+
import ReactVersion from 'shared/ReactVersion';
14+
export {ReactVersion as version};
15+
16+
export {default as __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED} from './src/ReactDOMSharedInternals';
17+
18+
export {
19+
createPortal,
20+
flushSync,
21+
} from './src/server/ReactDOMServerRenderingStub';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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+
* @emails react-core
8+
*/
9+
10+
'use strict';
11+
12+
let React;
13+
let ReactDOM;
14+
let ReactDOMFizzServer;
15+
16+
describe('react-dom-server-rendering-stub', () => {
17+
beforeEach(() => {
18+
jest.mock('react-dom', () => require('react-dom/server-rendering-stub'));
19+
20+
React = require('react');
21+
ReactDOM = require('react-dom');
22+
ReactDOMFizzServer = require('react-dom/server');
23+
});
24+
25+
it('exports a version', () => {
26+
expect(ReactDOM.version).toBeTruthy();
27+
});
28+
29+
it('exports that are expected to be client only in the future are not exported', () => {
30+
expect(ReactDOM.createRoot).toBe(undefined);
31+
expect(ReactDOM.hydrateRoot).toBe(undefined);
32+
expect(ReactDOM.findDOMNode).toBe(undefined);
33+
expect(ReactDOM.hydrate).toBe(undefined);
34+
expect(ReactDOM.render).toBe(undefined);
35+
expect(ReactDOM.unmountComponentAtNode).toBe(undefined);
36+
expect(ReactDOM.unstable_batchedUpdates).toBe(undefined);
37+
expect(ReactDOM.unstable_createEventHandle).toBe(undefined);
38+
expect(ReactDOM.unstable_flushControlled).toBe(undefined);
39+
expect(ReactDOM.unstable_isNewReconciler).toBe(undefined);
40+
expect(ReactDOM.unstable_renderSubtreeIntoContainer).toBe(undefined);
41+
expect(ReactDOM.unstable_runWithPriority).toBe(undefined);
42+
});
43+
44+
// @gate enableFloat
45+
it('provides preload and preinit exports', async () => {
46+
function App() {
47+
ReactDOM.preload('foo', {as: 'style'});
48+
ReactDOM.preinit('bar', {as: 'style'});
49+
return <div>foo</div>;
50+
}
51+
const html = ReactDOMFizzServer.renderToString(<App />);
52+
expect(html).toEqual(
53+
'<link href="foo" rel="preload" as="style"/><link rel="stylesheet" href="bar" data-rprec="default"/><div>foo</div>',
54+
);
55+
});
56+
57+
it('provides a stub for createPortal', async () => {
58+
expect(() => {
59+
ReactDOM.createPortal();
60+
}).toThrow(
61+
'createPortal was called on the server. Portals are not currently supported on the server. Update your program to conditionally call createPortal on the client only.',
62+
);
63+
});
64+
65+
it('provides a stub for flushSync', async () => {
66+
let x = false;
67+
expect(() => {
68+
ReactDOM.flushSync(() => (x = true));
69+
}).toThrow(
70+
'flushSync was called on the server. This is likely caused by a function being called during render or in module scope that was intended to be called from an effect or event handler. Update your to not call flushSync no the server.',
71+
);
72+
expect(x).toBe(false);
73+
});
74+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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 function createPortal() {
11+
throw new Error(
12+
'createPortal was called on the server. Portals are not currently' +
13+
' supported on the server. Update your program to conditionally call' +
14+
' createPortal on the client only.',
15+
);
16+
}
17+
18+
export function flushSync() {
19+
throw new Error(
20+
'flushSync was called on the server. This is likely caused by a' +
21+
' function being called during render or in module scope that was' +
22+
' intended to be called from an effect or event handler. Update your' +
23+
' to not call flushSync no the server.',
24+
);
25+
}

scripts/error-codes/codes.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -432,5 +432,7 @@
432432
"444": "getResource encountered a resource type it did not expect: \"%s\". this is a bug in React.",
433433
"445": "\"currentResources\" was expected to exist. This is a bug in React.",
434434
"446": "\"resourceRoot\" was expected to exist. This is a bug in React.",
435-
"447": "While attempting to insert a Resource, React expected the Document to contain a head element but it was not found."
435+
"447": "While attempting to insert a Resource, React expected the Document to contain a head element but it was not found.",
436+
"448": "createPortal was called on the server. Portals are not currently supported on the server. Update your program to conditionally call createPortal on the client only.",
437+
"449": "flushSync was called on the server. This is likely caused by a function being called during render or in module scope that was intended to be called from an effect or event handler. Update your to not call flushSync no the server."
436438
}

scripts/rollup/bundles.js

+12
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,18 @@ const bundles = [
351351
externals: ['react', 'util', 'stream', 'react-dom'],
352352
},
353353

354+
/******* React DOM Server Render Stub *******/
355+
{
356+
bundleTypes: [NODE_DEV, NODE_PROD, UMD_DEV, UMD_PROD],
357+
moduleType: RENDERER,
358+
entry: 'react-dom/server-rendering-stub',
359+
name: 'react-dom-server-rendering-stub',
360+
global: 'ReactDOMServerRenderingStub',
361+
minifyWithProdErrorCodes: true,
362+
wrapWithModuleBoundaries: false,
363+
externals: ['react'],
364+
},
365+
354366
/******* React Server DOM Webpack Writer *******/
355367
{
356368
bundleTypes: [NODE_DEV, NODE_PROD, UMD_DEV, UMD_PROD],

scripts/rollup/forks.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ const forks = Object.freeze({
7474
entry,
7575
dependencies
7676
) => {
77-
if (entry === 'react-dom') {
77+
if (entry === 'react-dom' || entry === 'react-dom/server-rendering-stub') {
7878
return './packages/react-dom/src/ReactDOMSharedInternals.js';
7979
}
8080
if (

scripts/shared/inlinedHostConfigs.js

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ module.exports = [
1414
'react-dom/unstable_testing',
1515
'react-dom/src/server/ReactDOMFizzServerNode.js',
1616
'react-dom/static.node',
17+
'react-dom/server-rendering-stub',
1718
'react-server-dom-webpack/writer.node.server',
1819
'react-server-dom-webpack',
1920
],
@@ -49,6 +50,7 @@ module.exports = [
4950
'react-dom/unstable_testing',
5051
'react-dom/src/server/ReactDOMFizzServerBrowser.js',
5152
'react-dom/static.browser',
53+
'react-dom/server-rendering-stub',
5254
'react-server-dom-webpack/writer.browser.server',
5355
'react-server-dom-webpack',
5456
],

0 commit comments

Comments
 (0)