@@ -92,7 +92,11 @@ export function registerServerReference<T>(
92
92
const PROMISE_PROTOTYPE = Promise.prototype;
93
93
94
94
const deepProxyHandlers = {
95
- get : function ( target : Function , name : string , receiver : Proxy < Function > ) {
95
+ get : function (
96
+ target : Function ,
97
+ name : string | symbol ,
98
+ receiver : Proxy < Function > ,
99
+ ) {
96
100
switch ( name ) {
97
101
// These names are read by the Flight runtime if you end up using the exports object.
98
102
case '$$typeof' :
@@ -117,6 +121,9 @@ const deepProxyHandlers = {
117
121
case Symbol . toPrimitive :
118
122
// $FlowFixMe[prop-missing]
119
123
return Object . prototype [ Symbol . toPrimitive ] ;
124
+ case Symbol . toStringTag :
125
+ // $FlowFixMe[prop-missing]
126
+ return Object . prototype [ Symbol . toStringTag ] ;
120
127
case 'Provider' :
121
128
throw new Error (
122
129
`Cannot render a Client Context Provider on the Server. ` +
@@ -137,105 +144,134 @@ const deepProxyHandlers = {
137
144
} ,
138
145
} ;
139
146
140
- const proxyHandlers = {
141
- get : function (
142
- target : Function ,
143
- name : string ,
144
- receiver : Proxy < Function > ,
145
- ) : $FlowFixMe {
146
- switch ( name ) {
147
- // These names are read by the Flight runtime if you end up using the exports object.
148
- case '$$typeof' :
149
- return target . $$typeof ;
150
- case '$$id' :
151
- return target . $$id ;
152
- case '$$async' :
153
- return target . $$async ;
154
- case 'name' :
155
- return target . name ;
156
- // We need to special case this because createElement reads it if we pass this
157
- // reference.
158
- case 'defaultProps' :
159
- return undefined ;
160
- // Avoid this attempting to be serialized.
161
- case 'toJSON' :
162
- return undefined ;
163
- case Symbol . toPrimitive :
164
- // $FlowFixMe[prop-missing]
165
- return Object . prototype [ Symbol . toPrimitive ] ;
166
- case '__esModule' :
167
- // Something is conditionally checking which export to use. We'll pretend to be
168
- // an ESM compat module but then we'll check again on the client.
169
- const moduleId = target . $$id ;
170
- target . default = registerClientReferenceImpl (
171
- ( function ( ) {
172
- throw new Error (
173
- `Attempted to call the default export of ${ moduleId } from the server ` +
174
- `but it's on the client. It's not possible to invoke a client function from ` +
175
- `the server, it can only be rendered as a Component or passed to props of a ` +
176
- `Client Component.` ,
177
- ) ;
178
- } : any ) ,
179
- target . $$id + '#' ,
180
- target . $$async ,
181
- ) ;
182
- return true ;
183
- case 'then' :
184
- if ( target . then ) {
185
- // Use a cached value
186
- return target . then ;
187
- }
188
- if ( ! target . $$async ) {
189
- // If this module is expected to return a Promise (such as an AsyncModule) then
190
- // we should resolve that with a client reference that unwraps the Promise on
191
- // the client.
192
-
193
- const clientReference : ClientReference < any > =
194
- registerClientReferenceImpl(({ } : any), target.$$id, true);
195
- const proxy = new Proxy(clientReference, proxyHandlers);
196
-
197
- // Treat this as a resolved Promise for React's use()
198
- target.status = 'fulfilled';
199
- target.value = proxy;
200
-
201
- const then = (target.then = registerClientReferenceImpl(
202
- (function then(resolve, reject: any) {
203
- // Expose to React.
204
- return Promise . resolve ( resolve ( proxy ) ) ;
205
- } : any),
206
- // If this is not used as a Promise but is treated as a reference to a `.then`
207
- // export then we should treat it as a reference to that name.
208
- target.$$id + '#then',
209
- false,
210
- ));
211
- return then;
212
- } else {
213
- // Since typeof .then === 'function' is a feature test we'd continue recursing
214
- // indefinitely if we return a function. Instead, we return an object reference
215
- // if we check further.
216
- return undefined ;
217
- }
218
- }
219
- let cachedReference = target [ name ] ;
220
- if ( ! cachedReference ) {
221
- const reference : ClientReference < any > = registerClientReferenceImpl (
147
+ function getReference ( target : Function , name : string | symbol ) : $FlowFixMe {
148
+ switch ( name ) {
149
+ // These names are read by the Flight runtime if you end up using the exports object.
150
+ case '$$typeof' :
151
+ return target . $$typeof ;
152
+ case '$$id' :
153
+ return target . $$id ;
154
+ case '$$async' :
155
+ return target . $$async ;
156
+ case 'name' :
157
+ return target . name ;
158
+ // We need to special case this because createElement reads it if we pass this
159
+ // reference.
160
+ case 'defaultProps' :
161
+ return undefined ;
162
+ // Avoid this attempting to be serialized.
163
+ case 'toJSON' :
164
+ return undefined ;
165
+ case Symbol . toPrimitive :
166
+ // $FlowFixMe[prop-missing]
167
+ return Object . prototype [ Symbol . toPrimitive ] ;
168
+ case Symbol . toStringTag :
169
+ // $FlowFixMe[prop-missing]
170
+ return Object . prototype [ Symbol . toStringTag ] ;
171
+ case '__esModule' :
172
+ // Something is conditionally checking which export to use. We'll pretend to be
173
+ // an ESM compat module but then we'll check again on the client.
174
+ const moduleId = target . $$id ;
175
+ target . default = registerClientReferenceImpl (
222
176
( function ( ) {
223
177
throw new Error (
224
- // eslint-disable-next-line react-internal/safe-string-coercion
225
- `Attempted to call ${ String ( name ) } () from the server but ${ String (
226
- name ,
227
- ) } is on the client. ` +
228
- `It's not possible to invoke a client function from the server, it can ` +
229
- `only be rendered as a Component or passed to props of a Client Component.` ,
178
+ `Attempted to call the default export of ${ moduleId } from the server ` +
179
+ `but it's on the client. It's not possible to invoke a client function from ` +
180
+ `the server, it can only be rendered as a Component or passed to props of a ` +
181
+ `Client Component.` ,
230
182
) ;
231
183
} : any ) ,
232
- target . $$id + '#' + name ,
184
+ target . $$id + '#' ,
233
185
target . $$async ,
234
186
) ;
235
- Object . defineProperty ( ( reference : any ) , 'name' , { value : name } ) ;
236
- cachedReference = target [ name ] = new Proxy ( reference , deepProxyHandlers ) ;
187
+ return true ;
188
+ case 'then ':
189
+ if ( target . then ) {
190
+ // Use a cached value
191
+ return target . then ;
192
+ }
193
+ if (!target.$$async) {
194
+ // If this module is expected to return a Promise (such as an AsyncModule) then
195
+ // we should resolve that with a client reference that unwraps the Promise on
196
+ // the client.
197
+
198
+ const clientReference : ClientReference < any > =
199
+ registerClientReferenceImpl ( ( { } : any ) , target . $$id , true ) ;
200
+ const proxy = new Proxy ( clientReference , proxyHandlers ) ;
201
+
202
+ // Treat this as a resolved Promise for React's use()
203
+ target . status = 'fulfilled' ;
204
+ target . value = proxy ;
205
+
206
+ const then = ( target . then = registerClientReferenceImpl (
207
+ ( function then ( resolve , reject : any ) {
208
+ // Expose to React.
209
+ return Promise . resolve ( resolve ( proxy ) ) ;
210
+ } : any ) ,
211
+ // If this is not used as a Promise but is treated as a reference to a `.then`
212
+ // export then we should treat it as a reference to that name.
213
+ target . $$id + '#then' ,
214
+ false ,
215
+ ) ) ;
216
+ return then ;
217
+ } else {
218
+ // Since typeof .then === 'function' is a feature test we'd continue recursing
219
+ // indefinitely if we return a function. Instead, we return an object reference
220
+ // if we check further.
221
+ return undefined ;
222
+ }
223
+ }
224
+ if ( typeof name === 'symbol ') {
225
+ throw new Error (
226
+ 'Cannot read Symbol exports. Only named exports are supported on a client module ' +
227
+ 'imported on the server.' ,
228
+ ) ;
229
+ }
230
+ let cachedReference = target[name];
231
+ if (!cachedReference) {
232
+ const reference : ClientReference < any > = registerClientReferenceImpl (
233
+ ( function ( ) {
234
+ throw new Error (
235
+ // eslint-disable-next-line react-internal/safe-string-coercion
236
+ `Attempted to call ${ String ( name ) } () from the server but ${ String (
237
+ name ,
238
+ ) } is on the client. ` +
239
+ `It's not possible to invoke a client function from the server, it can ` +
240
+ `only be rendered as a Component or passed to props of a Client Component.` ,
241
+ ) ;
242
+ } : any ) ,
243
+ target . $$id + '#' + name ,
244
+ target . $$async ,
245
+ ) ;
246
+ Object . defineProperty ( ( reference : any ) , 'name' , { value : name } ) ;
247
+ cachedReference = target [ name ] = new Proxy ( reference , deepProxyHandlers ) ;
248
+ }
249
+ return cachedReference;
250
+ }
251
+
252
+ const proxyHandlers = {
253
+ get : function (
254
+ target : Function ,
255
+ name : string | symbol ,
256
+ receiver : Proxy < Function > ,
257
+ ) : $FlowFixMe {
258
+ return getReference ( target , name ) ;
259
+ } ,
260
+ getOwnPropertyDescriptor : function (
261
+ target : Function ,
262
+ name : string | symbol ,
263
+ ) : $FlowFixMe {
264
+ let descriptor = Object . getOwnPropertyDescriptor ( target , name ) ;
265
+ if ( ! descriptor ) {
266
+ descriptor = {
267
+ value : getReference ( target , name ) ,
268
+ writable : false ,
269
+ configurable : false ,
270
+ enumerable : false ,
271
+ } ;
272
+ Object . defineProperty ( target , name , descriptor ) ;
237
273
}
238
- return cachedReference ;
274
+ return descriptor ;
239
275
} ,
240
276
getPrototypeOf ( target : Function ) : Object {
241
277
// Pretend to be a Promise in case anyone asks.
0 commit comments