vike 0.4.266 → 0.4.267-commit-7884d91

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 (159) hide show
  1. package/dist/client/runtime-client-routing/createPageContextClient.d.ts +4 -0
  2. package/dist/client/runtime-client-routing/getGlobalContextClientInternal.d.ts +4 -0
  3. package/dist/client/runtime-client-routing/getPageContextFromHooks.d.ts +22 -2
  4. package/dist/client/runtime-client-routing/getPageContextFromHooks.js +4 -5
  5. package/dist/client/runtime-client-routing/history.d.ts +19 -19
  6. package/dist/client/runtime-client-routing/history.js +89 -83
  7. package/dist/client/runtime-client-routing/renderPageClient.d.ts +472 -9
  8. package/dist/client/runtime-client-routing/renderPageClient.js +12 -11
  9. package/dist/client/runtime-client-routing/setScrollPosition.js +6 -5
  10. package/dist/client/runtime-client-routing/streamedValues.d.ts +5 -0
  11. package/dist/client/runtime-client-routing/streamedValues.js +23 -0
  12. package/dist/client/runtime-server-routing/createPageContextClient.d.ts +4 -0
  13. package/dist/client/runtime-server-routing/entry.js +1 -1
  14. package/dist/client/runtime-server-routing/getGlobalContextClientInternal.d.ts +4 -0
  15. package/dist/client/shared/getGlobalContextClientInternalShared.d.ts +4 -0
  16. package/dist/client/shared/getJsonSerializedInHtml.d.ts +2 -2
  17. package/dist/client/shared/getJsonSerializedInHtml.js +9 -6
  18. package/dist/client/shared/streamedValues/asyncIterable.d.ts +4 -0
  19. package/dist/client/shared/streamedValues/asyncIterable.js +26 -0
  20. package/dist/client/shared/streamedValues/lines.d.ts +11 -0
  21. package/dist/client/shared/streamedValues/lines.js +19 -0
  22. package/dist/client/shared/streamedValues/promise.d.ts +4 -0
  23. package/dist/client/shared/streamedValues/promise.js +19 -0
  24. package/dist/client/shared/streamedValues/readableStream.d.ts +4 -0
  25. package/dist/client/shared/streamedValues/readableStream.js +44 -0
  26. package/dist/client/shared/streamedValues/registry.d.ts +21 -0
  27. package/dist/client/shared/streamedValues/registry.js +40 -0
  28. package/dist/client/shared/streamedValues.d.ts +7 -0
  29. package/dist/client/shared/streamedValues.js +82 -0
  30. package/dist/node/api/resolveViteConfigUser.js +2 -2
  31. package/dist/node/prerender/runPrerender.d.ts +12 -4
  32. package/dist/node/prerender/runPrerender.js +71 -15
  33. package/dist/node/vite/assertEnvVite.js +2 -2
  34. package/dist/node/vite/index.js +2 -0
  35. package/dist/node/vite/plugins/build/handleAssetsManifest.js +8 -3
  36. package/dist/node/vite/plugins/build/pluginBuildApp.js +25 -26
  37. package/dist/node/vite/plugins/build/pluginBuildConfig.d.ts +2 -2
  38. package/dist/node/vite/plugins/build/pluginBuildConfig.js +24 -16
  39. package/dist/node/vite/plugins/build/pluginDistFileNames.js +70 -50
  40. package/dist/node/vite/plugins/build/pluginEnvironmentEntries.d.ts +6 -0
  41. package/dist/node/vite/plugins/build/pluginEnvironmentEntries.js +71 -0
  42. package/dist/node/vite/plugins/build/pluginSuppressRollupWarning.js +19 -17
  43. package/dist/node/vite/plugins/pluginCommon.js +9 -6
  44. package/dist/node/vite/plugins/pluginDev/logSkillHint.js +6 -4
  45. package/dist/node/vite/plugins/pluginDev/optimizeDeps.js +1 -1
  46. package/dist/node/vite/plugins/pluginReplaceConstantsGlobalThis.js +6 -4
  47. package/dist/node/vite/plugins/pluginUniversalDeploy.js +3 -2
  48. package/dist/node/vite/plugins/pluginVirtualFiles/generateVirtualFileGlobalEntry.d.ts +2 -1
  49. package/dist/node/vite/plugins/pluginVirtualFiles/generateVirtualFileGlobalEntry.js +29 -12
  50. package/dist/node/vite/plugins/pluginVirtualFiles/generateVirtualFileGlobalEntryWithOldDesign.js +3 -2
  51. package/dist/node/vite/plugins/pluginVirtualFiles/generateVirtualFilePageEntry.js +7 -7
  52. package/dist/node/vite/plugins/pluginVirtualFiles/getConfigValueSourcesRelevant.d.ts +7 -5
  53. package/dist/node/vite/plugins/pluginVirtualFiles/getConfigValueSourcesRelevant.js +4 -10
  54. package/dist/node/vite/plugins/pluginVirtualFiles.js +20 -0
  55. package/dist/node/vite/shared/addSsrMiddleware.js +13 -1
  56. package/dist/node/vite/shared/getAssetsDir.d.ts +3 -2
  57. package/dist/node/vite/shared/getAssetsDir.js +3 -3
  58. package/dist/node/vite/shared/isViteCli.d.ts +3 -3
  59. package/dist/node/vite/shared/isViteCli.js +80 -84
  60. package/dist/node/vite/shared/isViteServerSide.js +2 -7
  61. package/dist/node/vite/shared/resolveVikeConfigInternal/getPlusFiles.d.ts +2 -2
  62. package/dist/node/vite/shared/resolveVikeConfigInternal/getPlusFiles.js +3 -3
  63. package/dist/node/vite/shared/resolveVikeConfigInternal/loadFileAtConfigTime.d.ts +4 -4
  64. package/dist/node/vite/shared/resolveVikeConfigInternal/loadFileAtConfigTime.js +9 -9
  65. package/dist/node/vite/shared/resolveVikeConfigInternal/metaBuiltIn.d.ts +1 -1
  66. package/dist/node/vite/shared/resolveVikeConfigInternal/metaBuiltIn.js +12 -6
  67. package/dist/node/vite/shared/resolveVikeConfigInternal/pointerImports.d.ts +3 -1
  68. package/dist/node/vite/shared/resolveVikeConfigInternal/pointerImports.js +18 -46
  69. package/dist/node/vite/shared/resolveVikeConfigInternal/transpileAndExecuteFile.d.ts +3 -3
  70. package/dist/node/vite/shared/resolveVikeConfigInternal/transpileAndExecuteFile.js +333 -212
  71. package/dist/node/vite/shared/resolveVikeConfigInternal.d.ts +4 -1
  72. package/dist/node/vite/shared/resolveVikeConfigInternal.js +97 -26
  73. package/dist/server/runtime/globalContext.d.ts +20 -0
  74. package/dist/server/runtime/renderPageServer/analyzePage.js +3 -3
  75. package/dist/server/runtime/renderPageServer/createHttpResponse.d.ts +20 -7
  76. package/dist/server/runtime/renderPageServer/createHttpResponse.js +34 -15
  77. package/dist/server/runtime/renderPageServer/createPageContextServer.d.ts +4 -0
  78. package/dist/server/runtime/renderPageServer/csp.d.ts +2 -1
  79. package/dist/server/runtime/renderPageServer/csp.js +2 -1
  80. package/dist/server/runtime/renderPageServer/execHookOnError.js +1 -1
  81. package/dist/server/runtime/renderPageServer/execHookOnRenderHtml.d.ts +9 -0
  82. package/dist/server/runtime/renderPageServer/execHookOnRenderHtml.js +17 -5
  83. package/dist/server/runtime/renderPageServer/getHttpResponseBody.d.ts +2 -2
  84. package/dist/server/runtime/renderPageServer/getHttpResponseBody.js +17 -2
  85. package/dist/server/runtime/renderPageServer/getPageContextJson.d.ts +8 -0
  86. package/dist/server/runtime/renderPageServer/getPageContextJson.js +47 -0
  87. package/dist/server/runtime/renderPageServer/handleErrorWithoutErrorPage.d.ts +2 -0
  88. package/dist/server/runtime/renderPageServer/handleErrorWithoutErrorPage.js +1 -1
  89. package/dist/server/runtime/renderPageServer/headersResponse.d.ts +11 -2
  90. package/dist/server/runtime/renderPageServer/headersResponse.js +22 -2
  91. package/dist/server/runtime/renderPageServer/html/injectAssets/getHtmlTags.js +5 -4
  92. package/dist/server/runtime/renderPageServer/html/injectAssets.d.ts +3 -2
  93. package/dist/server/runtime/renderPageServer/html/injectAssets.js +7 -1
  94. package/dist/server/runtime/renderPageServer/html/renderHtml.js +4 -2
  95. package/dist/server/runtime/renderPageServer/html/serializeContext.d.ts +5 -1
  96. package/dist/server/runtime/renderPageServer/html/serializeContext.js +12 -9
  97. package/dist/server/runtime/renderPageServer/html/stream.d.ts +13 -6
  98. package/dist/server/runtime/renderPageServer/html/stream.js +121 -31
  99. package/dist/server/runtime/renderPageServer/html/streamedValuesHtml.d.ts +30 -0
  100. package/dist/server/runtime/renderPageServer/html/streamedValuesHtml.js +92 -0
  101. package/dist/server/runtime/renderPageServer/loadPageConfigsLazyServerSide.d.ts +4 -0
  102. package/dist/server/runtime/renderPageServer/loadPageConfigsLazyServerSide.js +5 -1
  103. package/dist/server/runtime/renderPageServer/loadPageContextEnvironments.d.ts +15 -0
  104. package/dist/server/runtime/renderPageServer/loadPageContextEnvironments.js +61 -0
  105. package/dist/server/runtime/renderPageServer/renderPageServerAfterRoute.d.ts +314 -1
  106. package/dist/server/runtime/renderPageServer/renderPageServerAfterRoute.js +21 -12
  107. package/dist/server/runtime/renderPageServer/streamedValues/asyncIterable.d.ts +4 -0
  108. package/dist/server/runtime/renderPageServer/streamedValues/asyncIterable.js +12 -0
  109. package/dist/server/runtime/renderPageServer/streamedValues/lines.d.ts +10 -0
  110. package/dist/server/runtime/renderPageServer/streamedValues/lines.js +49 -0
  111. package/dist/server/runtime/renderPageServer/streamedValues/promise.d.ts +4 -0
  112. package/dist/server/runtime/renderPageServer/streamedValues/promise.js +14 -0
  113. package/dist/server/runtime/renderPageServer/streamedValues/pump.d.ts +10 -0
  114. package/dist/server/runtime/renderPageServer/streamedValues/pump.js +67 -0
  115. package/dist/server/runtime/renderPageServer/streamedValues/readableStream.d.ts +4 -0
  116. package/dist/server/runtime/renderPageServer/streamedValues/readableStream.js +12 -0
  117. package/dist/server/runtime/renderPageServer/streamedValues/registry.d.ts +28 -0
  118. package/dist/server/runtime/renderPageServer/streamedValues/registry.js +33 -0
  119. package/dist/server/runtime/renderPageServer.d.ts +4 -0
  120. package/dist/server/runtime/renderPageServer.js +17 -8
  121. package/dist/shared-server-client/createGlobalContextShared.d.ts +8 -0
  122. package/dist/shared-server-client/createGlobalContextShared.js +2 -1
  123. package/dist/shared-server-client/getPageContextPublicShared.js +0 -2
  124. package/dist/shared-server-client/getPageFiles/parseVirtualFileExportsGlobalEntry.d.ts +8 -0
  125. package/dist/shared-server-client/getPageFiles/parseVirtualFileExportsGlobalEntry.js +17 -7
  126. package/dist/shared-server-client/hooks/execHook.d.ts +1 -1
  127. package/dist/shared-server-client/hooks/execHook.js +2 -2
  128. package/dist/shared-server-client/route/abort.d.ts +1 -1
  129. package/dist/shared-server-client/route/abort.js +4 -2
  130. package/dist/shared-server-client/streamedValues.d.ts +22 -0
  131. package/dist/shared-server-client/streamedValues.js +24 -0
  132. package/dist/shared-server-node/vike-environments.d.ts +4 -0
  133. package/dist/shared-server-node/vike-environments.js +10 -0
  134. package/dist/shared-server-node/virtualFileId.d.ts +7 -5
  135. package/dist/shared-server-node/virtualFileId.js +42 -42
  136. package/dist/types/Config.d.ts +9 -1
  137. package/dist/types/PageConfig.d.ts +13 -5
  138. package/dist/types/PageContext.d.ts +18 -1
  139. package/dist/utils/PROJECT_VERSION.d.ts +1 -1
  140. package/dist/utils/PROJECT_VERSION.js +1 -1
  141. package/dist/utils/assertNodeVersion.d.ts +2 -0
  142. package/dist/utils/assertNodeVersion.js +4 -1
  143. package/dist/utils/assertViteVersion.d.ts +1 -3
  144. package/dist/utils/assertViteVersion.js +6 -9
  145. package/dist/utils/debug.d.ts +1 -1
  146. package/dist/utils/debug.js +1 -1
  147. package/dist/utils/deepEqual.d.ts +2 -1
  148. package/dist/utils/deepEqual.js +21 -6
  149. package/dist/utils/getContentTypeFromUrl.d.ts +2 -0
  150. package/dist/utils/getContentTypeFromUrl.js +39 -0
  151. package/dist/utils/injectRollupInputs.d.ts +2 -2
  152. package/dist/utils/injectRollupInputs.js +2 -2
  153. package/dist/utils/isDev.js +2 -7
  154. package/dist/utils/parseUrl-extras.js +4 -0
  155. package/dist/utils/requireResolve.d.ts +0 -6
  156. package/dist/utils/requireResolve.js +0 -8
  157. package/package.json +9 -10
  158. package/dist/shared-server-client/addIs404ToPageProps.d.ts +0 -2
  159. package/dist/shared-server-client/addIs404ToPageProps.js +0 -17
@@ -16,6 +16,8 @@ export { isStreamReadableNode };
16
16
  export { getStreamName };
17
17
  export { inferStreamName };
18
18
  export { streamReadableWebToString };
19
+ export { streamReadableWebToBytes };
20
+ export { awaitFirstChunk };
19
21
  export { streamPipeNodeToString };
20
22
  export { isStreamWritableWeb };
21
23
  export { isStreamWritableNode };
@@ -74,9 +76,60 @@ async function streamReadableWebToString(readableWeb) {
74
76
  str += getClosingChunk();
75
77
  return str;
76
78
  }
79
+ async function streamReadableWebToBytes(readableWeb) {
80
+ const reader = readableWeb.getReader();
81
+ const chunks = [];
82
+ while (true) {
83
+ const { done, value } = await reader.read();
84
+ if (done)
85
+ break;
86
+ assertUsage(value instanceof Uint8Array, `The stream emitted a chunk that isn't a Uint8Array: ${String(value)}`);
87
+ chunks.push(value);
88
+ }
89
+ const bytes = new Uint8Array(chunks.reduce((len, chunk) => len + chunk.length, 0));
90
+ let offset = 0;
91
+ for (const chunk of chunks) {
92
+ bytes.set(chunk, offset);
93
+ offset += chunk.length;
94
+ }
95
+ return bytes;
96
+ }
97
+ // Resolves after the first chunk (rejects if the stream errors before), then reads on demand
98
+ async function awaitFirstChunk(stream, onErrorWhileStreaming) {
99
+ const reader = stream.getReader();
100
+ const firstChunk = await reader.read();
101
+ const streamStarted = new ReadableStream({
102
+ start(controller) {
103
+ if (firstChunk.done)
104
+ controller.close();
105
+ else
106
+ controller.enqueue(firstChunk.value);
107
+ },
108
+ async pull(controller) {
109
+ let chunk;
110
+ try {
111
+ chunk = await reader.read();
112
+ }
113
+ catch (err) {
114
+ onErrorWhileStreaming(err);
115
+ controller.error(err);
116
+ return;
117
+ }
118
+ if (chunk.done)
119
+ controller.close();
120
+ else
121
+ controller.enqueue(chunk.value);
122
+ },
123
+ cancel(reason) {
124
+ return reader.cancel(reason);
125
+ },
126
+ });
127
+ return streamStarted;
128
+ }
77
129
  async function stringToStreamReadableNode(str) {
78
130
  const { Readable } = await loadStreamNodeModule();
79
- return Readable.from(str);
131
+ // Readable.from() iterates a Uint8Array byte by byte
132
+ return Readable.from(typeof str === 'string' ? str : [str]);
80
133
  }
81
134
  async function streamReadableWebToStreamReadableNode(stream) {
82
135
  const { Readable } = await loadStreamNodeModule();
@@ -156,16 +209,19 @@ function streamPipeWebToString(streamPipeWeb) {
156
209
  return promise;
157
210
  }
158
211
  async function getStreamReadableNode(htmlRender) {
159
- if (typeof htmlRender === 'string') {
212
+ if (typeof htmlRender === 'string' || htmlRender instanceof Uint8Array) {
160
213
  return stringToStreamReadableNode(htmlRender);
161
214
  }
162
215
  if (isStreamReadableNode(htmlRender)) {
163
216
  return htmlRender;
164
217
  }
218
+ if (isStreamReadableWeb(htmlRender)) {
219
+ return streamReadableWebToStreamReadableNode(htmlRender);
220
+ }
165
221
  return null;
166
222
  }
167
223
  function getStreamReadableWeb(htmlRender) {
168
- if (typeof htmlRender === 'string') {
224
+ if (typeof htmlRender === 'string' || htmlRender instanceof Uint8Array) {
169
225
  return stringToStreamReadableWeb(htmlRender);
170
226
  }
171
227
  if (isStreamReadableWeb(htmlRender)) {
@@ -181,13 +237,14 @@ function getStreamReadableWeb(htmlRender) {
181
237
  return null;
182
238
  }
183
239
  function pipeToStreamWritableWeb(htmlRender, writable) {
184
- if (typeof htmlRender === 'string') {
240
+ if (typeof htmlRender === 'string' || htmlRender instanceof Uint8Array) {
185
241
  const streamPipeWeb = stringToStreamPipeWeb(htmlRender);
186
242
  streamPipeWeb(writable);
187
243
  return true;
188
244
  }
189
245
  if (isStreamReadableWeb(htmlRender)) {
190
- htmlRender.pipeTo(writable);
246
+ // pipeTo() propagates a failure of either side to the other side
247
+ htmlRender.pipeTo(writable).catch(() => { });
191
248
  return true;
192
249
  }
193
250
  if (isStreamPipeWeb(htmlRender)) {
@@ -203,23 +260,30 @@ function pipeToStreamWritableWeb(htmlRender, writable) {
203
260
  assert(false);
204
261
  }
205
262
  function pipeToStreamWritableNode(htmlRender, writable) {
206
- if (typeof htmlRender === 'string') {
263
+ if (typeof htmlRender === 'string' || htmlRender instanceof Uint8Array) {
207
264
  const streamPipeNode = stringToStreamPipeNode(htmlRender);
208
265
  streamPipeNode(writable);
209
266
  return true;
210
267
  }
211
- if (isStreamReadableNode(htmlRender)) {
212
- htmlRender.pipe(writable);
213
- return true;
214
- }
215
268
  if (isStreamPipeNode(htmlRender)) {
216
269
  const streamPipeNode = getStreamPipeNode(htmlRender);
217
270
  assert(streamPipeNode);
218
271
  streamPipeNode(writable);
219
272
  return true;
220
273
  }
221
- if (isStreamReadableWeb(htmlRender)) {
222
- streamReadableWebToStreamReadableNode(htmlRender).then((s) => s.pipe(writable));
274
+ if (isStreamReadableNode(htmlRender) || isStreamReadableWeb(htmlRender)) {
275
+ getStreamReadableNode(htmlRender).then(async (readable) => {
276
+ assert(readable);
277
+ const { pipeline } = await loadStreamNodeModule();
278
+ // pipeline() throws if the writable is already destroyed (e.g. the client left before the first chunk)
279
+ if (writable.destroyed)
280
+ return readable.destroy();
281
+ // Unlike pipe(), pipeline() destroys the readable if the writable closes early, and the writable if the readable errors or closes before its end
282
+ pipeline(readable, writable, () => { });
283
+ // E.g. compression() holds the writes until flush()
284
+ const w = writable;
285
+ readable.on('data', () => w.flush?.());
286
+ });
223
287
  return true;
224
288
  }
225
289
  if (isStreamPipeWeb(htmlRender)) {
@@ -228,7 +292,7 @@ function pipeToStreamWritableNode(htmlRender, writable) {
228
292
  checkType(htmlRender);
229
293
  assert(false);
230
294
  }
231
- async function processStream(streamOriginal, { injectStringAtBegin, injectStringAfterFirstChunk, injectStringAtEnd, onErrorWhileStreaming, enableEagerStreaming, }) {
295
+ async function processStream(streamOriginal, { injectStringAtBegin, injectStringAfterFirstChunk, injectStringAtEnd, onErrorWhileStreaming, enableEagerStreaming, onCancel, }) {
232
296
  const buffer = [];
233
297
  let streamOriginalHasStartedEmitting = false;
234
298
  let streamOriginalEnded = false;
@@ -275,6 +339,8 @@ async function processStream(streamOriginal, { injectStringAtBegin, injectString
275
339
  resolveReadyToWrite();
276
340
  },
277
341
  onError(err) {
342
+ // The HTML won't end: its streamed pageContext values won't be sent
343
+ onCancel();
278
344
  if (!promiseHasResolved) {
279
345
  reject(err);
280
346
  }
@@ -303,7 +369,10 @@ async function processStream(streamOriginal, { injectStringAtBegin, injectString
303
369
  streamOriginalEnded = true;
304
370
  });
305
371
  if (injectStringAtEnd && !isCancel) {
306
- const injectedChunk = await injectStringAtEnd();
372
+ const injectedChunk = await injectStringAtEnd((html) => {
373
+ writeStream(html);
374
+ flushStream();
375
+ });
307
376
  writeStream(injectedChunk);
308
377
  }
309
378
  await promiseReadyToWrite; // E.g. if the user calls the pipe wrapper after the original writable has ended
@@ -326,6 +395,7 @@ async function processStream(streamOriginal, { injectStringAtBegin, injectString
326
395
  onFlush() {
327
396
  flushStream();
328
397
  },
398
+ onCancel,
329
399
  });
330
400
  wrapperCreated = true;
331
401
  flushBuffer(); // In case onReadyToWrite() was already called (the flushBuffer() of onReadyToWrite() wasn't called because `wrapperCreated === false`)
@@ -388,7 +458,7 @@ async function processStream(streamOriginal, { injectStringAtBegin, injectString
388
458
  return !enableEagerStreaming && !streamOriginalHasStartedEmitting;
389
459
  }
390
460
  }
391
- async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onFlush, onReadyToWrite, }) {
461
+ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onFlush, onReadyToWrite, onCancel, }) {
392
462
  if (isStreamFromReactStreamingPackage(streamOriginal)) {
393
463
  debug(`onRenderHtml() hook returned ${pc.cyan('react-streaming')} result`);
394
464
  const stream = getStreamOfReactStreamingPackage(streamOriginal);
@@ -400,6 +470,16 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
400
470
  const pipeProxy = (writable_) => {
401
471
  writableOriginal = writable_;
402
472
  debug('original Node.js Writable received');
473
+ // Let the source know when the response closes early (no-op once it has ended)
474
+ const onClose = () => {
475
+ if (!hasEnded)
476
+ onCancel();
477
+ writableProxy.destroy();
478
+ };
479
+ if (writableOriginal.destroyed)
480
+ onClose();
481
+ else
482
+ writableOriginal.on('close', onClose);
403
483
  onReadyToWrite();
404
484
  if (hasEnded) {
405
485
  // onReadyToWrite() already wrote everything; we can close the stream right away
@@ -463,6 +543,11 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
463
543
  const pipeProxy = (writableOriginal) => {
464
544
  writerOriginal = writableOriginal.getWriter();
465
545
  debug('original Web Writable received');
546
+ // Let the source know when the response closes early
547
+ writerOriginal.closed.catch((err) => {
548
+ onCancel();
549
+ readerProxy?.cancel(err);
550
+ });
466
551
  (async () => {
467
552
  // CloudFlare Workers does not implement `ready` property
468
553
  // - https://github.com/vuejs/vue-next/issues/4287
@@ -480,7 +565,7 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
480
565
  stampPipe(pipeProxy, 'web-stream');
481
566
  const writeChunk = (chunk) => {
482
567
  assert(writerOriginal);
483
- writerOriginal.write(encodeForWebStream(chunk));
568
+ writerOriginal.write(encodeForWebStream(chunk)).catch(() => { });
484
569
  debugWithChunk('data written (Web Writable)', chunk);
485
570
  };
486
571
  // Web Streams have compression built-in
@@ -491,10 +576,11 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
491
576
  const endStream = () => {
492
577
  hasEnded = true;
493
578
  if (writerOriginal) {
494
- writerOriginal.close();
579
+ writerOriginal.close().catch(() => { });
495
580
  }
496
581
  };
497
582
  let writableProxy;
583
+ let readerProxy;
498
584
  if (typeof ReadableStream !== 'function') {
499
585
  writableProxy = new WritableStream({
500
586
  write(chunk) {
@@ -513,7 +599,8 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
513
599
  else {
514
600
  const { readable, writable } = new TransformStream();
515
601
  writableProxy = writable;
516
- handleReadableWeb(readable, {
602
+ readerProxy = readable.getReader();
603
+ handleReadableWeb(readerProxy, {
517
604
  onData,
518
605
  onError(err) {
519
606
  onError(err);
@@ -531,7 +618,7 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
531
618
  }
532
619
  if (isStreamReadableWeb(streamOriginal)) {
533
620
  debug('onRenderHtml() hook returned Web Readable');
534
- const readableOriginal = streamOriginal;
621
+ const readerOriginal = streamOriginal.getReader();
535
622
  let isClosed = false;
536
623
  let isCancel = false;
537
624
  const closeStream = async () => {
@@ -548,7 +635,7 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
548
635
  start(controller) {
549
636
  controllerProxy = controller;
550
637
  onReadyToWrite();
551
- handleReadableWeb(readableOriginal, {
638
+ handleReadableWeb(readerOriginal, {
552
639
  onData,
553
640
  onError(err) {
554
641
  onError(err);
@@ -559,18 +646,16 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
559
646
  },
560
647
  });
561
648
  },
562
- async cancel(...args) {
649
+ async cancel(reason) {
563
650
  debug('stream cancelled');
564
651
  isCancel = true;
565
- await readableOriginal.cancel(...args);
566
- // If readableOriginal has implemented readableOriginal.cancel() then the onEnd() callback and therefore closeStream() may already have been called at this point
567
- await closeStream();
652
+ onCancel();
653
+ // Ends handleReadableWeb() which then calls closeStream()
654
+ await readerOriginal.cancel(reason);
568
655
  },
569
656
  });
570
657
  const writeChunk = (chunk) => {
571
- if (!isCancel &&
572
- // If readableOriginal doesn't implement readableOriginal.cancel() then it may still emit data after we close the stream. We therefore need to check whether the steam is closed.
573
- !isClosed) {
658
+ if (!isCancel && !isClosed) {
574
659
  controllerProxy.enqueue(encodeForWebStream(chunk));
575
660
  debugWithChunk('data written (Web Readable)', chunk);
576
661
  }
@@ -603,6 +688,12 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
603
688
  readableProxy.push(null);
604
689
  };
605
690
  const readableProxy = new Readable({ read() { } });
691
+ // Destroy the source when the consumer closes early
692
+ readableProxy.once('close', () => {
693
+ if (!readableProxy.readableEnded)
694
+ onCancel();
695
+ readableOriginal.destroy();
696
+ });
606
697
  onReadyToWrite();
607
698
  readableOriginal.on('data', (chunk) => {
608
699
  onData(chunk);
@@ -622,8 +713,7 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
622
713
  }
623
714
  assert(false);
624
715
  }
625
- async function handleReadableWeb(readable, { onData, onError, onEnd, }) {
626
- const reader = readable.getReader();
716
+ async function handleReadableWeb(reader, { onData, onError, onEnd, }) {
627
717
  while (true) {
628
718
  let result;
629
719
  try {
@@ -776,8 +866,8 @@ function encodeForWebStream(thing) {
776
866
  // Because of Cloudflare Workers, we cannot statically import the `stream` module, instead we dynamically import it.
777
867
  async function loadStreamNodeModule() {
778
868
  const streamModule = (await import_('stream')).default;
779
- const { Readable, Writable } = streamModule;
780
- return { Readable, Writable };
869
+ const { Readable, Writable, pipeline } = streamModule;
870
+ return { Readable, Writable, pipeline };
781
871
  }
782
872
  function getStreamName(kind, type) {
783
873
  let typeName = capitalizeFirstLetter(type);
@@ -0,0 +1,30 @@
1
+ export { serializePageContextHtml };
2
+ export { getStreamedValuesHtml };
3
+ export { writeStreamedValuesHtmlAtStreamEnd };
4
+ export { cancelStreamedValuesHtml };
5
+ export { getStreamedValuesLinesPrerendered };
6
+ export type { PageContextStreamedValuesHtml };
7
+ import { type PageContextSerialization } from './serializeContext.js';
8
+ import type { PageContextCreatedServer } from '../createPageContextServer.js';
9
+ import type { StreamFromReactStreamingPackage } from './stream/react-streaming.js';
10
+ import { type PageContextCspNonce } from '../csp.js';
11
+ import '../../../assertEnvServer.js';
12
+ type StreamedValuesHtml = {
13
+ done: Promise<void>;
14
+ cancel: () => void;
15
+ /** The `<script>` tags not sent yet */
16
+ pending: string[];
17
+ /** Set once the HTML stream is ending */
18
+ writeHtml: null | ((html: string) => void);
19
+ /** Pre-rendering: all lines */
20
+ lines: null | string[];
21
+ };
22
+ type PageContextStreamedValuesHtml = PageContextCreatedServer & PageContextCspNonce & {
23
+ _requestId: number;
24
+ _streamedValuesHtml?: StreamedValuesHtml;
25
+ };
26
+ declare function serializePageContextHtml(pageContext: PageContextStreamedValuesHtml & PageContextSerialization, streamFromReactStreamingPackage: null | StreamFromReactStreamingPackage): string;
27
+ declare function getStreamedValuesHtml(pageContext: PageContextStreamedValuesHtml): Promise<null | string>;
28
+ declare function writeStreamedValuesHtmlAtStreamEnd(pageContext: PageContextStreamedValuesHtml, htmlEnd: string, writeHtml: (html: string) => void): Promise<string>;
29
+ declare function cancelStreamedValuesHtml(pageContext: PageContextStreamedValuesHtml): void;
30
+ declare function getStreamedValuesLinesPrerendered(pageContext: PageContextStreamedValuesHtml): Promise<null | string[]>;
@@ -0,0 +1,92 @@
1
+ // The streamed pageContext values (see shared-server-client/streamedValues.ts) of the HTML's
2
+ // `<script id="vike_pageContext">`: each line is sent as a `<script>` that pushes it to `self.__vike_streamed` (read by
3
+ // Vike's client runtime, see client/shared/streamedValues.ts).
4
+ // - HTML stream of react-streaming: the lines are injected into the stream as they're produced.
5
+ // - HTML stream: the lines produced while the stream is running are sent after it ends, and the lines produced
6
+ // afterwards are sent as they're produced; the HTML ends once all values have ended.
7
+ // - HTML string: the lines are appended to the HTML once all values have ended.
8
+ // - Pre-rendering: the lines are also collected for `index.pageContext.json`, so that the values are read once.
9
+ export { serializePageContextHtml };
10
+ export { getStreamedValuesHtml };
11
+ export { writeStreamedValuesHtmlAtStreamEnd };
12
+ export { cancelStreamedValuesHtml };
13
+ export { getStreamedValuesLinesPrerendered };
14
+ import { assert } from '../../../../utils/assert.js';
15
+ import { pumpStreamedValues } from '../streamedValues/pump.js';
16
+ import { getPageContextClientSerialized } from './serializeContext.js';
17
+ import { inferNonceAttr } from '../csp.js';
18
+ import '../../../assertEnvServer.js';
19
+ // The pageContext of `<script id="vike_pageContext">`, as `[pageContext]` if it has streamed values (which start streaming)
20
+ function serializePageContextHtml(pageContext, streamFromReactStreamingPackage) {
21
+ const { pageContextSerialized, streamedValues } = getPageContextClientSerialized(pageContext, true);
22
+ if (streamedValues.length === 0)
23
+ return pageContextSerialized;
24
+ // The pageContext is serialized once per HTML
25
+ assert(!pageContext._streamedValuesHtml);
26
+ const { isPrerendering } = pageContext;
27
+ const write = (line) => {
28
+ streamedValuesHtml.lines?.push(line);
29
+ const script = getScript(line, pageContext);
30
+ if (streamedValuesHtml.writeHtml) {
31
+ streamedValuesHtml.writeHtml(script);
32
+ }
33
+ else if (streamFromReactStreamingPackage && !streamFromReactStreamingPackage.hasStreamEnded()) {
34
+ streamFromReactStreamingPackage.injectToStream(script, { flush: true });
35
+ }
36
+ else {
37
+ streamedValuesHtml.pending.push(script);
38
+ }
39
+ };
40
+ const streamedValuesHtml = {
41
+ // A pre-rendered page can't have a failed value
42
+ ...pumpStreamedValues(pageContext, streamedValues, write, { failFast: isPrerendering }),
43
+ pending: [],
44
+ writeHtml: null,
45
+ lines: isPrerendering ? [] : null,
46
+ };
47
+ // Pre-rendering: the error is thrown by getStreamedValuesLinesPrerendered()
48
+ streamedValuesHtml.done.catch(() => { });
49
+ pageContext._streamedValuesHtml = streamedValuesHtml;
50
+ return `[${pageContextSerialized}]`;
51
+ }
52
+ // HTML string
53
+ async function getStreamedValuesHtml(pageContext) {
54
+ const streamedValuesHtml = pageContext._streamedValuesHtml;
55
+ if (!streamedValuesHtml)
56
+ return null;
57
+ await streamedValuesHtml.done.catch(() => { });
58
+ return streamedValuesHtml.pending.join('');
59
+ }
60
+ // HTML stream: `htmlEnd` is what Vike appends after the HTML stream ended. The lines are sent before `</body>`.
61
+ async function writeStreamedValuesHtmlAtStreamEnd(pageContext, htmlEnd, writeHtml) {
62
+ const streamedValuesHtml = pageContext._streamedValuesHtml;
63
+ if (!streamedValuesHtml)
64
+ return htmlEnd;
65
+ let i = htmlEnd.lastIndexOf('</body>');
66
+ if (i === -1)
67
+ i = htmlEnd.length;
68
+ writeHtml(htmlEnd.slice(0, i) + streamedValuesHtml.pending.join(''));
69
+ streamedValuesHtml.writeHtml = writeHtml;
70
+ await streamedValuesHtml.done.catch(() => { });
71
+ return htmlEnd.slice(i);
72
+ }
73
+ // The HTML response was cancelled (e.g. the user closed the tab) or failed
74
+ function cancelStreamedValuesHtml(pageContext) {
75
+ pageContext._streamedValuesHtml?.cancel();
76
+ }
77
+ // Pre-rendering: the lines for `index.pageContext.json` (the values are read once, while rendering the HTML)
78
+ async function getStreamedValuesLinesPrerendered(pageContext) {
79
+ const streamedValuesHtml = pageContext._streamedValuesHtml;
80
+ if (!streamedValuesHtml)
81
+ return null;
82
+ await streamedValuesHtml.done;
83
+ assert(streamedValuesHtml.lines);
84
+ return streamedValuesHtml.lines;
85
+ }
86
+ function getScript(line, pageContext) {
87
+ // A JavaScript string literal: JSON.stringify() escapes quotes, backslashes and line breaks; `<` is escaped so that the
88
+ // script never contains `</script>` nor `<!--`; `/` is escaped for the same reason as in `<script id="vike_pageContext">`
89
+ // (https://github.com/vikejs/vike/pull/2603)
90
+ const literal = JSON.stringify(line).replaceAll('<', '\\u003c').replaceAll('/', '\\/');
91
+ return `<script${inferNonceAttr(pageContext)}>(self.__vike_streamed=self.__vike_streamed||[]).push(${literal})</script>`;
92
+ }
@@ -52,6 +52,10 @@ declare function loadPageConfigsLazyServerSide(pageContext: PageContext_loadPage
52
52
  _pageFilesAll: import("../../../shared-server-client/getPageFiles.js").PageFile[];
53
53
  _pageConfigs: PageConfigRuntime[];
54
54
  _pageConfigGlobal: import("../../../types/PageConfig.js").PageConfigGlobalRuntime;
55
+ _environmentEntries: Record<string, {
56
+ pageConfigs: PageConfigRuntime[];
57
+ pageConfigGlobal: import("../../../types/PageConfig.js").PageConfigGlobalRuntime;
58
+ } | null>;
55
59
  _allPageIds: string[];
56
60
  } & (({
57
61
  isClientSide: false;
@@ -15,6 +15,7 @@ import { loadAndParseVirtualFilePageEntry } from '../../../shared-server-client/
15
15
  import { execHookServer } from './execHookServer.js';
16
16
  import { resolveHeadersResponseEarly } from './headersResponse.js';
17
17
  import { resolvePageContextCspNone } from './csp.js';
18
+ import { loadPageContextEnvironments } from './loadPageContextEnvironments.js';
18
19
  import '../../assertEnvServer.js';
19
20
  async function loadPageConfigsLazyServerSide(pageContext) {
20
21
  objectAssign(pageContext, {
@@ -109,7 +110,7 @@ async function resolvePageContext(pageContext) {
109
110
  return pageContext;
110
111
  }
111
112
  async function loadPageUserFiles(pageContext) {
112
- const [{ pageContextAddendum }] = await Promise.all([
113
+ const [{ pageContextAddendum }, pageContextEnvironments] = await Promise.all([
113
114
  (async () => {
114
115
  const pageFilesServerSide = getPageFilesServerSide(pageContext._pageFilesAll, pageContext.pageId);
115
116
  const isDev = !pageContext._globalContext._isProduction;
@@ -120,9 +121,12 @@ async function loadPageUserFiles(pageContext) {
120
121
  const pageContextAddendum = resolvePageContextConfig(pageFilesServerSide, pageConfigLoaded, pageContext._globalContext._pageConfigGlobal);
121
122
  return { pageContextAddendum };
122
123
  })(),
124
+ pageContext._pageConfig && loadPageContextEnvironments(pageContext),
123
125
  analyzePageClientSideInit(pageContext._globalContext._pageFilesAll, pageContext.pageId, {
124
126
  sharedPageFilesAlreadyLoaded: true,
125
127
  }),
126
128
  ]);
129
+ if (pageContextEnvironments)
130
+ objectAssign(pageContextAddendum, pageContextEnvironments);
127
131
  return pageContextAddendum;
128
132
  }
@@ -0,0 +1,15 @@
1
+ export { loadPageContextEnvironments };
2
+ import type { GlobalContextServerInternal } from '../globalContext.js';
3
+ import type { PageContextPublicMinimum } from '../../../shared-server-client/getPageContextPublicShared.js';
4
+ import '../../assertEnvServer.js';
5
+ declare function loadPageContextEnvironments(pageContext: PageContextPublicMinimum & {
6
+ pageId: string;
7
+ _globalContext: GlobalContextServerInternal;
8
+ }): Promise<{
9
+ environments: {
10
+ [k: string]: {
11
+ config: import("../../../types/index.js").ConfigResolved;
12
+ pageContext: object;
13
+ };
14
+ };
15
+ }>;
@@ -0,0 +1,61 @@
1
+ export { loadPageContextEnvironments };
2
+ import { resolvePageContextConfig } from '../../../shared-server-client/page-configs/resolveVikeConfigPublic.js';
3
+ import { parseGlobalEntryPageConfigs, } from '../../../shared-server-client/getPageFiles/parseVirtualFileExportsGlobalEntry.js';
4
+ import { findPageConfig } from '../../../shared-server-client/page-configs/findPageConfig.js';
5
+ import { loadAndParseVirtualFilePageEntry } from '../../../shared-server-client/page-configs/loadAndParseVirtualFilePageEntry.js';
6
+ import { generateVirtualFileIdAdditionalEnvironment } from '../../../shared-server-node/virtualFileId.js';
7
+ import { isRunnableDevEnvironment } from '../../../utils/isRunnableDevEnvironment.js';
8
+ import { assert, assertUsage } from '../../../utils/assert.js';
9
+ import { getPageContextPublicServer } from './getPageContextPublicServer.js';
10
+ import '../../assertEnvServer.js';
11
+ // Additional environments (e.g. `rsc`) run in the same runtime as the server environment => their functions can be called directly
12
+ // - `pageContext.environments[environmentName]` holds the environment's config values and its view of pageContext, which its functions are called with
13
+ async function loadPageContextEnvironments(pageContext) {
14
+ const environmentEntries = pageContext._globalContext._environmentEntries;
15
+ const environments = Object.fromEntries(await Promise.all(Object.entries(environmentEntries).map(async ([environmentName, environmentEntry]) => {
16
+ const pageContextConfigEnv = await loadPageContextConfig(pageContext, environmentName, environmentEntry);
17
+ const environment = {
18
+ config: pageContextConfigEnv.config,
19
+ pageContext: getPageContextEnvView(getPageContextPublicServer(pageContext), pageContextConfigEnv),
20
+ };
21
+ return [environmentName, environment];
22
+ })));
23
+ const pageContextEnvironments = { environments };
24
+ return pageContextEnvironments;
25
+ }
26
+ // The same pageContext object, except for the config values (and what's derived from them) which are the environment's
27
+ function getPageContextEnvView(pageContext, pageContextConfig) {
28
+ // TO-DO/soon/flat-pageContext make this clean using same mechanism as [Flat `pageContext`](https://github.com/vikejs/vike/issues/1268)
29
+ return new Proxy(pageContext, {
30
+ get(target, prop) {
31
+ if (prop === 'Page')
32
+ return pageContextConfig.exports.Page;
33
+ if (prop in pageContextConfig)
34
+ return pageContextConfig[prop];
35
+ return Reflect.get(target, prop);
36
+ },
37
+ });
38
+ }
39
+ async function loadPageContextConfig(pageContext, environmentName, environmentEntry) {
40
+ const globalContext = pageContext._globalContext;
41
+ const { pageConfigs, pageConfigGlobal } = await importEnvironmentEntry(globalContext, environmentName, environmentEntry);
42
+ const pageConfig = findPageConfig(pageConfigs, pageContext.pageId);
43
+ assert(pageConfig);
44
+ const pageConfigLoaded = await loadAndParseVirtualFilePageEntry(pageConfig, !globalContext._isProduction);
45
+ return resolvePageContextConfig([], pageConfigLoaded, pageConfigGlobal);
46
+ }
47
+ async function importEnvironmentEntry(globalContext, environmentName, environmentEntry) {
48
+ if (environmentEntry) {
49
+ // Prod
50
+ assert(globalContext._isProduction);
51
+ return environmentEntry;
52
+ }
53
+ else {
54
+ // Dev
55
+ assert(!globalContext._isProduction);
56
+ const environment = globalContext._viteDevServer?.environments[environmentName];
57
+ assertUsage(isRunnableDevEnvironment(environment), `The Vike environment ${environmentName} should be a server-side environment running in the same runtime (process or worker) as Vike's server`);
58
+ const virtualFileId = generateVirtualFileIdAdditionalEnvironment(environmentName);
59
+ return parseGlobalEntryPageConfigs(await environment.runner.import(virtualFileId));
60
+ }
61
+ }