react-server-dom-webpack 18.3.0-canary-14898b6a9-20240318 → 18.3.0-canary-4b84f1161-20240318

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/cjs/react-server-dom-webpack-client.browser.development.js +91 -189
  2. package/cjs/react-server-dom-webpack-client.browser.production.js +60 -43
  3. package/cjs/react-server-dom-webpack-client.browser.production.min.js +24 -23
  4. package/cjs/react-server-dom-webpack-client.browser.production.min.js.map +1 -1
  5. package/cjs/react-server-dom-webpack-client.edge.development.js +96 -241
  6. package/cjs/react-server-dom-webpack-client.edge.production.js +65 -84
  7. package/cjs/react-server-dom-webpack-client.edge.production.min.js +29 -29
  8. package/cjs/react-server-dom-webpack-client.edge.production.min.js.map +1 -1
  9. package/cjs/react-server-dom-webpack-client.node.development.js +96 -241
  10. package/cjs/react-server-dom-webpack-client.node.production.js +65 -84
  11. package/cjs/react-server-dom-webpack-client.node.production.min.js +29 -28
  12. package/cjs/react-server-dom-webpack-client.node.production.min.js.map +1 -1
  13. package/cjs/react-server-dom-webpack-client.node.unbundled.development.js +96 -241
  14. package/cjs/react-server-dom-webpack-client.node.unbundled.production.js +65 -84
  15. package/cjs/react-server-dom-webpack-client.node.unbundled.production.min.js +30 -30
  16. package/cjs/react-server-dom-webpack-client.node.unbundled.production.min.js.map +1 -1
  17. package/cjs/react-server-dom-webpack-node-register.js.map +1 -1
  18. package/cjs/react-server-dom-webpack-plugin.js.map +1 -1
  19. package/cjs/react-server-dom-webpack-server.browser.development.js +406 -550
  20. package/cjs/react-server-dom-webpack-server.browser.production.js +351 -373
  21. package/cjs/react-server-dom-webpack-server.browser.production.min.js +68 -65
  22. package/cjs/react-server-dom-webpack-server.browser.production.min.js.map +1 -1
  23. package/cjs/react-server-dom-webpack-server.edge.development.js +406 -553
  24. package/cjs/react-server-dom-webpack-server.edge.production.js +350 -375
  25. package/cjs/react-server-dom-webpack-server.edge.production.min.js +69 -66
  26. package/cjs/react-server-dom-webpack-server.edge.production.min.js.map +1 -1
  27. package/cjs/react-server-dom-webpack-server.node.development.js +406 -550
  28. package/cjs/react-server-dom-webpack-server.node.production.js +350 -372
  29. package/cjs/react-server-dom-webpack-server.node.production.min.js +72 -70
  30. package/cjs/react-server-dom-webpack-server.node.production.min.js.map +1 -1
  31. package/cjs/react-server-dom-webpack-server.node.unbundled.development.js +406 -550
  32. package/cjs/react-server-dom-webpack-server.node.unbundled.production.js +350 -372
  33. package/cjs/react-server-dom-webpack-server.node.unbundled.production.min.js +69 -67
  34. package/cjs/react-server-dom-webpack-server.node.unbundled.production.min.js.map +1 -1
  35. package/package.json +3 -3
  36. package/umd/react-server-dom-webpack-client.browser.development.js +91 -189
  37. package/umd/react-server-dom-webpack-client.browser.production.min.js +23 -22
  38. package/umd/react-server-dom-webpack-server.browser.development.js +406 -550
  39. package/umd/react-server-dom-webpack-server.browser.production.min.js +52 -52
@@ -176,10 +176,10 @@ function closeWithError(destination, error) {
176
176
  }
177
177
 
178
178
  // eslint-disable-next-line no-unused-vars
179
- const CLIENT_REFERENCE_TAG$1 = Symbol.for('react.client.reference');
179
+ const CLIENT_REFERENCE_TAG = Symbol.for('react.client.reference');
180
180
  const SERVER_REFERENCE_TAG = Symbol.for('react.server.reference');
181
181
  function isClientReference(reference) {
182
- return reference.$$typeof === CLIENT_REFERENCE_TAG$1;
182
+ return reference.$$typeof === CLIENT_REFERENCE_TAG;
183
183
  }
184
184
  function isServerReference(reference) {
185
185
  return reference.$$typeof === SERVER_REFERENCE_TAG;
@@ -191,7 +191,7 @@ function registerClientReference(proxyImplementation, id, exportName) {
191
191
  function registerClientReferenceImpl(proxyImplementation, id, async) {
192
192
  return Object.defineProperties(proxyImplementation, {
193
193
  $$typeof: {
194
- value: CLIENT_REFERENCE_TAG$1
194
+ value: CLIENT_REFERENCE_TAG
195
195
  },
196
196
  $$id: {
197
197
  value: id
@@ -212,7 +212,6 @@ function bind() {
212
212
  const newFn = FunctionBind.apply(this, arguments);
213
213
 
214
214
  if (this.$$typeof === SERVER_REFERENCE_TAG) {
215
-
216
215
  const args = ArraySlice.call(arguments, 1);
217
216
  return Object.defineProperties(newFn, {
218
217
  $$typeof: {
@@ -239,16 +238,13 @@ function registerServerReference(reference, id, exportName) {
239
238
  value: SERVER_REFERENCE_TAG
240
239
  },
241
240
  $$id: {
242
- value: exportName === null ? id : id + '#' + exportName,
243
- configurable: true
241
+ value: exportName === null ? id : id + '#' + exportName
244
242
  },
245
243
  $$bound: {
246
- value: null,
247
- configurable: true
244
+ value: null
248
245
  },
249
246
  bind: {
250
- value: bind,
251
- configurable: true
247
+ value: bind
252
248
  }
253
249
  });
254
250
  }
@@ -287,10 +283,6 @@ const deepProxyHandlers = {
287
283
  // $FlowFixMe[prop-missing]
288
284
  return Object.prototype[Symbol.toPrimitive];
289
285
 
290
- case Symbol.toStringTag:
291
- // $FlowFixMe[prop-missing]
292
- return Object.prototype[Symbol.toStringTag];
293
-
294
286
  case 'Provider':
295
287
  throw new Error("Cannot render a Client Context Provider on the Server. " + "Instead, you can export a Client Component wrapper " + "that itself renders a Client Context Provider.");
296
288
  } // eslint-disable-next-line react-internal/safe-string-coercion
@@ -332,10 +324,6 @@ function getReference(target, name) {
332
324
  // $FlowFixMe[prop-missing]
333
325
  return Object.prototype[Symbol.toPrimitive];
334
326
 
335
- case Symbol.toStringTag:
336
- // $FlowFixMe[prop-missing]
337
- return Object.prototype[Symbol.toStringTag];
338
-
339
327
  case '__esModule':
340
328
  // Something is conditionally checking which export to use. We'll pretend to be
341
329
  // an ESM compat module but then we'll check again on the client.
@@ -376,10 +364,6 @@ function getReference(target, name) {
376
364
 
377
365
  }
378
366
 
379
- if (typeof name === 'symbol') {
380
- throw new Error('Cannot read Symbol exports. Only named exports are supported on a client module ' + 'imported on the server.');
381
- }
382
-
383
367
  let cachedReference = target[name];
384
368
 
385
369
  if (!cachedReference) {
@@ -723,7 +707,6 @@ function createHints() {
723
707
  return new Set();
724
708
  }
725
709
 
726
- const supportsRequestStorage = true;
727
710
  const requestStorage = new async_hooks.AsyncLocalStorage();
728
711
 
729
712
  // ATTENTION
@@ -732,7 +715,7 @@ const requestStorage = new async_hooks.AsyncLocalStorage();
732
715
  // The Symbol used to tag the ReactElement-like types.
733
716
  const REACT_ELEMENT_TYPE = Symbol.for('react.element');
734
717
  const REACT_FRAGMENT_TYPE = Symbol.for('react.fragment');
735
- const REACT_CONTEXT_TYPE = Symbol.for('react.context');
718
+ const REACT_SERVER_CONTEXT_TYPE = Symbol.for('react.server_context');
736
719
  const REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref');
737
720
  const REACT_SUSPENSE_TYPE = Symbol.for('react.suspense');
738
721
  const REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list');
@@ -756,6 +739,146 @@ function getIteratorFn(maybeIterable) {
756
739
  return null;
757
740
  }
758
741
 
742
+ // Forming a reverse tree.
743
+ // The structure of a context snapshot is an implementation of this file.
744
+ // Currently, it's implemented as tracking the current active node.
745
+
746
+
747
+ const rootContextSnapshot = null; // We assume that this runtime owns the "current" field on all ReactContext instances.
748
+ // This global (actually thread local) state represents what state all those "current",
749
+ // fields are currently in.
750
+
751
+ let currentActiveSnapshot = null;
752
+
753
+ function popNode(prev) {
754
+ {
755
+ prev.context._currentValue = prev.parentValue;
756
+ }
757
+ }
758
+
759
+ function pushNode(next) {
760
+ {
761
+ next.context._currentValue = next.value;
762
+ }
763
+ }
764
+
765
+ function popToNearestCommonAncestor(prev, next) {
766
+ if (prev === next) ; else {
767
+ popNode(prev);
768
+ const parentPrev = prev.parent;
769
+ const parentNext = next.parent;
770
+
771
+ if (parentPrev === null) {
772
+ if (parentNext !== null) {
773
+ throw new Error('The stacks must reach the root at the same time. This is a bug in React.');
774
+ }
775
+ } else {
776
+ if (parentNext === null) {
777
+ throw new Error('The stacks must reach the root at the same time. This is a bug in React.');
778
+ }
779
+
780
+ popToNearestCommonAncestor(parentPrev, parentNext); // On the way back, we push the new ones that weren't common.
781
+
782
+ pushNode(next);
783
+ }
784
+ }
785
+ }
786
+
787
+ function popAllPrevious(prev) {
788
+ popNode(prev);
789
+ const parentPrev = prev.parent;
790
+
791
+ if (parentPrev !== null) {
792
+ popAllPrevious(parentPrev);
793
+ }
794
+ }
795
+
796
+ function pushAllNext(next) {
797
+ const parentNext = next.parent;
798
+
799
+ if (parentNext !== null) {
800
+ pushAllNext(parentNext);
801
+ }
802
+
803
+ pushNode(next);
804
+ }
805
+
806
+ function popPreviousToCommonLevel(prev, next) {
807
+ popNode(prev);
808
+ const parentPrev = prev.parent;
809
+
810
+ if (parentPrev === null) {
811
+ throw new Error('The depth must equal at least at zero before reaching the root. This is a bug in React.');
812
+ }
813
+
814
+ if (parentPrev.depth === next.depth) {
815
+ // We found the same level. Now we just need to find a shared ancestor.
816
+ popToNearestCommonAncestor(parentPrev, next);
817
+ } else {
818
+ // We must still be deeper.
819
+ popPreviousToCommonLevel(parentPrev, next);
820
+ }
821
+ }
822
+
823
+ function popNextToCommonLevel(prev, next) {
824
+ const parentNext = next.parent;
825
+
826
+ if (parentNext === null) {
827
+ throw new Error('The depth must equal at least at zero before reaching the root. This is a bug in React.');
828
+ }
829
+
830
+ if (prev.depth === parentNext.depth) {
831
+ // We found the same level. Now we just need to find a shared ancestor.
832
+ popToNearestCommonAncestor(prev, parentNext);
833
+ } else {
834
+ // We must still be deeper.
835
+ popNextToCommonLevel(prev, parentNext);
836
+ }
837
+
838
+ pushNode(next);
839
+ } // Perform context switching to the new snapshot.
840
+ // To make it cheap to read many contexts, while not suspending, we make the switch eagerly by
841
+ // updating all the context's current values. That way reads, always just read the current value.
842
+ // At the cost of updating contexts even if they're never read by this subtree.
843
+
844
+
845
+ function switchContext(newSnapshot) {
846
+ // The basic algorithm we need to do is to pop back any contexts that are no longer on the stack.
847
+ // We also need to update any new contexts that are now on the stack with the deepest value.
848
+ // The easiest way to update new contexts is to just reapply them in reverse order from the
849
+ // perspective of the backpointers. To avoid allocating a lot when switching, we use the stack
850
+ // for that. Therefore this algorithm is recursive.
851
+ // 1) First we pop which ever snapshot tree was deepest. Popping old contexts as we go.
852
+ // 2) Then we find the nearest common ancestor from there. Popping old contexts as we go.
853
+ // 3) Then we reapply new contexts on the way back up the stack.
854
+ const prev = currentActiveSnapshot;
855
+ const next = newSnapshot;
856
+
857
+ if (prev !== next) {
858
+ if (prev === null) {
859
+ // $FlowFixMe[incompatible-call]: This has to be non-null since it's not equal to prev.
860
+ pushAllNext(next);
861
+ } else if (next === null) {
862
+ popAllPrevious(prev);
863
+ } else if (prev.depth === next.depth) {
864
+ popToNearestCommonAncestor(prev, next);
865
+ } else if (prev.depth > next.depth) {
866
+ popPreviousToCommonLevel(prev, next);
867
+ } else {
868
+ popNextToCommonLevel(prev, next);
869
+ }
870
+
871
+ currentActiveSnapshot = next;
872
+ }
873
+ }
874
+ function getActiveContext() {
875
+ return currentActiveSnapshot;
876
+ }
877
+ function readContext$1(context) {
878
+ const value = context._currentValue ;
879
+ return value;
880
+ }
881
+
759
882
  // Corresponds to ReactFiberWakeable and ReactFizzWakeable modules. Generally,
760
883
  // changes to one module should be reflected in the others.
761
884
  // TODO: Rename this module and the corresponding Fiber one to "Thenable"
@@ -884,13 +1007,16 @@ function prepareToUseHooksForComponent(prevThenableState) {
884
1007
  thenableState = prevThenableState;
885
1008
  }
886
1009
  function getThenableStateAfterSuspending() {
887
- // If you use() to Suspend this should always exist but if you throw a Promise instead,
888
- // which is not really supported anymore, it will be empty. We use the empty set as a
889
- // marker to know if this was a replay of the same component or first attempt.
890
- const state = thenableState || createThenableState();
1010
+ const state = thenableState;
891
1011
  thenableState = null;
892
1012
  return state;
893
1013
  }
1014
+
1015
+ function readContext(context) {
1016
+
1017
+ return readContext$1(context);
1018
+ }
1019
+
894
1020
  const HooksDispatcher = {
895
1021
  useMemo(nextCreate) {
896
1022
  return nextCreate();
@@ -904,8 +1030,8 @@ const HooksDispatcher = {
904
1030
 
905
1031
  useDeferredValue: unsupportedHook,
906
1032
  useTransition: unsupportedHook,
907
- readContext: unsupportedContext,
908
- useContext: unsupportedContext,
1033
+ readContext,
1034
+ useContext: readContext,
909
1035
  useReducer: unsupportedHook,
910
1036
  useRef: unsupportedHook,
911
1037
  useState: unsupportedHook,
@@ -941,10 +1067,6 @@ function unsupportedRefresh() {
941
1067
  throw new Error('Refreshing the cache is not supported in Server Components.');
942
1068
  }
943
1069
 
944
- function unsupportedContext() {
945
- throw new Error('Cannot read a Client Context from a Server Component.');
946
- }
947
-
948
1070
  function useId() {
949
1071
  if (currentRequest$1 === null) {
950
1072
  throw new Error('useId can only be used while React is rendering');
@@ -970,22 +1092,14 @@ function use(usable) {
970
1092
  }
971
1093
 
972
1094
  return trackUsedThenable(thenableState, thenable, index);
973
- } else if (usable.$$typeof === REACT_CONTEXT_TYPE) {
974
- unsupportedContext();
1095
+ } else if (usable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
1096
+ const context = usable;
1097
+ return readContext(context);
975
1098
  }
976
1099
  }
977
1100
 
978
- if (isClientReference(usable)) {
979
- if (usable.value != null && usable.value.$$typeof === REACT_CONTEXT_TYPE) {
980
- // Show a more specific message since it's a common mistake.
981
- throw new Error('Cannot read a Client Context from a Server Component.');
982
- } else {
983
- throw new Error('Cannot use() an already resolved Client Reference.');
984
- }
985
- } else {
986
- throw new Error( // eslint-disable-next-line react-internal/safe-string-coercion
987
- 'An unsupported type was passed to use(): ' + String(usable));
988
- }
1101
+
1102
+ throw new Error('An unsupported type was passed to use(): ' + String(usable));
989
1103
  }
990
1104
 
991
1105
  function createSignal() {
@@ -1064,10 +1178,6 @@ function describeValueForErrorMessage(value) {
1064
1178
  return '[...]';
1065
1179
  }
1066
1180
 
1067
- if (value !== null && value.$$typeof === CLIENT_REFERENCE_TAG) {
1068
- return describeClientReference();
1069
- }
1070
-
1071
1181
  const name = objectName(value);
1072
1182
 
1073
1183
  if (name === 'Object') {
@@ -1078,14 +1188,7 @@ function describeValueForErrorMessage(value) {
1078
1188
  }
1079
1189
 
1080
1190
  case 'function':
1081
- {
1082
- if (value.$$typeof === CLIENT_REFERENCE_TAG) {
1083
- return describeClientReference();
1084
- }
1085
-
1086
- const name = value.displayName || value.name;
1087
- return name ? 'function ' + name : 'function';
1088
- }
1191
+ return 'function';
1089
1192
 
1090
1193
  default:
1091
1194
  // eslint-disable-next-line react-internal/safe-string-coercion
@@ -1131,12 +1234,6 @@ function describeElementType(type) {
1131
1234
  return '';
1132
1235
  }
1133
1236
 
1134
- const CLIENT_REFERENCE_TAG = Symbol.for('react.client.reference');
1135
-
1136
- function describeClientReference(ref) {
1137
- return 'client';
1138
- }
1139
-
1140
1237
  function describeObjectForErrorMessage(objectOrArray, expandedName) {
1141
1238
  const objKind = objectName(objectOrArray);
1142
1239
 
@@ -1184,8 +1281,6 @@ function describeObjectForErrorMessage(objectOrArray, expandedName) {
1184
1281
  } else {
1185
1282
  if (objectOrArray.$$typeof === REACT_ELEMENT_TYPE) {
1186
1283
  str = '<' + describeElementType(objectOrArray.type) + '/>';
1187
- } else if (objectOrArray.$$typeof === CLIENT_REFERENCE_TAG) {
1188
- return describeClientReference();
1189
1284
  } else {
1190
1285
  // Print Object
1191
1286
  str = '{';
@@ -1265,7 +1360,7 @@ function defaultPostponeHandler(reason) {// Noop
1265
1360
  const OPEN = 0;
1266
1361
  const CLOSING = 1;
1267
1362
  const CLOSED = 2;
1268
- function createRequest(model, bundlerConfig, onError, identifierPrefix, onPostpone, environmentName) {
1363
+ function createRequest(model, bundlerConfig, onError, context, identifierPrefix, onPostpone) {
1269
1364
  if (ReactCurrentCache.current !== null && ReactCurrentCache.current !== DefaultCacheDispatcher) {
1270
1365
  throw new Error('Currently React only supports one RSC renderer at a time.');
1271
1366
  }
@@ -1296,15 +1391,21 @@ function createRequest(model, bundlerConfig, onError, identifierPrefix, onPostpo
1296
1391
  writtenSymbols: new Map(),
1297
1392
  writtenClientReferences: new Map(),
1298
1393
  writtenServerReferences: new Map(),
1394
+ writtenProviders: new Map(),
1299
1395
  writtenObjects: new WeakMap(),
1300
1396
  identifierPrefix: identifierPrefix || '',
1301
1397
  identifierCount: 1,
1302
1398
  taintCleanupQueue: cleanupQueue,
1303
1399
  onError: onError === undefined ? defaultErrorHandler : onError,
1304
- onPostpone: onPostpone === undefined ? defaultPostponeHandler : onPostpone
1400
+ onPostpone: onPostpone === undefined ? defaultPostponeHandler : onPostpone,
1401
+ // $FlowFixMe[missing-this-annot]
1402
+ toJSON: function (key, value) {
1403
+ return resolveModelToJSON(request, this, key, value);
1404
+ }
1305
1405
  };
1306
-
1307
- const rootTask = createTask(request, model, null, false, abortSet);
1406
+ request.pendingChunks++;
1407
+ const rootContext = createRootContext();
1408
+ const rootTask = createTask(request, model, rootContext, abortSet);
1308
1409
  pingedTasks.push(rootTask);
1309
1410
  return request;
1310
1411
  }
@@ -1320,9 +1421,13 @@ function resolveRequest() {
1320
1421
  return null;
1321
1422
  }
1322
1423
 
1323
- function serializeThenable(request, task, thenable) {
1324
- const newTask = createTask(request, null, task.keyPath, // the server component sequence continues through Promise-as-a-child.
1325
- task.implicitSlot, request.abortableTasks);
1424
+ function createRootContext(reqContext) {
1425
+ return importServerContexts();
1426
+ }
1427
+
1428
+ function serializeThenable(request, thenable) {
1429
+ request.pendingChunks++;
1430
+ const newTask = createTask(request, null, getActiveContext(), request.abortableTasks);
1326
1431
 
1327
1432
  switch (thenable.status) {
1328
1433
  case 'fulfilled':
@@ -1456,117 +1561,61 @@ function createLazyWrapperAroundWakeable(wakeable) {
1456
1561
  _payload: thenable,
1457
1562
  _init: readThenable
1458
1563
  };
1459
-
1460
1564
  return lazyType;
1461
1565
  }
1462
1566
 
1463
- function renderFunctionComponent(request, task, key, Component, props) {
1464
- // Reset the task's thenable state before continuing, so that if a later
1465
- // component suspends we can reuse the same task object. If the same
1466
- // component suspends again, the thenable state will be restored.
1467
- const prevThenableState = task.thenableState;
1468
- task.thenableState = null;
1469
-
1470
- prepareToUseHooksForComponent(prevThenableState); // The secondArg is always undefined in Server Components since refs error early.
1471
-
1472
- const secondArg = undefined;
1473
- let result = Component(props, secondArg);
1474
-
1475
- if (typeof result === 'object' && result !== null && typeof result.then === 'function') {
1476
- // When the return value is in children position we can resolve it immediately,
1477
- // to its value without a wrapper if it's synchronously available.
1478
- const thenable = result;
1479
-
1480
- if (thenable.status === 'fulfilled') {
1481
- return thenable.value;
1482
- } // TODO: Once we accept Promises as children on the client, we can just return
1483
- // the thenable here.
1484
-
1485
-
1486
- result = createLazyWrapperAroundWakeable(result);
1487
- } // Track this element's key on the Server Component on the keyPath context..
1488
-
1489
-
1490
- const prevKeyPath = task.keyPath;
1491
- const prevImplicitSlot = task.implicitSlot;
1492
-
1493
- if (key !== null) {
1494
- // Append the key to the path. Technically a null key should really add the child
1495
- // index. We don't do that to hold the payload small and implementation simple.
1496
- task.keyPath = prevKeyPath === null ? key : prevKeyPath + ',' + key;
1497
- } else if (prevKeyPath === null) {
1498
- // This sequence of Server Components has no keys. This means that it was rendered
1499
- // in a slot that needs to assign an implicit key. Even if children below have
1500
- // explicit keys, they should not be used for the outer most key since it might
1501
- // collide with other slots in that set.
1502
- task.implicitSlot = true;
1503
- }
1504
-
1505
- const json = renderModelDestructive(request, task, emptyRoot, '', result);
1506
- task.keyPath = prevKeyPath;
1507
- task.implicitSlot = prevImplicitSlot;
1508
- return json;
1509
- }
1510
-
1511
- function renderFragment(request, task, children) {
1512
-
1513
- {
1514
- return children;
1515
- }
1516
- }
1517
-
1518
- function renderClientElement(task, type, key, props) {
1519
- {
1520
- return [REACT_ELEMENT_TYPE, type, key, props];
1521
- } // We prepend the terminal client element that actually gets serialized with
1522
- } // The chunk ID we're currently rendering that we can assign debug data to.
1523
-
1524
-
1525
- let debugID = null;
1526
-
1527
- function renderElement(request, task, type, key, ref, props) {
1567
+ function attemptResolveElement(request, type, key, ref, props, prevThenableState) {
1528
1568
  if (ref !== null && ref !== undefined) {
1529
1569
  // When the ref moves to the regular props object this will implicitly
1530
1570
  // throw for functions. We could probably relax it to a DEV warning for other
1531
1571
  // cases.
1532
- // TODO: `ref` is now just a prop when `enableRefAsProp` is on. Should we
1533
- // do what the above comment says?
1534
1572
  throw new Error('Refs cannot be used in Server Components, nor passed to Client Components.');
1535
1573
  }
1536
1574
 
1537
1575
  if (typeof type === 'function') {
1538
1576
  if (isClientReference(type)) {
1539
1577
  // This is a reference to a Client Component.
1540
- return renderClientElement(task, type, key, props);
1541
- } // This is a Server Component.
1578
+ return [REACT_ELEMENT_TYPE, type, key, props];
1579
+ } // This is a server-side component.
1580
+
1581
+
1582
+ prepareToUseHooksForComponent(prevThenableState);
1583
+ const result = type(props);
1584
+
1585
+ if (typeof result === 'object' && result !== null && typeof result.then === 'function') {
1586
+ // When the return value is in children position we can resolve it immediately,
1587
+ // to its value without a wrapper if it's synchronously available.
1588
+ const thenable = result;
1589
+
1590
+ if (thenable.status === 'fulfilled') {
1591
+ return thenable.value;
1592
+ } // TODO: Once we accept Promises as children on the client, we can just return
1593
+ // the thenable here.
1542
1594
 
1543
1595
 
1544
- return renderFunctionComponent(request, task, key, type, props);
1596
+ return createLazyWrapperAroundWakeable(result);
1597
+ }
1598
+
1599
+ return result;
1545
1600
  } else if (typeof type === 'string') {
1546
1601
  // This is a host element. E.g. HTML.
1547
- return renderClientElement(task, type, key, props);
1602
+ return [REACT_ELEMENT_TYPE, type, key, props];
1548
1603
  } else if (typeof type === 'symbol') {
1549
- if (type === REACT_FRAGMENT_TYPE && key === null) {
1604
+ if (type === REACT_FRAGMENT_TYPE) {
1550
1605
  // For key-less fragments, we add a small optimization to avoid serializing
1551
1606
  // it as a wrapper.
1552
- const prevImplicitSlot = task.implicitSlot;
1553
-
1554
- if (task.keyPath === null) {
1555
- task.implicitSlot = true;
1556
- }
1557
-
1558
- const json = renderModelDestructive(request, task, emptyRoot, '', props.children);
1559
- task.implicitSlot = prevImplicitSlot;
1560
- return json;
1607
+ // TODO: If a key is specified, we should propagate its key to any children.
1608
+ // Same as if a Server Component has a key.
1609
+ return props.children;
1561
1610
  } // This might be a built-in React component. We'll let the client decide.
1562
1611
  // Any built-in works as long as its props are serializable.
1563
1612
 
1564
1613
 
1565
- return renderClientElement(task, type, key, props);
1614
+ return [REACT_ELEMENT_TYPE, type, key, props];
1566
1615
  } else if (type != null && typeof type === 'object') {
1567
1616
  if (isClientReference(type)) {
1568
1617
  // This is a reference to a Client Component.
1569
- return renderClientElement(task, type, key, props);
1618
+ return [REACT_ELEMENT_TYPE, type, key, props];
1570
1619
  }
1571
1620
 
1572
1621
  switch (type.$$typeof) {
@@ -1575,17 +1624,19 @@ function renderElement(request, task, type, key, ref, props) {
1575
1624
  const payload = type._payload;
1576
1625
  const init = type._init;
1577
1626
  const wrappedType = init(payload);
1578
- return renderElement(request, task, wrappedType, key, ref, props);
1627
+ return attemptResolveElement(request, wrappedType, key, ref, props, prevThenableState);
1579
1628
  }
1580
1629
 
1581
1630
  case REACT_FORWARD_REF_TYPE:
1582
1631
  {
1583
- return renderFunctionComponent(request, task, key, type.render, props);
1632
+ const render = type.render;
1633
+ prepareToUseHooksForComponent(prevThenableState);
1634
+ return render(props, undefined);
1584
1635
  }
1585
1636
 
1586
1637
  case REACT_MEMO_TYPE:
1587
1638
  {
1588
- return renderElement(request, task, type.type, key, ref, props);
1639
+ return attemptResolveElement(request, type.type, key, ref, props, prevThenableState);
1589
1640
  }
1590
1641
  }
1591
1642
  }
@@ -1603,30 +1654,14 @@ function pingTask(request, task) {
1603
1654
  }
1604
1655
  }
1605
1656
 
1606
- function createTask(request, model, keyPath, implicitSlot, abortSet) {
1607
- request.pendingChunks++;
1657
+ function createTask(request, model, context, abortSet) {
1608
1658
  const id = request.nextChunkId++;
1609
-
1610
- if (typeof model === 'object' && model !== null) {
1611
- // If we're about to write this into a new task we can assign it an ID early so that
1612
- // any other references can refer to the value we're about to write.
1613
- {
1614
- request.writtenObjects.set(model, id);
1615
- }
1616
- }
1617
-
1618
1659
  const task = {
1619
1660
  id,
1620
1661
  status: PENDING$1,
1621
1662
  model,
1622
- keyPath,
1623
- implicitSlot,
1663
+ context,
1624
1664
  ping: () => pingTask(request, task),
1625
- toJSON: function (parentPropertyName, value) {
1626
- const parent = this; // Make sure that `parent[parentPropertyName]` wasn't JSONified before `value` was passed to us
1627
-
1628
- return renderModel(request, task, parent, parentPropertyName, value);
1629
- },
1630
1665
  thenableState: null
1631
1666
  };
1632
1667
  abortSet.add(task);
@@ -1695,13 +1730,13 @@ function encodeReferenceChunk(request, id, reference) {
1695
1730
  return stringToChunk(row);
1696
1731
  }
1697
1732
 
1698
- function serializeClientReference(request, parent, parentPropertyName, clientReference) {
1733
+ function serializeClientReference(request, parent, key, clientReference) {
1699
1734
  const clientReferenceKey = getClientReferenceKey(clientReference);
1700
1735
  const writtenClientReferences = request.writtenClientReferences;
1701
1736
  const existingId = writtenClientReferences.get(clientReferenceKey);
1702
1737
 
1703
1738
  if (existingId !== undefined) {
1704
- if (parent[0] === REACT_ELEMENT_TYPE && parentPropertyName === '1') {
1739
+ if (parent[0] === REACT_ELEMENT_TYPE && key === '1') {
1705
1740
  // If we're encoding the "type" of an element, we can refer
1706
1741
  // to that by a lazy reference instead of directly since React
1707
1742
  // knows how to deal with lazy values. This lets us suspend
@@ -1720,7 +1755,7 @@ function serializeClientReference(request, parent, parentPropertyName, clientRef
1720
1755
  emitImportChunk(request, importId, clientReferenceMetadata);
1721
1756
  writtenClientReferences.set(clientReferenceKey, importId);
1722
1757
 
1723
- if (parent[0] === REACT_ELEMENT_TYPE && parentPropertyName === '1') {
1758
+ if (parent[0] === REACT_ELEMENT_TYPE && key === '1') {
1724
1759
  // If we're encoding the "type" of an element, we can refer
1725
1760
  // to that by a lazy reference instead of directly since React
1726
1761
  // knows how to deal with lazy values. This lets us suspend
@@ -1740,14 +1775,13 @@ function serializeClientReference(request, parent, parentPropertyName, clientRef
1740
1775
  }
1741
1776
 
1742
1777
  function outlineModel(request, value) {
1743
- const newTask = createTask(request, value, null, // The way we use outlining is for reusing an object.
1744
- false, // It makes no sense for that use case to be contextual.
1745
- request.abortableTasks);
1778
+ request.pendingChunks++;
1779
+ const newTask = createTask(request, value, getActiveContext(), request.abortableTasks);
1746
1780
  retryTask(request, newTask);
1747
1781
  return newTask.id;
1748
1782
  }
1749
1783
 
1750
- function serializeServerReference(request, serverReference) {
1784
+ function serializeServerReference(request, parent, key, serverReference) {
1751
1785
  const writtenServerReferences = request.writtenServerReferences;
1752
1786
  const existingId = writtenServerReferences.get(serverReference);
1753
1787
 
@@ -1827,77 +1861,91 @@ function escapeStringValue(value) {
1827
1861
  return value;
1828
1862
  }
1829
1863
  }
1830
-
1831
1864
  let modelRoot = false;
1832
1865
 
1833
- function renderModel(request, task, parent, key, value) {
1834
- const prevKeyPath = task.keyPath;
1835
- const prevImplicitSlot = task.implicitSlot;
1866
+ function resolveModelToJSON(request, parent, key, value) {
1836
1867
 
1837
- try {
1838
- return renderModelDestructive(request, task, parent, key, value);
1839
- } catch (thrownValue) {
1840
- const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
1841
- // reasons, the rest of the Suspense implementation expects the thrown
1842
- // value to be a thenable, because before `use` existed that was the
1843
- // (unstable) API for suspending. This implementation detail can change
1844
- // later, once we deprecate the old API in favor of `use`.
1845
- getSuspendedThenable() : thrownValue; // If the suspended/errored value was an element or lazy it can be reduced
1846
- // to a lazy reference, so that it doesn't error the parent.
1847
1868
 
1848
- const model = task.model;
1849
- const wasReactNode = typeof model === 'object' && model !== null && (model.$$typeof === REACT_ELEMENT_TYPE || model.$$typeof === REACT_LAZY_TYPE);
1869
+ switch (value) {
1870
+ case REACT_ELEMENT_TYPE:
1871
+ return '$';
1872
+ }
1850
1873
 
1851
- if (typeof x === 'object' && x !== null) {
1852
- // $FlowFixMe[method-unbinding]
1853
- if (typeof x.then === 'function') {
1854
- // Something suspended, we'll need to create a new task and resolve it later.
1855
- const newTask = createTask(request, task.model, task.keyPath, task.implicitSlot, request.abortableTasks);
1856
- const ping = newTask.ping;
1857
- x.then(ping, ping);
1858
- newTask.thenableState = getThenableStateAfterSuspending(); // Restore the context. We assume that this will be restored by the inner
1859
- // functions in case nothing throws so we don't use "finally" here.
1860
1874
 
1861
- task.keyPath = prevKeyPath;
1862
- task.implicitSlot = prevImplicitSlot;
1875
+ while (typeof value === 'object' && value !== null && (value.$$typeof === REACT_ELEMENT_TYPE || value.$$typeof === REACT_LAZY_TYPE)) {
1863
1876
 
1864
- if (wasReactNode) {
1865
- return serializeLazyID(newTask.id);
1866
- }
1877
+ try {
1878
+ switch (value.$$typeof) {
1879
+ case REACT_ELEMENT_TYPE:
1880
+ {
1881
+ const writtenObjects = request.writtenObjects;
1882
+ const existingId = writtenObjects.get(value);
1883
+
1884
+ if (existingId !== undefined) {
1885
+ if (existingId === -1) {
1886
+ // Seen but not yet outlined.
1887
+ const newId = outlineModel(request, value);
1888
+ return serializeByValueID(newId);
1889
+ } else if (modelRoot === value) {
1890
+ // This is the ID we're currently emitting so we need to write it
1891
+ // once but if we discover it again, we refer to it by id.
1892
+ modelRoot = null;
1893
+ } else {
1894
+ // We've already emitted this as an outlined object, so we can
1895
+ // just refer to that by its existing ID.
1896
+ return serializeByValueID(existingId);
1897
+ }
1898
+ } else {
1899
+ // This is the first time we've seen this object. We may never see it again
1900
+ // so we'll inline it. Mark it as seen. If we see it again, we'll outline.
1901
+ writtenObjects.set(value, -1);
1902
+ } // TODO: Concatenate keys of parents onto children.
1867
1903
 
1868
- return serializeByValueID(newTask.id);
1869
- }
1870
- } // Restore the context. We assume that this will be restored by the inner
1871
- // functions in case nothing throws so we don't use "finally" here.
1872
1904
 
1905
+ const element = value; // Attempt to render the Server Component.
1873
1906
 
1874
- task.keyPath = prevKeyPath;
1875
- task.implicitSlot = prevImplicitSlot;
1907
+ value = attemptResolveElement(request, element.type, element.key, element.ref, element.props, null);
1908
+ break;
1909
+ }
1876
1910
 
1877
- if (wasReactNode) {
1878
- // Something errored. We'll still send everything we have up until this point.
1911
+ case REACT_LAZY_TYPE:
1912
+ {
1913
+ const payload = value._payload;
1914
+ const init = value._init;
1915
+ value = init(payload);
1916
+ break;
1917
+ }
1918
+ }
1919
+ } catch (thrownValue) {
1920
+ const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
1921
+ // reasons, the rest of the Suspense implementation expects the thrown
1922
+ // value to be a thenable, because before `use` existed that was the
1923
+ // (unstable) API for suspending. This implementation detail can change
1924
+ // later, once we deprecate the old API in favor of `use`.
1925
+ getSuspendedThenable() : thrownValue;
1926
+
1927
+ if (typeof x === 'object' && x !== null) {
1928
+ // $FlowFixMe[method-unbinding]
1929
+ if (typeof x.then === 'function') {
1930
+ // Something suspended, we'll need to create a new task and resolve it later.
1931
+ request.pendingChunks++;
1932
+ const newTask = createTask(request, value, getActiveContext(), request.abortableTasks);
1933
+ const ping = newTask.ping;
1934
+ x.then(ping, ping);
1935
+ newTask.thenableState = getThenableStateAfterSuspending();
1936
+ return serializeLazyID(newTask.id);
1937
+ }
1938
+ } // Something errored. We'll still send everything we have up until this point.
1879
1939
  // We'll replace this element with a lazy reference that throws on the client
1880
1940
  // once it gets rendered.
1941
+
1942
+
1881
1943
  request.pendingChunks++;
1882
1944
  const errorId = request.nextChunkId++;
1883
1945
  const digest = logRecoverableError(request, x);
1884
1946
  emitErrorChunk(request, errorId, digest);
1885
1947
  return serializeLazyID(errorId);
1886
- } // Something errored but it was not in a React Node. There's no need to serialize
1887
- // it by value because it'll just error the whole parent row anyway so we can
1888
- // just stop any siblings and error the whole parent row.
1889
-
1890
-
1891
- throw x;
1892
- }
1893
- }
1894
-
1895
- function renderModelDestructive(request, task, parent, parentPropertyName, value) {
1896
- // Set the currently rendering model
1897
- task.model = value; // Special Symbol, that's very common.
1898
-
1899
- if (value === REACT_ELEMENT_TYPE) {
1900
- return '$';
1948
+ }
1901
1949
  }
1902
1950
 
1903
1951
  if (value === null) {
@@ -1905,70 +1953,9 @@ function renderModelDestructive(request, task, parent, parentPropertyName, value
1905
1953
  }
1906
1954
 
1907
1955
  if (typeof value === 'object') {
1908
- switch (value.$$typeof) {
1909
- case REACT_ELEMENT_TYPE:
1910
- {
1911
- const writtenObjects = request.writtenObjects;
1912
- const existingId = writtenObjects.get(value);
1913
-
1914
- if (existingId !== undefined) {
1915
- if (modelRoot === value) {
1916
- // This is the ID we're currently emitting so we need to write it
1917
- // once but if we discover it again, we refer to it by id.
1918
- modelRoot = null;
1919
- } else if (existingId === -1) {
1920
- // Seen but not yet outlined.
1921
- // TODO: If we throw here we can treat this as suspending which causes an outline
1922
- // but that is able to reuse the same task if we're already in one but then that
1923
- // will be a lazy future value rather than guaranteed to exist but maybe that's good.
1924
- const newId = outlineModel(request, value);
1925
- return serializeByValueID(newId);
1926
- } else {
1927
- // We've already emitted this as an outlined object, so we can refer to that by its
1928
- // existing ID. TODO: We should use a lazy reference since, unlike plain objects,
1929
- // elements might suspend so it might not have emitted yet even if we have the ID for
1930
- // it. However, this creates an extra wrapper when it's not needed. We should really
1931
- // detect whether this already was emitted and synchronously available. In that
1932
- // case we can refer to it synchronously and only make it lazy otherwise.
1933
- // We currently don't have a data structure that lets us see that though.
1934
- return serializeByValueID(existingId);
1935
- }
1936
- } else {
1937
- // This is the first time we've seen this object. We may never see it again
1938
- // so we'll inline it. Mark it as seen. If we see it again, we'll outline.
1939
- writtenObjects.set(value, -1);
1940
- }
1941
-
1942
- const element = value;
1943
-
1944
- const props = element.props;
1945
- let ref;
1946
-
1947
- {
1948
- ref = element.ref;
1949
- } // Attempt to render the Server Component.
1950
-
1951
-
1952
- return renderElement(request, task, element.type, // $FlowFixMe[incompatible-call] the key of an element is null | string
1953
- element.key, ref, props);
1954
- }
1955
-
1956
- case REACT_LAZY_TYPE:
1957
- {
1958
- // Reset the task's thenable state before continuing. If there was one, it was
1959
- // from suspending the lazy before.
1960
- task.thenableState = null;
1961
- const lazy = value;
1962
- const payload = lazy._payload;
1963
- const init = lazy._init;
1964
- const resolvedModel = init(payload);
1965
-
1966
- return renderModelDestructive(request, task, emptyRoot, '', resolvedModel);
1967
- }
1968
- }
1969
1956
 
1970
1957
  if (isClientReference(value)) {
1971
- return serializeClientReference(request, parent, parentPropertyName, value);
1958
+ return serializeClientReference(request, parent, key, value);
1972
1959
  }
1973
1960
 
1974
1961
  const writtenObjects = request.writtenObjects;
@@ -1988,20 +1975,20 @@ function renderModelDestructive(request, task, parent, parentPropertyName, value
1988
1975
  // or a Promise type. Either of which can be represented by a Promise.
1989
1976
 
1990
1977
 
1991
- const promiseId = serializeThenable(request, task, value);
1978
+ const promiseId = serializeThenable(request, value);
1992
1979
  writtenObjects.set(value, promiseId);
1993
1980
  return serializePromiseID(promiseId);
1994
1981
  }
1995
1982
 
1996
1983
  if (existingId !== undefined) {
1997
- if (modelRoot === value) {
1998
- // This is the ID we're currently emitting so we need to write it
1999
- // once but if we discover it again, we refer to it by id.
2000
- modelRoot = null;
2001
- } else if (existingId === -1) {
1984
+ if (existingId === -1) {
2002
1985
  // Seen but not yet outlined.
2003
1986
  const newId = outlineModel(request, value);
2004
1987
  return serializeByValueID(newId);
1988
+ } else if (modelRoot === value) {
1989
+ // This is the ID we're currently emitting so we need to write it
1990
+ // once but if we discover it again, we refer to it by id.
1991
+ modelRoot = null;
2005
1992
  } else {
2006
1993
  // We've already emitted this as an outlined object, so we can
2007
1994
  // just refer to that by its existing ID.
@@ -2014,7 +2001,8 @@ function renderModelDestructive(request, task, parent, parentPropertyName, value
2014
2001
  }
2015
2002
 
2016
2003
  if (isArray(value)) {
2017
- return renderFragment(request, task, value);
2004
+ // $FlowFixMe[incompatible-return]
2005
+ return value;
2018
2006
  }
2019
2007
 
2020
2008
  if (value instanceof Map) {
@@ -2028,7 +2016,7 @@ function renderModelDestructive(request, task, parent, parentPropertyName, value
2028
2016
  const iteratorFn = getIteratorFn(value);
2029
2017
 
2030
2018
  if (iteratorFn) {
2031
- return renderFragment(request, task, Array.from(value));
2019
+ return Array.from(value);
2032
2020
  } // Verify that this is a simple plain object.
2033
2021
 
2034
2022
 
@@ -2048,7 +2036,7 @@ function renderModelDestructive(request, task, parent, parentPropertyName, value
2048
2036
  if (value[value.length - 1] === 'Z') {
2049
2037
  // Possibly a Date, whose toJSON automatically calls toISOString
2050
2038
  // $FlowFixMe[incompatible-use]
2051
- const originalValue = parent[parentPropertyName];
2039
+ const originalValue = parent[key];
2052
2040
 
2053
2041
  if (originalValue instanceof Date) {
2054
2042
  return serializeDateFromDateJSON(value);
@@ -2078,18 +2066,19 @@ function renderModelDestructive(request, task, parent, parentPropertyName, value
2078
2066
  }
2079
2067
 
2080
2068
  if (typeof value === 'function') {
2069
+
2081
2070
  if (isClientReference(value)) {
2082
- return serializeClientReference(request, parent, parentPropertyName, value);
2071
+ return serializeClientReference(request, parent, key, value);
2083
2072
  }
2084
2073
 
2085
2074
  if (isServerReference(value)) {
2086
- return serializeServerReference(request, value);
2075
+ return serializeServerReference(request, parent, key, value);
2087
2076
  }
2088
2077
 
2089
- if (/^on[A-Z]/.test(parentPropertyName)) {
2090
- throw new Error('Event handlers cannot be passed to Client Component props.' + describeObjectForErrorMessage(parent, parentPropertyName) + '\nIf you need interactivity, consider converting part of this to a Client Component.');
2078
+ if (/^on[A-Z]/.test(key)) {
2079
+ throw new Error('Event handlers cannot be passed to Client Component props.' + describeObjectForErrorMessage(parent, key) + '\nIf you need interactivity, consider converting part of this to a Client Component.');
2091
2080
  } else {
2092
- throw new Error('Functions cannot be passed directly to Client Components ' + 'unless you explicitly expose it by marking it with "use server". ' + 'Or maybe you meant to call this function rather than return it.' + describeObjectForErrorMessage(parent, parentPropertyName));
2081
+ throw new Error('Functions cannot be passed directly to Client Components ' + 'unless you explicitly expose it by marking it with "use server".' + describeObjectForErrorMessage(parent, key));
2093
2082
  }
2094
2083
  }
2095
2084
 
@@ -2106,7 +2095,7 @@ function renderModelDestructive(request, task, parent, parentPropertyName, value
2106
2095
 
2107
2096
  if (Symbol.for(name) !== value) {
2108
2097
  throw new Error('Only global symbols received from Symbol.for(...) can be passed to Client Components. ' + ("The symbol Symbol.for(" + // $FlowFixMe[incompatible-type] `description` might be undefined
2109
- value.description + ") cannot be found among global symbols.") + describeObjectForErrorMessage(parent, parentPropertyName));
2098
+ value.description + ") cannot be found among global symbols.") + describeObjectForErrorMessage(parent, key));
2110
2099
  }
2111
2100
 
2112
2101
  request.pendingChunks++;
@@ -2121,40 +2110,17 @@ function renderModelDestructive(request, task, parent, parentPropertyName, value
2121
2110
  return serializeBigInt(value);
2122
2111
  }
2123
2112
 
2124
- throw new Error("Type " + typeof value + " is not supported in Client Component props." + describeObjectForErrorMessage(parent, parentPropertyName));
2113
+ throw new Error("Type " + typeof value + " is not supported in Client Component props." + describeObjectForErrorMessage(parent, key));
2125
2114
  }
2126
2115
 
2127
2116
  function logPostpone(request, reason) {
2128
- const prevRequest = currentRequest;
2129
- currentRequest = null;
2130
-
2131
- try {
2132
- const onPostpone = request.onPostpone;
2133
-
2134
- if (supportsRequestStorage) {
2135
- // Exit the request context while running callbacks.
2136
- requestStorage.run(undefined, onPostpone, reason);
2137
- }
2138
- } finally {
2139
- currentRequest = prevRequest;
2140
- }
2117
+ const onPostpone = request.onPostpone;
2118
+ onPostpone(reason);
2141
2119
  }
2142
2120
 
2143
2121
  function logRecoverableError(request, error) {
2144
- const prevRequest = currentRequest;
2145
- currentRequest = null;
2146
- let errorDigest;
2147
-
2148
- try {
2149
- const onError = request.onError;
2150
-
2151
- if (supportsRequestStorage) {
2152
- // Exit the request context while running callbacks.
2153
- errorDigest = requestStorage.run(undefined, onError, error);
2154
- }
2155
- } finally {
2156
- currentRequest = prevRequest;
2157
- }
2122
+ const onError = request.onError;
2123
+ const errorDigest = onError(error);
2158
2124
 
2159
2125
  if (errorDigest != null && typeof errorDigest !== 'string') {
2160
2126
  // eslint-disable-next-line react-internal/prod-error-codes
@@ -2224,54 +2190,62 @@ function emitSymbolChunk(request, id, name) {
2224
2190
  request.completedImportChunks.push(processedChunk);
2225
2191
  }
2226
2192
 
2227
- function emitModelChunk(request, id, json) {
2193
+ function emitModelChunk(request, id, model) {
2194
+ // Track the root so we know that we have to emit this object even though it
2195
+ // already has an ID. This is needed because we might see this object twice
2196
+ // in the same toJSON if it is cyclic.
2197
+ modelRoot = model; // $FlowFixMe[incompatible-type] stringify can return null
2198
+
2199
+ const json = stringify(model, request.toJSON);
2228
2200
  const row = id.toString(16) + ':' + json + '\n';
2229
2201
  const processedChunk = stringToChunk(row);
2230
2202
  request.completedRegularChunks.push(processedChunk);
2231
2203
  }
2232
2204
 
2233
- const emptyRoot = {};
2234
-
2235
2205
  function retryTask(request, task) {
2236
2206
  if (task.status !== PENDING$1) {
2237
2207
  // We completed this by other means before we had a chance to retry it.
2238
2208
  return;
2239
2209
  }
2240
2210
 
2211
+ switchContext(task.context);
2212
+
2241
2213
  try {
2242
- // Track the root so we know that we have to emit this object even though it
2243
- // already has an ID. This is needed because we might see this object twice
2244
- // in the same toJSON if it is cyclic.
2245
- modelRoot = task.model;
2214
+ let value = task.model;
2246
2215
 
2247
- if (false) ; // We call the destructive form that mutates this task. That way if something
2248
- // suspends again, we can reuse the same task instead of spawning a new one.
2216
+ if (typeof value === 'object' && value !== null && value.$$typeof === REACT_ELEMENT_TYPE) {
2217
+ request.writtenObjects.set(value, task.id); // TODO: Concatenate keys of parents onto children.
2249
2218
 
2219
+ const element = value; // When retrying a component, reuse the thenableState from the
2220
+ // previous attempt.
2250
2221
 
2251
- const resolvedModel = renderModelDestructive(request, task, emptyRoot, '', task.model);
2222
+ const prevThenableState = task.thenableState; // Attempt to render the Server Component.
2223
+ // Doing this here lets us reuse this same task if the next component
2224
+ // also suspends.
2252
2225
 
2253
- if (false) ; // Track the root again for the resolved object.
2226
+ task.model = value;
2227
+ value = attemptResolveElement(request, element.type, element.key, element.ref, element.props, prevThenableState); // Successfully finished this component. We're going to keep rendering
2228
+ // using the same task, but we reset its thenable state before continuing.
2254
2229
 
2230
+ task.thenableState = null; // Keep rendering and reuse the same task. This inner loop is separate
2231
+ // from the render above because we don't need to reset the thenable state
2232
+ // until the next time something suspends and retries.
2255
2233
 
2256
- modelRoot = resolvedModel; // The keyPath resets at any terminal child node.
2234
+ while (typeof value === 'object' && value !== null && value.$$typeof === REACT_ELEMENT_TYPE) {
2235
+ request.writtenObjects.set(value, task.id); // TODO: Concatenate keys of parents onto children.
2257
2236
 
2258
- task.keyPath = null;
2259
- task.implicitSlot = false;
2260
- let json;
2237
+ const nextElement = value;
2238
+ task.model = value;
2239
+ value = attemptResolveElement(request, nextElement.type, nextElement.key, nextElement.ref, nextElement.props, null);
2240
+ }
2241
+ } // Track that this object is outlined and has an id.
2261
2242
 
2262
- if (typeof resolvedModel === 'object' && resolvedModel !== null) {
2263
- // Object might contain unresolved values like additional elements.
2264
- // This is simulating what the JSON loop would do if this was part of it.
2265
- // $FlowFixMe[incompatible-type] stringify can return null for undefined but we never do
2266
- json = stringify(resolvedModel, task.toJSON);
2267
- } else {
2268
- // If the value is a string, it means it's a terminal value and we already escaped it
2269
- // We don't need to escape it again so it's not passed the toJSON replacer.
2270
- // $FlowFixMe[incompatible-type] stringify can return null for undefined but we never do
2271
- json = stringify(resolvedModel);
2243
+
2244
+ if (typeof value === 'object' && value !== null) {
2245
+ request.writtenObjects.set(value, task.id);
2272
2246
  }
2273
2247
 
2274
- emitModelChunk(request, task.id, json);
2248
+ emitModelChunk(request, task.id, value);
2275
2249
  request.abortableTasks.delete(task);
2276
2250
  task.status = COMPLETED;
2277
2251
  } catch (thrownValue) {
@@ -2297,7 +2271,6 @@ function retryTask(request, task) {
2297
2271
  task.status = ERRORED$1;
2298
2272
  const digest = logRecoverableError(request, x);
2299
2273
  emitErrorChunk(request, task.id, digest);
2300
- } finally {
2301
2274
  }
2302
2275
  }
2303
2276
 
@@ -2503,6 +2476,11 @@ function abort(request, reason) {
2503
2476
  }
2504
2477
  }
2505
2478
 
2479
+ function importServerContexts(contexts) {
2480
+
2481
+ return rootContextSnapshot;
2482
+ }
2483
+
2506
2484
  function resolveServerReference(bundlerConfig, id) {
2507
2485
  const idx = id.lastIndexOf('#');
2508
2486
  const specifier = id.slice(0, idx);
@@ -3209,7 +3187,7 @@ function createCancelHandler(request, reason) {
3209
3187
  }
3210
3188
 
3211
3189
  function renderToPipeableStream(model, webpackMap, options) {
3212
- const request = createRequest(model, webpackMap, options ? options.onError : undefined, options ? options.identifierPrefix : undefined, options ? options.onPostpone : undefined);
3190
+ const request = createRequest(model, webpackMap, options ? options.onError : undefined, options ? options.context : undefined, options ? options.identifierPrefix : undefined, options ? options.onPostpone : undefined);
3213
3191
  let hasStartedFlowing = false;
3214
3192
  startWork(request);
3215
3193
  return {