Skip to content

Commit 2d2f2af

Browse files
authored
Restrict React DOM imports from Server Components (facebook#27382)
Adds a separate entry point for the react-dom package when it's accessed from a Server Component environment, using the "react-server" export condition. When you're inside a Server Component module, you won't be able to import client-only APIs like useState. This applies to almost all React DOM exports, except for Float ones like preload.
1 parent d6dcad6 commit 2d2f2af

File tree

6 files changed

+56
-2
lines changed

6 files changed

+56
-2
lines changed
Lines changed: 7 additions & 0 deletions
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.shared-subset.production.min.js');
5+
} else {
6+
module.exports = require('./cjs/react-dom.shared-subset.development.js');
7+
}

packages/react-dom/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@
4646
"umd/"
4747
],
4848
"exports": {
49-
".": "./index.js",
49+
".": {
50+
"react-server": "./react-dom.shared-subset.js",
51+
"default": "./index.js"
52+
},
5053
"./client": "./client.js",
5154
"./server": {
5255
"workerd": "./server.edge.js",
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and 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+
// This is the subset of APIs that can be accessed from Server Component modules
11+
export {default as __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED} from './ReactDOMSharedInternals';
12+
export {
13+
prefetchDNS,
14+
preconnect,
15+
preload,
16+
preloadModule,
17+
preinit,
18+
preinitModule,
19+
} from './shared/ReactDOMFloat';

scripts/rollup/bundles.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,18 @@ const bundles = [
165165
externals: ['react'],
166166
},
167167

168+
/******* React DOM Shared Subset *******/
169+
{
170+
bundleTypes: [NODE_DEV, NODE_PROD],
171+
moduleType: RENDERER,
172+
entry: 'react-dom/src/ReactDOMSharedSubset.js',
173+
name: 'react-dom.shared-subset',
174+
global: 'ReactDOM',
175+
minifyWithProdErrorCodes: false,
176+
wrapWithModuleBoundaries: false,
177+
externals: ['react'],
178+
},
179+
168180
/******* Test Utils *******/
169181
{
170182
moduleType: RENDERER_UTILS,

scripts/rollup/forks.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,11 @@ const forks = Object.freeze({
8484
entry,
8585
dependencies
8686
) => {
87-
if (entry === 'react-dom' || entry === 'react-dom/server-rendering-stub') {
87+
if (
88+
entry === 'react-dom' ||
89+
entry === 'react-dom/server-rendering-stub' ||
90+
entry === 'react-dom/src/ReactDOMSharedSubset.js'
91+
) {
8892
return './packages/react-dom/src/ReactDOMSharedInternals.js';
8993
}
9094
if (

scripts/shared/inlinedHostConfigs.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ module.exports = [
1111
shortName: 'dom-node',
1212
entryPoints: [
1313
'react-dom',
14+
'react-dom/src/ReactDOMSharedSubset.js',
1415
'react-dom/unstable_testing',
1516
'react-dom/src/server/react-dom-server.node.js',
1617
'react-dom/static.node',
@@ -21,6 +22,7 @@ module.exports = [
2122
],
2223
paths: [
2324
'react-dom',
25+
'react-dom/src/ReactDOMSharedSubset.js',
2426
'react-dom-bindings',
2527
'react-dom/client',
2628
'react-dom/server',
@@ -73,6 +75,7 @@ module.exports = [
7375
],
7476
paths: [
7577
'react-dom',
78+
'react-dom/src/ReactDOMSharedSubset.js',
7679
'react-dom-bindings',
7780
'react-dom/client',
7881
'react-dom/server.browser',
@@ -101,6 +104,7 @@ module.exports = [
101104
entryPoints: ['react-server-dom-esm/client.browser'],
102105
paths: [
103106
'react-dom',
107+
'react-dom/src/ReactDOMSharedSubset.js',
104108
'react-dom/client',
105109
'react-dom/server',
106110
'react-dom/server.node',
@@ -128,6 +132,7 @@ module.exports = [
128132
],
129133
paths: [
130134
'react-dom',
135+
'react-dom/src/ReactDOMSharedSubset.js',
131136
'react-dom-bindings',
132137
'react-dom/client',
133138
'react-dom/server.edge',
@@ -158,6 +163,7 @@ module.exports = [
158163
],
159164
paths: [
160165
'react-dom',
166+
'react-dom/src/ReactDOMSharedSubset.js',
161167
'react-dom-bindings',
162168
'react-dom/client',
163169
'react-dom/server',
@@ -192,6 +198,7 @@ module.exports = [
192198
],
193199
paths: [
194200
'react-dom',
201+
'react-dom/src/ReactDOMSharedSubset.js',
195202
'react-dom-bindings',
196203
'react-dom/client',
197204
'react-dom/server',
@@ -224,6 +231,7 @@ module.exports = [
224231
],
225232
paths: [
226233
'react-dom',
234+
'react-dom/src/ReactDOMSharedSubset.js',
227235
'react-dom-bindings',
228236
'react-server-dom-webpack',
229237
'react-dom/src/server/ReactDOMLegacyServerImpl.js', // not an entrypoint, but only usable in *Brower and *Node files
@@ -241,6 +249,7 @@ module.exports = [
241249
entryPoints: ['react-server-dom-fb/src/ReactDOMServerFB.js'],
242250
paths: [
243251
'react-dom',
252+
'react-dom/src/ReactDOMSharedSubset.js',
244253
'react-dom-bindings',
245254
'react-server-dom-fb',
246255
'shared/ReactDOMSharedInternals',

0 commit comments

Comments
 (0)