@samitouri / QOS-React-2 / commits / d0f396651b

Allow functions to be used as module references (#25137)

Sebastian Markbåge committed Aug 25, 2022 at 07:47 UTC d0f396651bd654a9c2058d9c779aab843651ca9a
1 file changed +54 -39
packages/react-server/src/ReactFlightServer.js
+54 -39
@@ -195,6 +195,10 @@ function attemptResolveElement(
195 );
196 }
197 if (typeof type === 'function') {
198 + if (isModuleReference(type)) {
199 + // This is a reference to a client component.
200 + return [REACT_ELEMENT_TYPE, type, key, props];
201 + }
202 // This is a server-side component.
203 return type(props);
204 } else if (typeof type === 'string') {
@@ -295,6 +299,52 @@ function serializeByRefID(id: number): string {
299 return '@' + id.toString(16);
300 }
301
302 +function serializeModuleReference(
303 + request: Request,
304 + parent: {+[key: string | number]: ReactModel} | $ReadOnlyArray<ReactModel>,
305 + key: string,
306 + moduleReference: ModuleReference<any>,
307 +): string {
308 + const moduleKey: ModuleKey = getModuleKey(moduleReference);
309 + const writtenModules = request.writtenModules;
310 + const existingId = writtenModules.get(moduleKey);
311 + if (existingId !== undefined) {
312 + if (parent[0] === REACT_ELEMENT_TYPE && key === '1') {
313 + // If we're encoding the "type" of an element, we can refer
314 + // to that by a lazy reference instead of directly since React
315 + // knows how to deal with lazy values. This lets us suspend
316 + // on this component rather than its parent until the code has
317 + // loaded.
318 + return serializeByRefID(existingId);
319 + }
320 + return serializeByValueID(existingId);
321 + }
322 + try {
323 + const moduleMetaData: ModuleMetaData = resolveModuleMetaData(
324 + request.bundlerConfig,
325 + moduleReference,
326 + );
327 + request.pendingChunks++;
328 + const moduleId = request.nextChunkId++;
329 + emitModuleChunk(request, moduleId, moduleMetaData);
330 + writtenModules.set(moduleKey, moduleId);
331 + if (parent[0] === REACT_ELEMENT_TYPE && key === '1') {
332 + // If we're encoding the "type" of an element, we can refer
333 + // to that by a lazy reference instead of directly since React
334 + // knows how to deal with lazy values. This lets us suspend
335 + // on this component rather than its parent until the code has
336 + // loaded.
337 + return serializeByRefID(moduleId);
338 + }
339 + return serializeByValueID(moduleId);
340 + } catch (x) {
341 + request.pendingChunks++;
342 + const errorId = request.nextChunkId++;
343 + emitErrorChunk(request, errorId, x);
344 + return serializeByValueID(errorId);
345 + }
346 +}
347 +
348 function escapeStringValue(value: string): string {
349 if (value[0] === '$' || value[0] === '@') {
350 // We need to escape $ or @ prefixed strings since we use those to encode
@@ -561,45 +611,7 @@ export function resolveModelToJSON(
611
612 if (typeof value === 'object') {
613 if (isModuleReference(value)) {
564 - const moduleReference: ModuleReference<any> = (value: any);
565 - const moduleKey: ModuleKey = getModuleKey(moduleReference);
566 - const writtenModules = request.writtenModules;
567 - const existingId = writtenModules.get(moduleKey);
568 - if (existingId !== undefined) {
569 - if (parent[0] === REACT_ELEMENT_TYPE && key === '1') {
570 - // If we're encoding the "type" of an element, we can refer
571 - // to that by a lazy reference instead of directly since React
572 - // knows how to deal with lazy values. This lets us suspend
573 - // on this component rather than its parent until the code has
574 - // loaded.
575 - return serializeByRefID(existingId);
576 - }
577 - return serializeByValueID(existingId);
578 - }
579 - try {
580 - const moduleMetaData: ModuleMetaData = resolveModuleMetaData(
581 - request.bundlerConfig,
582 - moduleReference,
583 - );
584 - request.pendingChunks++;
585 - const moduleId = request.nextChunkId++;
586 - emitModuleChunk(request, moduleId, moduleMetaData);
587 - writtenModules.set(moduleKey, moduleId);
588 - if (parent[0] === REACT_ELEMENT_TYPE && key === '1') {
589 - // If we're encoding the "type" of an element, we can refer
590 - // to that by a lazy reference instead of directly since React
591 - // knows how to deal with lazy values. This lets us suspend
592 - // on this component rather than its parent until the code has
593 - // loaded.
594 - return serializeByRefID(moduleId);
595 - }
596 - return serializeByValueID(moduleId);
597 - } catch (x) {
598 - request.pendingChunks++;
599 - const errorId = request.nextChunkId++;
600 - emitErrorChunk(request, errorId, x);
601 - return serializeByValueID(errorId);
602 - }
614 + return serializeModuleReference(request, parent, key, (value: any));
615 } else if ((value: any).$$typeof === REACT_PROVIDER_TYPE) {
616 const providerKey = ((value: any): ReactProviderType<any>)._context
617 ._globalName;
@@ -673,6 +685,9 @@ export function resolveModelToJSON(
685 }
686
687 if (typeof value === 'function') {
688 + if (isModuleReference(value)) {
689 + return serializeModuleReference(request, parent, key, (value: any));
690 + }
691 if (/^on[A-Z]/.test(key)) {
692 throw new Error(
693 'Event handlers cannot be passed to client component props. ' +