vike 0.4.194 → 0.4.195

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 (31) hide show
  1. package/dist/cjs/node/runtime/html/injectAssets/getHtmlTags.js +17 -12
  2. package/dist/cjs/node/runtime/html/injectAssets/injectHtmlTags.js +1 -1
  3. package/dist/cjs/node/runtime/html/injectAssets.js +2 -2
  4. package/dist/cjs/node/runtime/renderPage/createHttpResponse.js +11 -11
  5. package/dist/cjs/node/runtime/renderPage/handleErrorWithoutErrorPage.js +1 -1
  6. package/dist/cjs/node/runtime/renderPage/renderPageAlreadyRouted.js +1 -1
  7. package/dist/cjs/node/runtime/renderPage.js +5 -4
  8. package/dist/cjs/shared/route/executeOnBeforeRouteHook.js +1 -1
  9. package/dist/cjs/utils/PROJECT_VERSION.js +1 -1
  10. package/dist/esm/client/client-routing-runtime/renderPageClientSide.js +4 -5
  11. package/dist/esm/node/runtime/html/injectAssets/getHtmlTags.d.ts +1 -1
  12. package/dist/esm/node/runtime/html/injectAssets/getHtmlTags.js +17 -12
  13. package/dist/esm/node/runtime/html/injectAssets/injectHtmlTags.js +1 -1
  14. package/dist/esm/node/runtime/html/injectAssets.js +2 -2
  15. package/dist/esm/node/runtime/renderPage/createHttpResponse.d.ts +2 -2
  16. package/dist/esm/node/runtime/renderPage/createHttpResponse.js +10 -10
  17. package/dist/esm/node/runtime/renderPage/handleErrorWithoutErrorPage.js +2 -2
  18. package/dist/esm/node/runtime/renderPage/renderPageAlreadyRouted.js +2 -2
  19. package/dist/esm/node/runtime/renderPage.js +5 -4
  20. package/dist/esm/shared/page-configs/Config.d.ts +1 -1
  21. package/dist/esm/shared/route/executeOnBeforeRouteHook.js +1 -1
  22. package/dist/esm/utils/PROJECT_VERSION.d.ts +1 -1
  23. package/dist/esm/utils/PROJECT_VERSION.js +1 -1
  24. package/dist/esm/utils/projectInfo.d.ts +1 -1
  25. package/package.json +1 -1
  26. /package/dist/cjs/node/runtime/renderPage/{createHttpResponseObject → createHttpResponse}/assertNoInfiniteHttpRedirect.js +0 -0
  27. /package/dist/cjs/node/runtime/renderPage/{createHttpResponseObject → createHttpResponse}/getCacheControl.js +0 -0
  28. /package/dist/esm/node/runtime/renderPage/{createHttpResponseObject → createHttpResponse}/assertNoInfiniteHttpRedirect.d.ts +0 -0
  29. /package/dist/esm/node/runtime/renderPage/{createHttpResponseObject → createHttpResponse}/assertNoInfiniteHttpRedirect.js +0 -0
  30. /package/dist/esm/node/runtime/renderPage/{createHttpResponseObject → createHttpResponse}/getCacheControl.d.ts +0 -0
  31. /package/dist/esm/node/runtime/renderPage/{createHttpResponseObject → createHttpResponse}/getCacheControl.js +0 -0
@@ -25,7 +25,7 @@ function getHtmlTags(pageContext, streamFromReactStreamingPackage, injectFilter,
25
25
  if (asset.isEntry && asset.assetType === 'script') {
26
26
  // We could allow the user to change the position of <script> but we currently don't:
27
27
  // - Because of mergeScriptEntries()
28
- // - We would need to add STREAM to to PreloadFilterInject
28
+ // - We would need to add HTML_STREAM to to PreloadFilterInject
29
29
  // To suppor this, we should add the JavaScript entry to injectFilterEntries (with an `src` value of `null`)
30
30
  return false;
31
31
  }
@@ -82,31 +82,36 @@ function getHtmlTags(pageContext, streamFromReactStreamingPackage, injectFilter,
82
82
  // ==========
83
83
  // JavaScript
84
84
  // ==========
85
- // - The pageContext JSON should be fully sent before Vike's client runtime starts executing.
85
+ // - By default, we place the entry <script> towards the end of the HTML for better performance.
86
+ // - Performance-wise, it's more interesting to start showing the page (parse HTML and load CSS) before starting loading scripts.
87
+ // - But with HTML streaming, in order to support [Progressive Rendering](https://vike.dev/streaming#progressive-rendering), the entry <script> should be injected earlier instead.
88
+ // - The entry <script> shouldn't be `<script defer>` upon HTML streaming, otherwise progressive hydration while SSR streaming won't work.
89
+ // - `<script id="vike_pageContext" type="application/json">` (the `pageContext` JSON) should be fully sent before Vike's client runtime starts executing.
86
90
  // - Otherwise, race condition "SyntaxError: Unterminated string in JSON": https://github.com/vikejs/vike/issues/567
87
- // - <script id="vike_pageContext" type="application/json"> must appear before the entry <script> (which loads Vike's client runtime).
88
- // - <script id="vike_pageContext" type="application/json"> can't be async nor defer.
89
- // - The entry <script> can't be defer, otherwise progressive hydration while SSR streaming won't work.
90
- // - The entry <script> should be towards the end of the HTML as performance-wise it's more interesting to parse <div id="page-view"> before running the entry <script> which initiates the hydration.
91
- // - But with HTML streaming, in order to support [Progressive Rendering](https://vike.dev/streaming#progressive-rendering), the entry <script> should be injected early instead.
91
+ // - `<script id="vike_pageContext" type="application/json">` must appear before the entry <script> (which loads Vike's client runtime).
92
+ // - `<script id="vike_pageContext" type="application/json">` can't be async nor defer.
93
+ const positionJavaScriptDefault = 'HTML_END';
92
94
  const positionJavaScriptEntry = (() => {
93
95
  if (injectScriptsAt !== null) {
94
96
  if (pageContext._pageContextPromise) {
95
97
  (0, utils_js_1.assertWarning)(injectScriptsAt === 'HTML_END' || !isStream, `You're setting injectScriptsAt to ${picocolors_1.default.code(JSON.stringify(injectScriptsAt))} while using HTML streaming with a pageContext promise (https://vike.dev/streaming#initial-data-after-stream-end) which is contradictory: the pageContext promise is skipped.`, { onlyOnce: true });
96
98
  }
99
+ if (injectScriptsAt === 'HTML_STREAM' && !isStream) {
100
+ return positionJavaScriptDefault;
101
+ }
97
102
  return injectScriptsAt;
98
103
  }
99
104
  if (pageContext._pageContextPromise) {
100
105
  // - If there is a pageContext._pageContextPromise then <script id="vike_pageContext" type="application/json"> needs to await for it.
101
106
  // - pageContext._pageContextPromise is typically resolved only after the page's components are rendered and the stream ended.
102
107
  // - https://vike.dev/streaming#initial-data-after-stream-end
103
- return 'HTML_END';
108
+ return positionJavaScriptDefault;
104
109
  }
105
110
  if (streamFromReactStreamingPackage && !streamFromReactStreamingPackage.hasStreamEnded()) {
106
111
  // If there is a stream then, in order to support progressive hydration, inject the JavaScript during the stream after React(/Vue/Solid/...) resolved the first suspense boundary.
107
- return 'STREAM';
112
+ return 'HTML_STREAM';
108
113
  }
109
- return 'HTML_END';
114
+ return positionJavaScriptDefault;
110
115
  })();
111
116
  if (pageContext._pageContextPromise && streamFromReactStreamingPackage) {
112
117
  // - Should we show this warning for Solid as well? Solid seems to also support progressive rendering.
@@ -140,7 +145,7 @@ function getHtmlTags(pageContext, streamFromReactStreamingPackage, injectFilter,
140
145
  const htmlTag = (0, inferHtmlTags_js_1.inferPreloadTag)(asset);
141
146
  if (!asset.inject)
142
147
  return;
143
- // Ideally, instead of this conditional ternary operator, we should add STREAM to PreloadFilterInject (or a better fitting name such as HTML_STREAM)
148
+ // Ideally, instead of this conditional ternary operator, we should add HTML_STREAM to PreloadFilterInject
144
149
  const position = asset.inject === 'HTML_END' ? positionJavaScriptEntry : asset.inject;
145
150
  htmlTags.push({ htmlTag, position });
146
151
  });
@@ -223,6 +228,6 @@ function getInjectScriptsAt(pageId, pageConfigs) {
223
228
  (0, utils_js_1.assertUsage)(injectScriptsAt === null ||
224
229
  injectScriptsAt === 'HTML_BEGIN' ||
225
230
  injectScriptsAt === 'HTML_END' ||
226
- injectScriptsAt === 'STREAM', `${configDefinedAt} has an invalid value`);
231
+ injectScriptsAt === 'HTML_STREAM', `${configDefinedAt} has an invalid value`);
227
232
  return injectScriptsAt;
228
233
  }
@@ -13,7 +13,7 @@ function injectHtmlTags(htmlString, htmlTags, position) {
13
13
  exports.injectHtmlTags = injectHtmlTags;
14
14
  // Is it worth it? Should we remove this? https://github.com/vikejs/vike/pull/1740#issuecomment-2230540892
15
15
  function injectHtmlTagsUsingStream(htmlTags, streamFromReactStreamingPackage) {
16
- const htmlFragment = joinHtmlTags(htmlTags.filter((h) => h.position === 'STREAM'));
16
+ const htmlFragment = joinHtmlTags(htmlTags.filter((h) => h.position === 'HTML_STREAM'));
17
17
  if (htmlFragment) {
18
18
  (0, utils_js_1.assert)(!streamFromReactStreamingPackage.hasStreamEnded());
19
19
  streamFromReactStreamingPackage.injectToStream(htmlFragment, { flush: true });
@@ -13,7 +13,7 @@ async function injectHtmlTagsToString(htmlParts, pageContext, injectFilter) {
13
13
  let htmlString = htmlPartsToString(htmlParts, pageAssets);
14
14
  htmlString = injectToHtmlBegin(htmlString, htmlTags);
15
15
  htmlString = injectToHtmlEnd(htmlString, htmlTags);
16
- (0, utils_js_1.assert)(htmlTags.filter((snippet) => snippet.position === 'STREAM').length === 0);
16
+ (0, utils_js_1.assert)(htmlTags.filter((snippet) => snippet.position === 'HTML_STREAM').length === 0);
17
17
  return htmlString;
18
18
  }
19
19
  exports.injectHtmlTagsToString = injectHtmlTagsToString;
@@ -41,7 +41,7 @@ function injectHtmlTagsToStream(pageContext, streamFromReactStreamingPackage, in
41
41
  if (streamFromReactStreamingPackage)
42
42
  return null;
43
43
  (0, utils_js_1.assert)(htmlTags);
44
- const tags = htmlTags.filter((h) => h.position === 'STREAM');
44
+ const tags = htmlTags.filter((h) => h.position === 'HTML_STREAM');
45
45
  if (tags.length === 0)
46
46
  return null;
47
47
  const htmlFragment = (0, injectHtmlTags_js_1.joinHtmlTags)(tags);
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createHttpResponseFavicon404 = exports.createHttpResponseRedirect = exports.createHttpResponseError = exports.createHttpResponsePageContextJson = exports.createHttpResponse = void 0;
3
+ exports.createHttpResponseFavicon404 = exports.createHttpResponseRedirect = exports.createHttpResponseError = exports.createHttpResponsePageContextJson = exports.createHttpResponsePage = void 0;
4
4
  const utils_js_1 = require("../utils.js");
5
5
  const error_page_js_1 = require("../../../shared/error-page.js");
6
6
  const getHttpResponseBody_js_1 = require("./getHttpResponseBody.js");
7
7
  const getEarlyHints_js_1 = require("./getEarlyHints.js");
8
- const getCacheControl_js_1 = require("./createHttpResponseObject/getCacheControl.js");
9
- const assertNoInfiniteHttpRedirect_js_1 = require("./createHttpResponseObject/assertNoInfiniteHttpRedirect.js");
10
- async function createHttpResponse(htmlRender, renderHook, pageContext) {
8
+ const getCacheControl_js_1 = require("./createHttpResponse/getCacheControl.js");
9
+ const assertNoInfiniteHttpRedirect_js_1 = require("./createHttpResponse/assertNoInfiniteHttpRedirect.js");
10
+ async function createHttpResponsePage(htmlRender, renderHook, pageContext) {
11
11
  let statusCode = pageContext.abortStatusCode;
12
12
  if (!statusCode) {
13
13
  const isError = !pageContext._pageId || (0, error_page_js_1.isErrorPage)(pageContext._pageId, pageContext._pageConfigs);
@@ -30,21 +30,21 @@ async function createHttpResponse(htmlRender, renderHook, pageContext) {
30
30
  if (cacheControl) {
31
31
  headers.push(['Cache-Control', cacheControl]);
32
32
  }
33
- return getHttpResponse(statusCode, 'text/html;charset=utf-8', headers, htmlRender, earlyHints, renderHook);
33
+ return createHttpResponse(statusCode, 'text/html;charset=utf-8', headers, htmlRender, earlyHints, renderHook);
34
34
  }
35
- exports.createHttpResponse = createHttpResponse;
35
+ exports.createHttpResponsePage = createHttpResponsePage;
36
36
  function createHttpResponseFavicon404() {
37
- const httpResponse = getHttpResponse(404, 'text/html;charset=utf-8', [], "<p>No favicon.ico found.</p><script>console.log('This HTTP response was generated by Vike.')</script>");
37
+ const httpResponse = createHttpResponse(404, 'text/html;charset=utf-8', [], "<p>No favicon.ico found.</p><script>console.log('This HTTP response was generated by Vike.')</script>");
38
38
  return httpResponse;
39
39
  }
40
40
  exports.createHttpResponseFavicon404 = createHttpResponseFavicon404;
41
41
  function createHttpResponseError() {
42
- const httpResponse = getHttpResponse(500, 'text/html;charset=utf-8', [], "<p>An error occurred.</p><script>console.log('This HTTP response was generated by Vike. This response is used instead of rendering the error page (https://vike.dev/error-page), either because there isn't error page or because an error occurred while rendering the error page.')</script>");
42
+ const httpResponse = createHttpResponse(500, 'text/html;charset=utf-8', [], "<p>An error occurred.</p><script>console.log('This HTTP response was generated by Vike. This response is used instead of rendering the error page (https://vike.dev/error-page), either because there isn't error page or because an error occurred while rendering the error page.')</script>");
43
43
  return httpResponse;
44
44
  }
45
45
  exports.createHttpResponseError = createHttpResponseError;
46
46
  async function createHttpResponsePageContextJson(pageContextSerialized) {
47
- const httpResponse = getHttpResponse(200, 'application/json', [], pageContextSerialized, [], null);
47
+ const httpResponse = createHttpResponse(200, 'application/json', [], pageContextSerialized, [], null);
48
48
  return httpResponse;
49
49
  }
50
50
  exports.createHttpResponsePageContextJson = createHttpResponsePageContextJson;
@@ -56,13 +56,13 @@ urlLogical) {
56
56
  (0, utils_js_1.assert)(statusCode);
57
57
  (0, utils_js_1.assert)(300 <= statusCode && statusCode <= 399);
58
58
  const headers = [['Location', url]];
59
- return getHttpResponse(statusCode, 'text/html;charset=utf-8', headers,
59
+ return createHttpResponse(statusCode, 'text/html;charset=utf-8', headers,
60
60
  // For bots / programmatic crawlig: show what's going on.
61
61
  // For users: showing a blank page is probably better than a flickering text.
62
62
  `<p style="display: none">Redirecting to ${url}</p><script>console.log('This HTTP response was generated by Vike.')</script>`);
63
63
  }
64
64
  exports.createHttpResponseRedirect = createHttpResponseRedirect;
65
- function getHttpResponse(statusCode, contentType, headers, htmlRender, earlyHints = [], renderHook = null) {
65
+ function createHttpResponse(statusCode, contentType, headers, htmlRender, earlyHints = [], renderHook = null) {
66
66
  headers.push(['Content-Type', contentType]);
67
67
  (0, utils_js_1.assert)(renderHook || typeof htmlRender === 'string');
68
68
  return {
@@ -25,7 +25,7 @@ async function handleErrorWithoutErrorPage(pageContext) {
25
25
  else {
26
26
  const __getPageAssets = async () => [];
27
27
  (0, utils_js_1.objectAssign)(pageContext, { __getPageAssets });
28
- const httpResponse = await (0, createHttpResponse_js_1.createHttpResponse)((0, stringify_1.stringify)({ serverSideError: true }), null, pageContext);
28
+ const httpResponse = await (0, createHttpResponse_js_1.createHttpResponsePage)((0, stringify_1.stringify)({ serverSideError: true }), null, pageContext);
29
29
  (0, utils_js_1.objectAssign)(pageContext, { httpResponse });
30
30
  return pageContext;
31
31
  }
@@ -58,7 +58,7 @@ async function renderPageAlreadyRouted(pageContext) {
58
58
  }
59
59
  const renderHookResult = await (0, executeOnRenderHtmlHook_js_1.executeOnRenderHtmlHook)(pageContext);
60
60
  const { htmlRender, renderHook } = renderHookResult;
61
- const httpResponse = await (0, createHttpResponse_js_1.createHttpResponse)(htmlRender, renderHook, pageContext);
61
+ const httpResponse = await (0, createHttpResponse_js_1.createHttpResponsePage)(htmlRender, renderHook, pageContext);
62
62
  (0, utils_js_1.objectAssign)(pageContext, { httpResponse });
63
63
  return pageContext;
64
64
  }
@@ -242,6 +242,9 @@ function logHttpResponse(urlOriginalPretty, httpRequestId, pageContextReturn) {
242
242
  }
243
243
  (0, loggerRuntime_js_1.logRuntimeInfo)?.(msg, httpRequestId, isNominal ? 'info' : 'error');
244
244
  }
245
+ function prettyUrl(url) {
246
+ return picocolors_1.default.bold(decodeURI(url));
247
+ }
245
248
  function getPageContextHttpResponseError(err, pageContextInit) {
246
249
  const pageContextWithError = createPageContext(pageContextInit);
247
250
  const httpResponse = (0, createHttpResponse_js_1.createHttpResponseError)();
@@ -284,6 +287,7 @@ async function renderPageNominal(pageContext) {
284
287
  }
285
288
  }
286
289
  (0, utils_js_1.assert)((0, utils_js_1.hasProp)(pageContext, '_pageId', 'string'));
290
+ (0, utils_js_1.assert)(pageContext.errorWhileRendering === null);
287
291
  // Render
288
292
  const pageContextAfterRender = await (0, renderPageAlreadyRouted_js_1.renderPageAlreadyRouted)(pageContext);
289
293
  (0, utils_js_1.assert)(pageContext === pageContextAfterRender);
@@ -446,8 +450,5 @@ function assertBaseUrl(pageContextInit) {
446
450
  const { urlOriginal } = pageContextInit;
447
451
  const { urlWithoutPageContextRequestSuffix } = (0, handlePageContextRequestUrl_js_1.handlePageContextRequestUrl)(urlOriginal);
448
452
  const { hasBaseServer } = (0, utils_js_1.parseUrl)(urlWithoutPageContextRequestSuffix, baseServer);
449
- (0, utils_js_1.assertUsage)(hasBaseServer, `${picocolors_1.default.code('renderPage(pageContextInit)')} (https://vike.dev/renderPage) called with ${picocolors_1.default.code(`pageContextInit.urlOriginal===${JSON.stringify(urlOriginal)}`)} which doesn't start with Base URL ${prettyUrl(baseServer)} (https://vike.dev/base-url)`);
450
- }
451
- function prettyUrl(url) {
452
- return picocolors_1.default.code(decodeURI(url));
453
+ (0, utils_js_1.assertUsage)(hasBaseServer, `${picocolors_1.default.code('renderPage(pageContextInit)')} (https://vike.dev/renderPage) called with ${picocolors_1.default.code(`pageContextInit.urlOriginal===${JSON.stringify(urlOriginal)}`)} which doesn't start with Base URL ${picocolors_1.default.code(baseServer)} (https://vike.dev/base-url)`);
453
454
  }
@@ -72,7 +72,7 @@ async function getPageContextFromHook(onBeforeRouteHook, pageContext) {
72
72
  }
73
73
  if ((0, utils_js_1.hasProp)(hookReturn.pageContext, 'urlLogical')) {
74
74
  (0, utils_js_1.assertUsageUrlPathnameAbsolute)(
75
- // We type-cast to string instead of assertUsage() in order to save client-side KBs
75
+ // We skip validation and type-cast instead of assertUsage() in order to save client-side KBs
76
76
  hookReturn.pageContext.urlLogical, `${errPrefix} returned ${picocolors_1.default.cyan('{ pageContext: { urlLogical } }')} but ${picocolors_1.default.cyan('urlLogical')}`);
77
77
  }
78
78
  (0, assertPageContextProvidedByUser_js_1.assertPageContextProvidedByUser)(hookReturn.pageContext, {
@@ -2,4 +2,4 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PROJECT_VERSION = void 0;
4
4
  // Automatically updated by @brillout/release-me
5
- exports.PROJECT_VERSION = '0.4.194';
5
+ exports.PROJECT_VERSION = '0.4.195';
@@ -20,6 +20,7 @@ import { getErrorPageId } from '../../shared/error-page.js';
20
20
  const globalObject = getGlobalObject('renderPageClientSide.ts', { renderCounter: 0 });
21
21
  async function renderPageClientSide(renderArgs) {
22
22
  const { scrollTarget, urlOriginal = getCurrentUrl(), overwriteLastHistoryEntry = false, isBackwardNavigation, pageContextsFromRewrite = [], redirectCount = 0, isUserLandPushStateNavigation, isClientSideNavigation = true } = renderArgs;
23
+ const { previousPageContext } = globalObject;
23
24
  const { isRenderOutdated, setHydrationCanBeAborted, isFirstRender } = getIsRenderOutdated();
24
25
  // Note that pageContext.isHydration isn't equivalent to isFirstRender
25
26
  // - Thus pageContext.isHydration isn't equivalent to !pageContext.isClientSideNavigation
@@ -41,7 +42,6 @@ async function renderPageClientSide(renderArgs) {
41
42
  return;
42
43
  // onPageTransitionStart()
43
44
  if (globalObject.isFirstRenderDone) {
44
- const { previousPageContext } = globalObject;
45
45
  assert(previousPageContext);
46
46
  // We use the hook of the previous page in order to be able to call onPageTransitionStart() before fetching the files of the next page.
47
47
  // https://github.com/vikejs/vike/issues/1560
@@ -96,8 +96,8 @@ async function renderPageClientSide(renderArgs) {
96
96
  }
97
97
  assert(hasProp(pageContextFromRoute, '_pageId', 'string')); // Help TS
98
98
  const isSamePage = pageContextFromRoute._pageId &&
99
- globalObject.previousPageContext?._pageId &&
100
- pageContextFromRoute._pageId === globalObject.previousPageContext._pageId;
99
+ previousPageContext?._pageId &&
100
+ pageContextFromRoute._pageId === previousPageContext._pageId;
101
101
  if (isUserLandPushStateNavigation && isSamePage) {
102
102
  // Skip's Vike's rendering; let the user handle the navigation
103
103
  return;
@@ -171,7 +171,7 @@ async function renderPageClientSide(renderArgs) {
171
171
  objectAssign(pageContext, {
172
172
  isBackwardNavigation,
173
173
  isClientSideNavigation,
174
- _previousPageContext: globalObject.previousPageContext
174
+ _previousPageContext: previousPageContext
175
175
  });
176
176
  {
177
177
  const pageContextFromAllRewrites = getPageContextFromAllRewrites(pageContextsFromRewrite);
@@ -367,7 +367,6 @@ async function renderPageClientSide(renderArgs) {
367
367
  // onPageTransitionEnd()
368
368
  if (globalObject.isTransitioning) {
369
369
  globalObject.isTransitioning = undefined;
370
- const { previousPageContext } = globalObject;
371
370
  assert(previousPageContext);
372
371
  assertHook(previousPageContext, 'onPageTransitionEnd');
373
372
  const hook = getHook(previousPageContext, 'onPageTransitionEnd');
@@ -22,7 +22,7 @@ type InjectFilterEntry = {
22
22
  isEntry: boolean;
23
23
  inject: PreloadFilterInject;
24
24
  };
25
- type Position = 'HTML_BEGIN' | 'HTML_END' | 'STREAM';
25
+ type Position = 'HTML_BEGIN' | 'HTML_END' | 'HTML_STREAM';
26
26
  type HtmlTag = {
27
27
  htmlTag: string | (() => string);
28
28
  position: Position;
@@ -20,7 +20,7 @@ function getHtmlTags(pageContext, streamFromReactStreamingPackage, injectFilter,
20
20
  if (asset.isEntry && asset.assetType === 'script') {
21
21
  // We could allow the user to change the position of <script> but we currently don't:
22
22
  // - Because of mergeScriptEntries()
23
- // - We would need to add STREAM to to PreloadFilterInject
23
+ // - We would need to add HTML_STREAM to to PreloadFilterInject
24
24
  // To suppor this, we should add the JavaScript entry to injectFilterEntries (with an `src` value of `null`)
25
25
  return false;
26
26
  }
@@ -77,31 +77,36 @@ function getHtmlTags(pageContext, streamFromReactStreamingPackage, injectFilter,
77
77
  // ==========
78
78
  // JavaScript
79
79
  // ==========
80
- // - The pageContext JSON should be fully sent before Vike's client runtime starts executing.
80
+ // - By default, we place the entry <script> towards the end of the HTML for better performance.
81
+ // - Performance-wise, it's more interesting to start showing the page (parse HTML and load CSS) before starting loading scripts.
82
+ // - But with HTML streaming, in order to support [Progressive Rendering](https://vike.dev/streaming#progressive-rendering), the entry <script> should be injected earlier instead.
83
+ // - The entry <script> shouldn't be `<script defer>` upon HTML streaming, otherwise progressive hydration while SSR streaming won't work.
84
+ // - `<script id="vike_pageContext" type="application/json">` (the `pageContext` JSON) should be fully sent before Vike's client runtime starts executing.
81
85
  // - Otherwise, race condition "SyntaxError: Unterminated string in JSON": https://github.com/vikejs/vike/issues/567
82
- // - <script id="vike_pageContext" type="application/json"> must appear before the entry <script> (which loads Vike's client runtime).
83
- // - <script id="vike_pageContext" type="application/json"> can't be async nor defer.
84
- // - The entry <script> can't be defer, otherwise progressive hydration while SSR streaming won't work.
85
- // - The entry <script> should be towards the end of the HTML as performance-wise it's more interesting to parse <div id="page-view"> before running the entry <script> which initiates the hydration.
86
- // - But with HTML streaming, in order to support [Progressive Rendering](https://vike.dev/streaming#progressive-rendering), the entry <script> should be injected early instead.
86
+ // - `<script id="vike_pageContext" type="application/json">` must appear before the entry <script> (which loads Vike's client runtime).
87
+ // - `<script id="vike_pageContext" type="application/json">` can't be async nor defer.
88
+ const positionJavaScriptDefault = 'HTML_END';
87
89
  const positionJavaScriptEntry = (() => {
88
90
  if (injectScriptsAt !== null) {
89
91
  if (pageContext._pageContextPromise) {
90
92
  assertWarning(injectScriptsAt === 'HTML_END' || !isStream, `You're setting injectScriptsAt to ${pc.code(JSON.stringify(injectScriptsAt))} while using HTML streaming with a pageContext promise (https://vike.dev/streaming#initial-data-after-stream-end) which is contradictory: the pageContext promise is skipped.`, { onlyOnce: true });
91
93
  }
94
+ if (injectScriptsAt === 'HTML_STREAM' && !isStream) {
95
+ return positionJavaScriptDefault;
96
+ }
92
97
  return injectScriptsAt;
93
98
  }
94
99
  if (pageContext._pageContextPromise) {
95
100
  // - If there is a pageContext._pageContextPromise then <script id="vike_pageContext" type="application/json"> needs to await for it.
96
101
  // - pageContext._pageContextPromise is typically resolved only after the page's components are rendered and the stream ended.
97
102
  // - https://vike.dev/streaming#initial-data-after-stream-end
98
- return 'HTML_END';
103
+ return positionJavaScriptDefault;
99
104
  }
100
105
  if (streamFromReactStreamingPackage && !streamFromReactStreamingPackage.hasStreamEnded()) {
101
106
  // If there is a stream then, in order to support progressive hydration, inject the JavaScript during the stream after React(/Vue/Solid/...) resolved the first suspense boundary.
102
- return 'STREAM';
107
+ return 'HTML_STREAM';
103
108
  }
104
- return 'HTML_END';
109
+ return positionJavaScriptDefault;
105
110
  })();
106
111
  if (pageContext._pageContextPromise && streamFromReactStreamingPackage) {
107
112
  // - Should we show this warning for Solid as well? Solid seems to also support progressive rendering.
@@ -135,7 +140,7 @@ function getHtmlTags(pageContext, streamFromReactStreamingPackage, injectFilter,
135
140
  const htmlTag = inferPreloadTag(asset);
136
141
  if (!asset.inject)
137
142
  return;
138
- // Ideally, instead of this conditional ternary operator, we should add STREAM to PreloadFilterInject (or a better fitting name such as HTML_STREAM)
143
+ // Ideally, instead of this conditional ternary operator, we should add HTML_STREAM to PreloadFilterInject
139
144
  const position = asset.inject === 'HTML_END' ? positionJavaScriptEntry : asset.inject;
140
145
  htmlTags.push({ htmlTag, position });
141
146
  });
@@ -217,6 +222,6 @@ function getInjectScriptsAt(pageId, pageConfigs) {
217
222
  assertUsage(injectScriptsAt === null ||
218
223
  injectScriptsAt === 'HTML_BEGIN' ||
219
224
  injectScriptsAt === 'HTML_END' ||
220
- injectScriptsAt === 'STREAM', `${configDefinedAt} has an invalid value`);
225
+ injectScriptsAt === 'HTML_STREAM', `${configDefinedAt} has an invalid value`);
221
226
  return injectScriptsAt;
222
227
  }
@@ -16,7 +16,7 @@ function injectHtmlTags(htmlString, htmlTags, position) {
16
16
  }
17
17
  // Is it worth it? Should we remove this? https://github.com/vikejs/vike/pull/1740#issuecomment-2230540892
18
18
  function injectHtmlTagsUsingStream(htmlTags, streamFromReactStreamingPackage) {
19
- const htmlFragment = joinHtmlTags(htmlTags.filter((h) => h.position === 'STREAM'));
19
+ const htmlFragment = joinHtmlTags(htmlTags.filter((h) => h.position === 'HTML_STREAM'));
20
20
  if (htmlFragment) {
21
21
  assert(!streamFromReactStreamingPackage.hasStreamEnded());
22
22
  streamFromReactStreamingPackage.injectToStream(htmlFragment, { flush: true });
@@ -12,7 +12,7 @@ async function injectHtmlTagsToString(htmlParts, pageContext, injectFilter) {
12
12
  let htmlString = htmlPartsToString(htmlParts, pageAssets);
13
13
  htmlString = injectToHtmlBegin(htmlString, htmlTags);
14
14
  htmlString = injectToHtmlEnd(htmlString, htmlTags);
15
- assert(htmlTags.filter((snippet) => snippet.position === 'STREAM').length === 0);
15
+ assert(htmlTags.filter((snippet) => snippet.position === 'HTML_STREAM').length === 0);
16
16
  return htmlString;
17
17
  }
18
18
  function injectHtmlTagsToStream(pageContext, streamFromReactStreamingPackage, injectFilter) {
@@ -39,7 +39,7 @@ function injectHtmlTagsToStream(pageContext, streamFromReactStreamingPackage, in
39
39
  if (streamFromReactStreamingPackage)
40
40
  return null;
41
41
  assert(htmlTags);
42
- const tags = htmlTags.filter((h) => h.position === 'STREAM');
42
+ const tags = htmlTags.filter((h) => h.position === 'HTML_STREAM');
43
43
  if (tags.length === 0)
44
44
  return null;
45
45
  const htmlFragment = joinHtmlTags(tags);
@@ -1,4 +1,4 @@
1
- export { createHttpResponse };
1
+ export { createHttpResponsePage };
2
2
  export { createHttpResponsePageContextJson };
3
3
  export { createHttpResponseError };
4
4
  export { createHttpResponseRedirect };
@@ -18,7 +18,7 @@ type HttpResponse = {
18
18
  /** **Deprecated**: use `headers` instead, see https://vike.dev/migration/0.4.134 */
19
19
  contentType: 'application/json' | 'text/html;charset=utf-8';
20
20
  } & HttpResponseBody;
21
- declare function createHttpResponse(htmlRender: HtmlRender, renderHook: null | RenderHook, pageContext: {
21
+ declare function createHttpResponsePage(htmlRender: HtmlRender, renderHook: null | RenderHook, pageContext: {
22
22
  _pageId: null | string;
23
23
  is404: null | boolean;
24
24
  errorWhileRendering: null | Error;
@@ -1,4 +1,4 @@
1
- export { createHttpResponse };
1
+ export { createHttpResponsePage };
2
2
  export { createHttpResponsePageContextJson };
3
3
  export { createHttpResponseError };
4
4
  export { createHttpResponseRedirect };
@@ -7,9 +7,9 @@ import { assert, assertWarning } from '../utils.js';
7
7
  import { isErrorPage } from '../../../shared/error-page.js';
8
8
  import { getHttpResponseBody, getHttpResponseBodyStreamHandlers } from './getHttpResponseBody.js';
9
9
  import { getEarlyHints } from './getEarlyHints.js';
10
- import { getCacheControl } from './createHttpResponseObject/getCacheControl.js';
11
- import { assertNoInfiniteHttpRedirect } from './createHttpResponseObject/assertNoInfiniteHttpRedirect.js';
12
- async function createHttpResponse(htmlRender, renderHook, pageContext) {
10
+ import { getCacheControl } from './createHttpResponse/getCacheControl.js';
11
+ import { assertNoInfiniteHttpRedirect } from './createHttpResponse/assertNoInfiniteHttpRedirect.js';
12
+ async function createHttpResponsePage(htmlRender, renderHook, pageContext) {
13
13
  let statusCode = pageContext.abortStatusCode;
14
14
  if (!statusCode) {
15
15
  const isError = !pageContext._pageId || isErrorPage(pageContext._pageId, pageContext._pageConfigs);
@@ -32,18 +32,18 @@ async function createHttpResponse(htmlRender, renderHook, pageContext) {
32
32
  if (cacheControl) {
33
33
  headers.push(['Cache-Control', cacheControl]);
34
34
  }
35
- return getHttpResponse(statusCode, 'text/html;charset=utf-8', headers, htmlRender, earlyHints, renderHook);
35
+ return createHttpResponse(statusCode, 'text/html;charset=utf-8', headers, htmlRender, earlyHints, renderHook);
36
36
  }
37
37
  function createHttpResponseFavicon404() {
38
- const httpResponse = getHttpResponse(404, 'text/html;charset=utf-8', [], "<p>No favicon.ico found.</p><script>console.log('This HTTP response was generated by Vike.')</script>");
38
+ const httpResponse = createHttpResponse(404, 'text/html;charset=utf-8', [], "<p>No favicon.ico found.</p><script>console.log('This HTTP response was generated by Vike.')</script>");
39
39
  return httpResponse;
40
40
  }
41
41
  function createHttpResponseError() {
42
- const httpResponse = getHttpResponse(500, 'text/html;charset=utf-8', [], "<p>An error occurred.</p><script>console.log('This HTTP response was generated by Vike. This response is used instead of rendering the error page (https://vike.dev/error-page), either because there isn't error page or because an error occurred while rendering the error page.')</script>");
42
+ const httpResponse = createHttpResponse(500, 'text/html;charset=utf-8', [], "<p>An error occurred.</p><script>console.log('This HTTP response was generated by Vike. This response is used instead of rendering the error page (https://vike.dev/error-page), either because there isn't error page or because an error occurred while rendering the error page.')</script>");
43
43
  return httpResponse;
44
44
  }
45
45
  async function createHttpResponsePageContextJson(pageContextSerialized) {
46
- const httpResponse = getHttpResponse(200, 'application/json', [], pageContextSerialized, [], null);
46
+ const httpResponse = createHttpResponse(200, 'application/json', [], pageContextSerialized, [], null);
47
47
  return httpResponse;
48
48
  }
49
49
  function createHttpResponseRedirect({ url, statusCode },
@@ -54,12 +54,12 @@ urlLogical) {
54
54
  assert(statusCode);
55
55
  assert(300 <= statusCode && statusCode <= 399);
56
56
  const headers = [['Location', url]];
57
- return getHttpResponse(statusCode, 'text/html;charset=utf-8', headers,
57
+ return createHttpResponse(statusCode, 'text/html;charset=utf-8', headers,
58
58
  // For bots / programmatic crawlig: show what's going on.
59
59
  // For users: showing a blank page is probably better than a flickering text.
60
60
  `<p style="display: none">Redirecting to ${url}</p><script>console.log('This HTTP response was generated by Vike.')</script>`);
61
61
  }
62
- function getHttpResponse(statusCode, contentType, headers, htmlRender, earlyHints = [], renderHook = null) {
62
+ function createHttpResponse(statusCode, contentType, headers, htmlRender, earlyHints = [], renderHook = null) {
63
63
  headers.push(['Content-Type', contentType]);
64
64
  assert(renderHook || typeof htmlRender === 'string');
65
65
  return {
@@ -2,7 +2,7 @@ export { handleErrorWithoutErrorPage };
2
2
  import { stringify } from '@brillout/json-serializer/stringify';
3
3
  import { getGlobalContext } from '../globalContext.js';
4
4
  import { assert, assertWarning, objectAssign } from '../utils.js';
5
- import { createHttpResponse, createHttpResponseError } from './createHttpResponse.js';
5
+ import { createHttpResponsePage, createHttpResponseError } from './createHttpResponse.js';
6
6
  import pc from '@brillout/picocolors';
7
7
  // When the user hasn't defined _error.page.js
8
8
  async function handleErrorWithoutErrorPage(pageContext) {
@@ -20,7 +20,7 @@ async function handleErrorWithoutErrorPage(pageContext) {
20
20
  else {
21
21
  const __getPageAssets = async () => [];
22
22
  objectAssign(pageContext, { __getPageAssets });
23
- const httpResponse = await createHttpResponse(stringify({ serverSideError: true }), null, pageContext);
23
+ const httpResponse = await createHttpResponsePage(stringify({ serverSideError: true }), null, pageContext);
24
24
  objectAssign(pageContext, { httpResponse });
25
25
  return pageContext;
26
26
  }
@@ -10,7 +10,7 @@ import { assert, assertUsage, assertWarning, hasProp, normalizeHeaders, objectAs
10
10
  import { serializePageContextClientSide } from '../html/serializePageContextClientSide.js';
11
11
  import { getPageContextUrlComputed } from '../../../shared/getPageContextUrlComputed.js';
12
12
  import { getGlobalContext } from '../globalContext.js';
13
- import { createHttpResponse, createHttpResponsePageContextJson } from './createHttpResponse.js';
13
+ import { createHttpResponsePage, createHttpResponsePageContextJson } from './createHttpResponse.js';
14
14
  import { loadUserFilesServerSide } from './loadUserFilesServerSide.js';
15
15
  import { executeOnRenderHtmlHook } from './executeOnRenderHtmlHook.js';
16
16
  import { executeOnBeforeRenderAndDataHooks } from './executeOnBeforeRenderAndDataHooks.js';
@@ -57,7 +57,7 @@ async function renderPageAlreadyRouted(pageContext) {
57
57
  }
58
58
  const renderHookResult = await executeOnRenderHtmlHook(pageContext);
59
59
  const { htmlRender, renderHook } = renderHookResult;
60
- const httpResponse = await createHttpResponse(htmlRender, renderHook, pageContext);
60
+ const httpResponse = await createHttpResponsePage(htmlRender, renderHook, pageContext);
61
61
  objectAssign(pageContext, { httpResponse });
62
62
  return pageContext;
63
63
  }
@@ -236,6 +236,9 @@ function logHttpResponse(urlOriginalPretty, httpRequestId, pageContextReturn) {
236
236
  }
237
237
  logRuntimeInfo?.(msg, httpRequestId, isNominal ? 'info' : 'error');
238
238
  }
239
+ function prettyUrl(url) {
240
+ return pc.bold(decodeURI(url));
241
+ }
239
242
  function getPageContextHttpResponseError(err, pageContextInit) {
240
243
  const pageContextWithError = createPageContext(pageContextInit);
241
244
  const httpResponse = createHttpResponseError();
@@ -278,6 +281,7 @@ async function renderPageNominal(pageContext) {
278
281
  }
279
282
  }
280
283
  assert(hasProp(pageContext, '_pageId', 'string'));
284
+ assert(pageContext.errorWhileRendering === null);
281
285
  // Render
282
286
  const pageContextAfterRender = await renderPageAlreadyRouted(pageContext);
283
287
  assert(pageContext === pageContextAfterRender);
@@ -440,8 +444,5 @@ function assertBaseUrl(pageContextInit) {
440
444
  const { urlOriginal } = pageContextInit;
441
445
  const { urlWithoutPageContextRequestSuffix } = handlePageContextRequestUrl(urlOriginal);
442
446
  const { hasBaseServer } = parseUrl(urlWithoutPageContextRequestSuffix, baseServer);
443
- assertUsage(hasBaseServer, `${pc.code('renderPage(pageContextInit)')} (https://vike.dev/renderPage) called with ${pc.code(`pageContextInit.urlOriginal===${JSON.stringify(urlOriginal)}`)} which doesn't start with Base URL ${prettyUrl(baseServer)} (https://vike.dev/base-url)`);
444
- }
445
- function prettyUrl(url) {
446
- return pc.code(decodeURI(url));
447
+ assertUsage(hasBaseServer, `${pc.code('renderPage(pageContextInit)')} (https://vike.dev/renderPage) called with ${pc.code(`pageContextInit.urlOriginal===${JSON.stringify(urlOriginal)}`)} which doesn't start with Base URL ${pc.code(baseServer)} (https://vike.dev/base-url)`);
447
448
  }
@@ -358,7 +358,7 @@ type ConfigBuiltIn = {
358
358
  *
359
359
  * https://vike.dev/injectScriptsAt
360
360
  */
361
- injectScriptsAt?: 'HTML_BEGIN' | 'HTML_END' | 'STREAM' | null;
361
+ injectScriptsAt?: 'HTML_BEGIN' | 'HTML_END' | 'HTML_STREAM' | null;
362
362
  /** Used by Vike extensions to set their name.
363
363
  *
364
364
  * https://vike.dev/extends
@@ -66,7 +66,7 @@ async function getPageContextFromHook(onBeforeRouteHook, pageContext) {
66
66
  }
67
67
  if (hasProp(hookReturn.pageContext, 'urlLogical')) {
68
68
  assertUsageUrlPathnameAbsolute(
69
- // We type-cast to string instead of assertUsage() in order to save client-side KBs
69
+ // We skip validation and type-cast instead of assertUsage() in order to save client-side KBs
70
70
  hookReturn.pageContext.urlLogical, `${errPrefix} returned ${pc.cyan('{ pageContext: { urlLogical } }')} but ${pc.cyan('urlLogical')}`);
71
71
  }
72
72
  assertPageContextProvidedByUser(hookReturn.pageContext, {
@@ -1 +1 @@
1
- export declare const PROJECT_VERSION: "0.4.194";
1
+ export declare const PROJECT_VERSION: "0.4.195";
@@ -1,2 +1,2 @@
1
1
  // Automatically updated by @brillout/release-me
2
- export const PROJECT_VERSION = '0.4.194';
2
+ export const PROJECT_VERSION = '0.4.195';
@@ -1,4 +1,4 @@
1
1
  export declare const projectInfo: {
2
2
  projectName: "Vike";
3
- projectVersion: "0.4.194";
3
+ projectVersion: "0.4.195";
4
4
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vike",
3
- "version": "0.4.194",
3
+ "version": "0.4.195",
4
4
  "repository": "https://github.com/vikejs/vike",
5
5
  "exports": {
6
6
  "./server": {