@shopify/hydrogen 1.3.1 → 1.3.2

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 (60) hide show
  1. package/dist/esnext/entry-client.js +1 -1
  2. package/dist/esnext/entry-server.js +20 -25
  3. package/dist/esnext/foundation/HydrogenResponse/HydrogenResponse.server.d.ts +4 -0
  4. package/dist/esnext/foundation/HydrogenResponse/HydrogenResponse.server.js +16 -1
  5. package/dist/esnext/foundation/fetchSync/ResponseSync.d.ts +2 -1
  6. package/dist/esnext/foundation/fetchSync/ResponseSync.js +14 -2
  7. package/dist/esnext/framework/plugin.js +2 -2
  8. package/dist/esnext/framework/plugins/vite-plugin-assets-version.js +4 -0
  9. package/dist/esnext/framework/plugins/vite-plugin-client-imports.js +6 -3
  10. package/dist/esnext/framework/plugins/vite-plugin-css-modules-rsc.js +3 -0
  11. package/dist/esnext/framework/plugins/vite-plugin-css-rsc.js +8 -0
  12. package/dist/esnext/framework/plugins/vite-plugin-hydration-auto-import.js +7 -1
  13. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-client-components-cache.d.ts +3 -0
  14. package/dist/esnext/framework/plugins/{vite-plugin-hydrogen-client-middleware.js → vite-plugin-hydrogen-client-components-cache.js} +2 -2
  15. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-config.js +101 -91
  16. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-middleware.js +6 -6
  17. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-suppress-warnings.js +5 -0
  18. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-virtual-files.js +21 -1
  19. package/dist/esnext/framework/plugins/vite-plugin-platform-entry.js +14 -1
  20. package/dist/esnext/framework/plugins/vite-plugin-ssr-interop.js +5 -1
  21. package/dist/esnext/framework/viteception.js +7 -1
  22. package/dist/esnext/types.d.ts +2 -1
  23. package/dist/esnext/utilities/apiRoutes.d.ts +2 -0
  24. package/dist/esnext/utilities/apiRoutes.js +1 -0
  25. package/dist/esnext/utilities/log/log.js +12 -3
  26. package/dist/esnext/utilities/template.d.ts +7 -6
  27. package/dist/esnext/utilities/template.js +39 -1
  28. package/dist/esnext/utilities/vite.d.ts +1 -0
  29. package/dist/esnext/utilities/vite.js +4 -0
  30. package/dist/esnext/version.d.ts +1 -1
  31. package/dist/esnext/version.js +1 -1
  32. package/dist/node/framework/plugin.js +2 -2
  33. package/dist/node/framework/plugins/vite-plugin-assets-version.js +4 -0
  34. package/dist/node/framework/plugins/vite-plugin-client-imports.js +6 -3
  35. package/dist/node/framework/plugins/vite-plugin-css-modules-rsc.js +3 -0
  36. package/dist/node/framework/plugins/vite-plugin-css-rsc.js +8 -0
  37. package/dist/node/framework/plugins/vite-plugin-hydration-auto-import.js +7 -1
  38. package/dist/node/framework/plugins/vite-plugin-hydrogen-client-components-cache.d.ts +3 -0
  39. package/dist/node/framework/plugins/{vite-plugin-hydrogen-client-middleware.js → vite-plugin-hydrogen-client-components-cache.js} +2 -2
  40. package/dist/node/framework/plugins/vite-plugin-hydrogen-config.js +101 -91
  41. package/dist/node/framework/plugins/vite-plugin-hydrogen-middleware.js +6 -6
  42. package/dist/node/framework/plugins/vite-plugin-hydrogen-suppress-warnings.js +5 -0
  43. package/dist/node/framework/plugins/vite-plugin-hydrogen-virtual-files.js +21 -1
  44. package/dist/node/framework/plugins/vite-plugin-platform-entry.js +14 -1
  45. package/dist/node/framework/plugins/vite-plugin-ssr-interop.js +5 -1
  46. package/dist/node/framework/viteception.js +7 -1
  47. package/dist/node/utilities/vite.d.ts +1 -0
  48. package/dist/node/utilities/vite.js +30 -0
  49. package/package.json +3 -3
  50. package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-plugin.js +31 -21
  51. package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-writer.browser.development.server.js +105 -29
  52. package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-writer.browser.production.min.server.js +30 -29
  53. package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-writer.node.development.server.js +92 -29
  54. package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-writer.node.production.min.server.js +31 -29
  55. package/vendor/react-server-dom-vite/esm/react-server-dom-vite-plugin.js +24 -14
  56. package/vendor/react-server-dom-vite/esm/react-server-dom-vite-writer.browser.server.js +105 -29
  57. package/vendor/react-server-dom-vite/esm/react-server-dom-vite-writer.node.server.js +92 -29
  58. package/vendor/react-server-dom-vite/package.json +2 -2
  59. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-client-middleware.d.ts +0 -9
  60. package/dist/node/framework/plugins/vite-plugin-hydrogen-client-middleware.d.ts +0 -9
@@ -9,10 +9,23 @@ const magic_string_1 = __importDefault(require("magic-string"));
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const fs_1 = __importDefault(require("fs"));
11
11
  const fast_glob_1 = __importDefault(require("fast-glob"));
12
+ const vite_js_1 = require("../../utilities/vite.js");
12
13
  const SSR_BUNDLE_NAME = 'index.js';
13
14
  // Keep this in the outer scope to share it
14
15
  // across client <> server builds.
15
16
  let clientBuildPath;
17
+ /* -- Plugin notes:
18
+ * This plugin simplifies the way a platform entry file imports user files. This is
19
+ * needed to write generic integrations with different platform providers.
20
+ *
21
+ * Instead of using relative paths:
22
+ * `import handleRequest from '../../<arbitrary_path>/src/App.server';`
23
+ * `import indexTemplate from '../../<arbitrary_path>/dist/client/index.html?raw';`
24
+ *
25
+ * It allows importing from a known static path which dynamically resolves the user files:
26
+ * `import {handleRequest, indexTemplate} from '@shopify/hydrogen/platforms';`
27
+ *
28
+ */
16
29
  exports.default = () => {
17
30
  let config;
18
31
  let isESM;
@@ -23,7 +36,7 @@ exports.default = () => {
23
36
  config = _config;
24
37
  if (config.build.ssr) {
25
38
  const { output = {} } = config.build.rollupOptions || {};
26
- const { format = '' } = (Array.isArray(output) ? output[0] : output) || {};
39
+ const { format = vite_js_1.isVite3 ? 'es' : '' } = (Array.isArray(output) ? output[0] : output) || {};
27
40
  isESM = Boolean(process.env.WORKER) || ['es', 'esm'].includes(format);
28
41
  }
29
42
  },
@@ -1,8 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ /* -- Plugin notes:
4
+ * This plugin makes sure we don't leak server logic to the browser when importing
5
+ * the `useEnvContext` utility.
6
+ */
3
7
  exports.default = () => {
4
8
  return {
5
- name: 'vite-plugin-ssr-interop',
9
+ name: 'hydrogen:ssr-interop',
6
10
  enforce: 'pre',
7
11
  transform(code, id, options = {}) {
8
12
  if (options.ssr && id.includes('foundation/ssr-interop')) {
@@ -2,12 +2,18 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.viteception = void 0;
4
4
  const vite_1 = require("vite");
5
+ const vite_js_1 = require("../utilities/vite.js");
5
6
  async function viteception(paths, options) {
6
7
  const isWorker = process.env.WORKER;
7
8
  delete process.env.WORKER;
8
9
  const server = await (0, vite_1.createServer)({
9
10
  clearScreen: false,
10
- server: { middlewareMode: 'ssr' },
11
+ server: {
12
+ middlewareMode: vite_js_1.isVite3 ? true : 'ssr',
13
+ hmr: false,
14
+ },
15
+ // @ts-ignore
16
+ appType: 'custom',
11
17
  ...options,
12
18
  });
13
19
  if (isWorker) {
@@ -0,0 +1 @@
1
+ export declare const isVite3: any;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.isVite3 = void 0;
27
+ // `version` is only exported in Vite 3
28
+ const vite = __importStar(require("vite"));
29
+ // @ts-ignore
30
+ exports.isVite3 = vite.version?.startsWith('3.');
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "engines": {
8
8
  "node": ">=14"
9
9
  },
10
- "version": "1.3.1",
10
+ "version": "1.3.2",
11
11
  "description": "Modern custom Shopify storefronts",
12
12
  "license": "MIT",
13
13
  "main": "dist/esnext/index.js",
@@ -119,7 +119,7 @@
119
119
  "react": "^18.2.0",
120
120
  "react-dom": "^18.2.0",
121
121
  "serve-static": "^1.14.1",
122
- "vite": "^2.9.0"
122
+ "vite": "^2.9.0 || ^3.0.0"
123
123
  },
124
124
  "peerDependenciesMeta": {
125
125
  "body-parser": {
@@ -151,7 +151,7 @@
151
151
  "react-helmet-async": "^1.3.0",
152
152
  "serve-static": "^1.15.0",
153
153
  "set-cookie-parser": "^2.5.0",
154
- "undici": "^5.5.1",
154
+ "undici": "^5.8.2",
155
155
  "uuid": "^8.3.2",
156
156
  "vite-plugin-inspect": "^0.3.6",
157
157
  "web-streams-polyfill": "^3.2.0",
@@ -14,9 +14,9 @@
14
14
 
15
15
  var esModuleLexer = require('es-module-lexer');
16
16
  var MagicString = require('magic-string');
17
- var vite = require('vite');
18
17
  var fs = require('fs');
19
18
  var path = require('path');
19
+ var vite = require('vite');
20
20
 
21
21
  function _unsupportedIterableToArray(o, minLen) {
22
22
  if (!o) return;
@@ -94,6 +94,10 @@ function _createForOfIteratorHelper(o, allowArrayLike) {
94
94
 
95
95
  var assign = Object.assign;
96
96
 
97
+ var normalizePath = vite.normalizePath,
98
+ transformWithEsbuild = vite.transformWithEsbuild,
99
+ createServer = vite.createServer;
100
+ var isVite3 = vite.version && vite.version.startsWith('3.');
97
101
  var rscViteFileRE = /\/react-server-dom-vite.js/;
98
102
  var noProxyRE = /[&?]no-proxy($|&)/;
99
103
 
@@ -267,11 +271,11 @@ function ReactFlightVitePlugin() {
267
271
  var injectGlobs = function (clientComponents) {
268
272
  var importerPath = path.dirname(id);
269
273
  var importers = clientComponents.map(function (absolutePath) {
270
- return vite.normalizePath(path.relative(importerPath, absolutePath));
274
+ return normalizePath(path.relative(importerPath, absolutePath));
271
275
  });
272
276
  var injectedGlobs = "Object.assign(Object.create(null), " + importers.map(function (glob) {
273
277
  return (// Mark the globs to modify the result after Vite resolves them.
274
- "\n/* HASH_BEGIN */ " + ("import.meta.glob('" + vite.normalizePath(glob) + "') /* HASH_END */")
278
+ "\n/* HASH_BEGIN */ " + ("import.meta.glob('" + normalizePath(glob) + "') /* HASH_END */")
275
279
  );
276
280
  }).join(', ') + ");";
277
281
  s.replace(INJECTING_RE, injectedGlobs);
@@ -358,7 +362,7 @@ async function proxyClientComponent(filepath, src) {
358
362
  src = await fs.promises.readFile(filepath, 'utf-8');
359
363
  }
360
364
 
361
- var _await$transformWithE = await vite.transformWithEsbuild(src, filepath),
365
+ var _await$transformWithE = await transformWithEsbuild(src, filepath),
362
366
  code = _await$transformWithE.code;
363
367
 
364
368
  var _parse = esModuleLexer.parse(code),
@@ -407,12 +411,14 @@ function findClientBoundaries(moduleGraph) {
407
411
 
408
412
  async function findClientBoundariesForClientBuild(serverEntries, optimizeBoundaries, root) {
409
413
  // Viteception
410
- var server = await vite.createServer({
414
+ var server = await createServer({
411
415
  root: root,
412
416
  clearScreen: false,
413
417
  server: {
414
- middlewareMode: 'ssr'
415
- }
418
+ middlewareMode: isVite3 ? true : 'ssr',
419
+ hmr: false
420
+ },
421
+ appType: 'custom'
416
422
  });
417
423
 
418
424
  try {
@@ -435,9 +441,10 @@ var hashImportsPlugin = {
435
441
  if (rscViteFileRE.test(id)) {
436
442
  var s = new MagicString(code);
437
443
  s.replace(/\/\*\s*HASH_BEGIN\s*\*\/\s*([^]+?)\/\*\s*HASH_END\s*\*\//gm, function (_, imports) {
438
- return imports.trim().replace(/"([^"]+?)":/gm, function (__, relativePath) {
444
+ return imports.trim().replace(/"([^"]+?)":/gm, function (all, relativePath) {
445
+ if (relativePath === '__VITE_PRELOAD__') return all;
439
446
  var absolutePath = path.resolve(path.dirname(id.split('?')[0]), relativePath);
440
- return "\"" + getComponentId(vite.normalizePath(absolutePath)) + "\":";
447
+ return "\"" + getComponentId(normalizePath(absolutePath)) + "\":";
441
448
  });
442
449
  });
443
450
  return {
@@ -529,17 +536,20 @@ function isDirectImportInServer(originalMod, currentMod, accModInfo) {
529
536
  });
530
537
  }
531
538
 
532
- function resolveModPath(modPath, dirname, retryExtension) {
533
- var absolutePath = '';
539
+ var RESOLVE_EXTENSIONS = ['', '.js', '.ts', '.jsx', '.tsx', '/index', '/index.js', '/index.ts', '/index.jsx', '/index.tsx']; // Resolve relative paths and aliases. Examples:
540
+ // - import {XYZ} from '~/components' => import {XYZ} from '<absolute>/src/components/index.ts'
541
+ // - import {XYZ} from '/src/component.client' => import {XYZ} from '<absolute>/src/component.client.jsx'`
534
542
 
535
- try {
536
- absolutePath = modPath.startsWith('.') ? vite.normalizePath(path.resolve(dirname, modPath)) : modPath;
537
- return vite.normalizePath(require.resolve(absolutePath + (retryExtension || '')));
538
- } catch (error) {
539
- if (!/\.[jt]sx?$/.test(absolutePath) && retryExtension !== '.tsx') {
540
- // Node cannot infer .[jt]sx extensions.
541
- // Append them here and retry a couple of times.
542
- return resolveModPath(absolutePath, dirname, retryExtension ? '.tsx' : '.jsx');
543
+ function resolveModPath(modPath, dirname) {
544
+ var extensions = /\.[jt]sx?$/.test(modPath) ? [''] : RESOLVE_EXTENSIONS;
545
+
546
+ for (var i = 0; i < extensions.length; i++) {
547
+ var extension = extensions[i];
548
+
549
+ try {
550
+ var absolutePath = modPath.startsWith('.') ? normalizePath(path.resolve(dirname, modPath)) : modPath;
551
+ return normalizePath(require.resolve(absolutePath + extension));
552
+ } catch (error) {// Do not throw, this is likely a virtual module or another exception
543
553
  }
544
554
  }
545
555
  }
@@ -551,7 +561,7 @@ function augmentModuleGraph(moduleGraph, id, code, root, resolveAlias) {
551
561
  var _id$split = id.split('?'),
552
562
  source = _id$split[0];
553
563
 
554
- var dirname = vite.normalizePath(path.dirname(source));
564
+ var dirname = normalizePath(path.dirname(source));
555
565
 
556
566
  var _parse2 = esModuleLexer.parse(code),
557
567
  rawImports = _parse2[0],
@@ -582,7 +592,7 @@ function augmentModuleGraph(moduleGraph, id, code, root, resolveAlias) {
582
592
 
583
593
  if (modPath && modPath.startsWith('/src/')) {
584
594
  // Vite default alias
585
- modPath = vite.normalizePath(path.join(root, modPath));
595
+ modPath = normalizePath(path.join(root, modPath));
586
596
  }
587
597
 
588
598
  var resolvedPath = resolveModPath(modPath, dirname);
@@ -168,6 +168,11 @@ function processModelChunk(request, id, model) {
168
168
  var row = serializeRowHeader('J', id) + json + '\n';
169
169
  return stringToChunk(row);
170
170
  }
171
+ function processReferenceChunk(request, id, reference) {
172
+ var json = stringify(reference);
173
+ var row = serializeRowHeader('J', id) + json + '\n';
174
+ return stringToChunk(row);
175
+ }
171
176
  function processModuleChunk(request, id, moduleMetaData) {
172
177
  var json = stringify(moduleMetaData);
173
178
  var row = serializeRowHeader('M', id) + json + '\n';
@@ -510,6 +515,7 @@ var startInlineScript = stringToPrecomputedChunk('<script>');
510
515
  var endInlineScript = stringToPrecomputedChunk('</script>');
511
516
  var startScriptSrc = stringToPrecomputedChunk('<script src="');
512
517
  var startModuleSrc = stringToPrecomputedChunk('<script type="module" src="');
518
+ var scriptIntegirty = stringToPrecomputedChunk('" integrity="');
513
519
  var endAsyncScript = stringToPrecomputedChunk('" async=""></script>');
514
520
 
515
521
  var textSeparator = stringToPrecomputedChunk('<!-- -->');
@@ -987,6 +993,10 @@ function getOrCreateServerContext(globalName) {
987
993
  return ContextRegistry[globalName];
988
994
  }
989
995
 
996
+ var PENDING = 0;
997
+ var COMPLETED = 1;
998
+ var ABORTED = 3;
999
+ var ERRORED = 4;
990
1000
  var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
991
1001
 
992
1002
  function defaultErrorHandler(error) {
@@ -997,7 +1007,8 @@ var OPEN = 0;
997
1007
  var CLOSING = 1;
998
1008
  var CLOSED = 2;
999
1009
  function createRequest(model, bundlerConfig, onError, context, identifierPrefix) {
1000
- var pingedSegments = [];
1010
+ var abortSet = new Set();
1011
+ var pingedTasks = [];
1001
1012
  var request = {
1002
1013
  status: OPEN,
1003
1014
  fatalError: null,
@@ -1006,7 +1017,8 @@ function createRequest(model, bundlerConfig, onError, context, identifierPrefix)
1006
1017
  cache: new Map(),
1007
1018
  nextChunkId: 0,
1008
1019
  pendingChunks: 0,
1009
- pingedSegments: pingedSegments,
1020
+ abortableTasks: abortSet,
1021
+ pingedTasks: pingedTasks,
1010
1022
  completedModuleChunks: [],
1011
1023
  completedJSONChunks: [],
1012
1024
  completedErrorChunks: [],
@@ -1022,8 +1034,8 @@ function createRequest(model, bundlerConfig, onError, context, identifierPrefix)
1022
1034
  };
1023
1035
  request.pendingChunks++;
1024
1036
  var rootContext = createRootContext(context);
1025
- var rootSegment = createSegment(request, model, rootContext);
1026
- pingedSegments.push(rootSegment);
1037
+ var rootTask = createTask(request, model, rootContext, abortSet);
1038
+ pingedTasks.push(rootTask);
1027
1039
  return request;
1028
1040
  }
1029
1041
 
@@ -1121,28 +1133,30 @@ function attemptResolveElement(type, key, ref, props) {
1121
1133
  throw new Error("Unsupported server component type: " + describeValueForErrorMessage(type));
1122
1134
  }
1123
1135
 
1124
- function pingSegment(request, segment) {
1125
- var pingedSegments = request.pingedSegments;
1126
- pingedSegments.push(segment);
1136
+ function pingTask(request, task) {
1137
+ var pingedTasks = request.pingedTasks;
1138
+ pingedTasks.push(task);
1127
1139
 
1128
- if (pingedSegments.length === 1) {
1140
+ if (pingedTasks.length === 1) {
1129
1141
  scheduleWork(function () {
1130
1142
  return performWork(request);
1131
1143
  });
1132
1144
  }
1133
1145
  }
1134
1146
 
1135
- function createSegment(request, model, context) {
1147
+ function createTask(request, model, context, abortSet) {
1136
1148
  var id = request.nextChunkId++;
1137
- var segment = {
1149
+ var task = {
1138
1150
  id: id,
1151
+ status: PENDING,
1139
1152
  model: model,
1140
1153
  context: context,
1141
1154
  ping: function () {
1142
- return pingSegment(request, segment);
1155
+ return pingTask(request, task);
1143
1156
  }
1144
1157
  };
1145
- return segment;
1158
+ abortSet.add(task);
1159
+ return task;
1146
1160
  }
1147
1161
 
1148
1162
  function serializeByValueID(id) {
@@ -1377,12 +1391,12 @@ function resolveModelToJSON(request, parent, key, value) {
1377
1391
  }
1378
1392
  } catch (x) {
1379
1393
  if (typeof x === 'object' && x !== null && typeof x.then === 'function') {
1380
- // Something suspended, we'll need to create a new segment and resolve it later.
1394
+ // Something suspended, we'll need to create a new task and resolve it later.
1381
1395
  request.pendingChunks++;
1382
- var newSegment = createSegment(request, value, getActiveContext());
1383
- var ping = newSegment.ping;
1396
+ var newTask = createTask(request, value, getActiveContext(), request.abortableTasks);
1397
+ var ping = newTask.ping;
1384
1398
  x.then(ping, ping);
1385
- return serializeByRefID(newSegment.id);
1399
+ return serializeByRefID(newTask.id);
1386
1400
  } else {
1387
1401
  logRecoverableError(request, x); // Something errored. We'll still send everything we have up until this point.
1388
1402
  // We'll replace this element with a lazy reference that throws on the client
@@ -1590,34 +1604,43 @@ function emitProviderChunk(request, id, contextName) {
1590
1604
  request.completedJSONChunks.push(processedChunk);
1591
1605
  }
1592
1606
 
1593
- function retrySegment(request, segment) {
1594
- switchContext(segment.context);
1607
+ function retryTask(request, task) {
1608
+ if (task.status !== PENDING) {
1609
+ // We completed this by other means before we had a chance to retry it.
1610
+ return;
1611
+ }
1612
+
1613
+ switchContext(task.context);
1595
1614
 
1596
1615
  try {
1597
- var _value3 = segment.model;
1616
+ var _value3 = task.model;
1598
1617
 
1599
1618
  while (typeof _value3 === 'object' && _value3 !== null && _value3.$$typeof === REACT_ELEMENT_TYPE) {
1600
1619
  // TODO: Concatenate keys of parents onto children.
1601
1620
  var element = _value3; // Attempt to render the server component.
1602
- // Doing this here lets us reuse this same segment if the next component
1621
+ // Doing this here lets us reuse this same task if the next component
1603
1622
  // also suspends.
1604
1623
 
1605
- segment.model = _value3;
1624
+ task.model = _value3;
1606
1625
  _value3 = attemptResolveElement(element.type, element.key, element.ref, element.props);
1607
1626
  }
1608
1627
 
1609
- var processedChunk = processModelChunk(request, segment.id, _value3);
1628
+ var processedChunk = processModelChunk(request, task.id, _value3);
1610
1629
  request.completedJSONChunks.push(processedChunk);
1630
+ request.abortableTasks.delete(task);
1631
+ task.status = COMPLETED;
1611
1632
  } catch (x) {
1612
1633
  if (typeof x === 'object' && x !== null && typeof x.then === 'function') {
1613
1634
  // Something suspended again, let's pick it back up later.
1614
- var ping = segment.ping;
1635
+ var ping = task.ping;
1615
1636
  x.then(ping, ping);
1616
1637
  return;
1617
1638
  } else {
1639
+ request.abortableTasks.delete(task);
1640
+ task.status = ERRORED;
1618
1641
  logRecoverableError(request, x); // This errored, we need to serialize this error to the
1619
1642
 
1620
- emitErrorChunk(request, segment.id, x);
1643
+ emitErrorChunk(request, task.id, x);
1621
1644
  }
1622
1645
  }
1623
1646
  }
@@ -1630,12 +1653,12 @@ function performWork(request) {
1630
1653
  prepareToUseHooksForRequest(request);
1631
1654
 
1632
1655
  try {
1633
- var pingedSegments = request.pingedSegments;
1634
- request.pingedSegments = [];
1656
+ var pingedTasks = request.pingedTasks;
1657
+ request.pingedTasks = [];
1635
1658
 
1636
- for (var i = 0; i < pingedSegments.length; i++) {
1637
- var segment = pingedSegments[i];
1638
- retrySegment(request, segment);
1659
+ for (var i = 0; i < pingedTasks.length; i++) {
1660
+ var task = pingedTasks[i];
1661
+ retryTask(request, task);
1639
1662
  }
1640
1663
 
1641
1664
  if (request.destination !== null) {
@@ -1651,6 +1674,15 @@ function performWork(request) {
1651
1674
  }
1652
1675
  }
1653
1676
 
1677
+ function abortTask(task, request, errorId) {
1678
+ task.status = ABORTED; // Instead of emitting an error per task.id, we emit a model that only
1679
+ // has a single value referencing the error.
1680
+
1681
+ var ref = serializeByValueID(errorId);
1682
+ var processedChunk = processReferenceChunk(request, task.id, ref);
1683
+ request.completedJSONChunks.push(processedChunk);
1684
+ }
1685
+
1654
1686
  function flushCompletedChunks(request, destination) {
1655
1687
  beginWriting();
1656
1688
 
@@ -1750,6 +1782,34 @@ function startFlowing(request, destination) {
1750
1782
  logRecoverableError(request, error);
1751
1783
  fatalError(request, error);
1752
1784
  }
1785
+ } // This is called to early terminate a request. It creates an error at all pending tasks.
1786
+
1787
+ function abort(request, reason) {
1788
+ try {
1789
+ var abortableTasks = request.abortableTasks;
1790
+
1791
+ if (abortableTasks.size > 0) {
1792
+ // We have tasks to abort. We'll emit one error row and then emit a reference
1793
+ // to that row from every row that's still remaining.
1794
+ var _error = reason === undefined ? new Error('The render was aborted by the server without a reason.') : reason;
1795
+
1796
+ logRecoverableError(request, _error);
1797
+ request.pendingChunks++;
1798
+ var errorId = request.nextChunkId++;
1799
+ emitErrorChunk(request, errorId, _error);
1800
+ abortableTasks.forEach(function (task) {
1801
+ return abortTask(task, request, errorId);
1802
+ });
1803
+ abortableTasks.clear();
1804
+ }
1805
+
1806
+ if (request.destination !== null) {
1807
+ flushCompletedChunks(request, request.destination);
1808
+ }
1809
+ } catch (error) {
1810
+ logRecoverableError(request, error);
1811
+ fatalError(request, error);
1812
+ }
1753
1813
  }
1754
1814
 
1755
1815
  function importServerContexts(contexts) {
@@ -1787,6 +1847,22 @@ function renderToReadableStream(model, options) {
1787
1847
  }
1788
1848
  }), {}, // Manifest, not used
1789
1849
  options ? options.onError : undefined, options ? options.context : undefined, options ? options.identifierPrefix : undefined);
1850
+
1851
+ if (options && options.signal) {
1852
+ var signal = options.signal;
1853
+
1854
+ if (signal.aborted) {
1855
+ abort(request, signal.reason);
1856
+ } else {
1857
+ var listener = function () {
1858
+ abort(request, signal.reason);
1859
+ signal.removeEventListener('abort', listener);
1860
+ };
1861
+
1862
+ signal.addEventListener('abort', listener);
1863
+ }
1864
+ }
1865
+
1790
1866
  var stream = new ReadableStream({
1791
1867
  type: 'bytes',
1792
1868
  start: function (controller) {