vike 0.4.147 → 0.4.148-commit-7596dcd

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 (74) hide show
  1. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getConfigValuesSerialized.js +17 -12
  2. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/configDefinitionsBuiltIn.js +3 -0
  3. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.js +116 -0
  4. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +33 -45
  5. package/dist/cjs/node/prerender/runPrerender.js +85 -84
  6. package/dist/cjs/node/runtime/html/injectAssets/injectAssets__public.js +1 -1
  7. package/dist/cjs/node/runtime/html/renderHtml.js +1 -1
  8. package/dist/cjs/node/runtime/renderPage/createHttpResponseObject/assertNoInfiniteHttpRedirect.js +12 -12
  9. package/dist/cjs/node/runtime/renderPage/createHttpResponseObject.js +3 -3
  10. package/dist/cjs/node/runtime/renderPage/executeOnBeforeRenderHook.js +1 -1
  11. package/dist/cjs/node/runtime/renderPage/executeOnRenderHtmlHook.js +3 -3
  12. package/dist/cjs/node/runtime/renderPage/getHttpResponseBody.js +1 -1
  13. package/dist/cjs/node/runtime/renderPage/renderPageAlreadyRouted.js +21 -18
  14. package/dist/cjs/node/runtime/renderPage.js +73 -49
  15. package/dist/cjs/shared/getPageFiles/parseGlobResults.js +3 -3
  16. package/dist/cjs/shared/hooks/executeHook.js +18 -29
  17. package/dist/cjs/shared/hooks/getHook.js +104 -3
  18. package/dist/cjs/shared/page-configs/helpers/getConfigDefinedAtString.js +1 -1
  19. package/dist/cjs/shared/route/executeGuardHook.js +3 -2
  20. package/dist/cjs/shared/route/executeOnBeforeRouteHook.js +4 -4
  21. package/dist/cjs/shared/route/loadPageRoutes.js +10 -15
  22. package/dist/cjs/shared/route/resolveRedirects.js +8 -5
  23. package/dist/cjs/utils/parseUrl-extras.js +6 -1
  24. package/dist/cjs/utils/parseUrl.js +24 -16
  25. package/dist/cjs/utils/projectInfo.js +1 -1
  26. package/dist/esm/client/client-routing-runtime/createPageContext.d.ts +1 -1
  27. package/dist/esm/client/client-routing-runtime/getPageContextFromHooks.js +20 -10
  28. package/dist/esm/client/client-routing-runtime/onBrowserHistoryNavigation.js +2 -2
  29. package/dist/esm/client/client-routing-runtime/renderPageClientSide.js +18 -12
  30. package/dist/esm/client/shared/executeOnRenderClientHook.js +1 -1
  31. package/dist/esm/client/shared/getPageContextSerializedInHtml.js +1 -1
  32. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getConfigValuesSerialized.js +17 -12
  33. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/configDefinitionsBuiltIn.js +3 -0
  34. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.d.ts +5 -0
  35. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.js +110 -0
  36. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +34 -46
  37. package/dist/esm/node/prerender/runPrerender.js +87 -86
  38. package/dist/esm/node/runtime/html/injectAssets/injectAssets__public.js +1 -1
  39. package/dist/esm/node/runtime/html/renderHtml.js +1 -1
  40. package/dist/esm/node/runtime/renderPage/createHttpResponseObject/assertNoInfiniteHttpRedirect.d.ts +1 -1
  41. package/dist/esm/node/runtime/renderPage/createHttpResponseObject/assertNoInfiniteHttpRedirect.js +13 -13
  42. package/dist/esm/node/runtime/renderPage/createHttpResponseObject.d.ts +1 -1
  43. package/dist/esm/node/runtime/renderPage/createHttpResponseObject.js +3 -3
  44. package/dist/esm/node/runtime/renderPage/executeOnBeforeRenderHook.js +1 -1
  45. package/dist/esm/node/runtime/renderPage/executeOnRenderHtmlHook.d.ts +2 -2
  46. package/dist/esm/node/runtime/renderPage/executeOnRenderHtmlHook.js +3 -3
  47. package/dist/esm/node/runtime/renderPage/getHttpResponseBody.js +1 -1
  48. package/dist/esm/node/runtime/renderPage/renderPageAlreadyRouted.d.ts +7 -7
  49. package/dist/esm/node/runtime/renderPage/renderPageAlreadyRouted.js +22 -19
  50. package/dist/esm/node/runtime/renderPage.js +74 -50
  51. package/dist/esm/shared/getPageFiles/parseGlobResults.js +1 -1
  52. package/dist/esm/shared/hooks/executeHook.d.ts +2 -2
  53. package/dist/esm/shared/hooks/executeHook.js +18 -29
  54. package/dist/esm/shared/hooks/getHook.d.ts +17 -7
  55. package/dist/esm/shared/hooks/getHook.js +103 -3
  56. package/dist/esm/shared/page-configs/Config.d.ts +21 -13
  57. package/dist/esm/shared/page-configs/helpers/getConfigDefinedAtString.d.ts +1 -1
  58. package/dist/esm/shared/page-configs/helpers/getConfigDefinedAtString.js +1 -1
  59. package/dist/esm/shared/route/executeGuardHook.js +4 -3
  60. package/dist/esm/shared/route/executeOnBeforeRouteHook.d.ts +1 -8
  61. package/dist/esm/shared/route/executeOnBeforeRouteHook.js +6 -6
  62. package/dist/esm/shared/route/index.d.ts +2 -2
  63. package/dist/esm/shared/route/loadPageRoutes.d.ts +2 -2
  64. package/dist/esm/shared/route/loadPageRoutes.js +11 -16
  65. package/dist/esm/shared/route/resolveRedirects.js +8 -5
  66. package/dist/esm/utils/parseUrl-extras.d.ts +2 -0
  67. package/dist/esm/utils/parseUrl-extras.js +5 -0
  68. package/dist/esm/utils/parseUrl.js +24 -16
  69. package/dist/esm/utils/projectInfo.d.ts +2 -2
  70. package/dist/esm/utils/projectInfo.js +1 -1
  71. package/package.json +3 -3
  72. /package/dist/cjs/shared/page-configs/serialize/{assertPageConfigs.js → assertPageConfigsSerialized.js} +0 -0
  73. /package/dist/esm/shared/page-configs/serialize/{assertPageConfigs.d.ts → assertPageConfigsSerialized.d.ts} +0 -0
  74. /package/dist/esm/shared/page-configs/serialize/{assertPageConfigs.js → assertPageConfigsSerialized.js} +0 -0
@@ -12,7 +12,7 @@ import { HttpResponse } from './createHttpResponseObject.js';
12
12
  import { PageContext_loadPageFilesServerSide, type PageFiles } from './loadPageFilesServerSide.js';
13
13
  import type { PageConfigRuntime, PageConfigGlobalRuntime } from '../../../shared/page-configs/PageConfig.js';
14
14
  import { type PageRoutes } from '../../../shared/route/loadPageRoutes.js';
15
- import type { OnBeforeRouteHook } from '../../../shared/route/executeOnBeforeRouteHook.js';
15
+ import type { Hook } from '../../../shared/hooks/getHook.js';
16
16
  type PageContextAfterRender = {
17
17
  httpResponse: null | HttpResponse;
18
18
  errorWhileRendering: null | Error;
@@ -46,7 +46,7 @@ declare function prerenderPage(pageContext: PageContextInitEnhanced & PageFiles
46
46
  _pageConfigGlobal: PageConfigGlobalRuntime;
47
47
  _allPageIds: string[];
48
48
  _pageRoutes: PageRoutes;
49
- _onBeforeRouteHook: OnBeforeRouteHook | null;
49
+ _onBeforeRouteHook: Hook | null;
50
50
  _pageContextInit: {
51
51
  urlOriginal: string;
52
52
  };
@@ -93,7 +93,7 @@ declare function prerenderPage(pageContext: PageContextInitEnhanced & PageFiles
93
93
  _pageConfigGlobal: PageConfigGlobalRuntime;
94
94
  _allPageIds: string[];
95
95
  _pageRoutes: PageRoutes;
96
- _onBeforeRouteHook: OnBeforeRouteHook | null;
96
+ _onBeforeRouteHook: Hook | null;
97
97
  _pageContextInit: {
98
98
  urlOriginal: string;
99
99
  };
@@ -141,7 +141,7 @@ declare function prerender404Page(renderContext: RenderContext, pageContextInit_
141
141
  _pageConfigGlobal: PageConfigGlobalRuntime;
142
142
  _allPageIds: string[];
143
143
  _pageRoutes: PageRoutes;
144
- _onBeforeRouteHook: OnBeforeRouteHook | null;
144
+ _onBeforeRouteHook: Hook | null;
145
145
  _pageContextInit: {
146
146
  urlOriginal: string;
147
147
  };
@@ -188,7 +188,7 @@ declare function prerender404Page(renderContext: RenderContext, pageContextInit_
188
188
  _pageConfigGlobal: PageConfigGlobalRuntime;
189
189
  _allPageIds: string[];
190
190
  _pageRoutes: PageRoutes;
191
- _onBeforeRouteHook: OnBeforeRouteHook | null;
191
+ _onBeforeRouteHook: Hook | null;
192
192
  _pageContextInit: {
193
193
  urlOriginal: string;
194
194
  };
@@ -243,7 +243,7 @@ declare function getPageContextInitEnhanced(pageContextInit: {
243
243
  _pageConfigGlobal: PageConfigGlobalRuntime;
244
244
  _allPageIds: string[];
245
245
  _pageRoutes: PageRoutes;
246
- _onBeforeRouteHook: OnBeforeRouteHook | null;
246
+ _onBeforeRouteHook: Hook | null;
247
247
  _pageContextInit: {
248
248
  urlOriginal: string;
249
249
  };
@@ -260,6 +260,6 @@ type RenderContext = {
260
260
  pageConfigGlobal: PageConfigGlobalRuntime;
261
261
  allPageIds: string[];
262
262
  pageRoutes: PageRoutes;
263
- onBeforeRouteHook: OnBeforeRouteHook | null;
263
+ onBeforeRouteHook: Hook | null;
264
264
  };
265
265
  declare function getRenderContext(): Promise<RenderContext>;
@@ -6,7 +6,7 @@ export { getRenderContext };
6
6
  import { getErrorPageId } from '../../../shared/error-page.js';
7
7
  import { getHtmlString } from '../html/renderHtml.js';
8
8
  import { getPageFilesAll } from '../../../shared/getPageFiles.js';
9
- import { assert, assertUsage, hasProp, isNotNullish, objectAssign, unique } from '../utils.js';
9
+ import { assert, assertUsage, assertWarning, hasProp, isNotNullish, objectAssign, unique } from '../utils.js';
10
10
  import { serializePageContextClientSide } from '../html/serializePageContextClientSide.js';
11
11
  import { addUrlComputedProps } from '../../../shared/addUrlComputedProps.js';
12
12
  import { getGlobalContext } from '../globalContext.js';
@@ -150,7 +150,7 @@ async function getRenderContext() {
150
150
  const globalContext = getGlobalContext();
151
151
  const { pageFilesAll, allPageIds, pageConfigs, pageConfigGlobal } = await getPageFilesAll(false, globalContext.isProduction);
152
152
  const { pageRoutes, onBeforeRouteHook } = await loadPageRoutes(pageFilesAll, pageConfigs, pageConfigGlobal, allPageIds);
153
- assertNonMixedDesign(pageFilesAll, pageConfigs);
153
+ assertV1Design(pageFilesAll, pageConfigs);
154
154
  const renderContext = {
155
155
  pageFilesAll: pageFilesAll,
156
156
  pageConfigs,
@@ -161,21 +161,24 @@ async function getRenderContext() {
161
161
  };
162
162
  return renderContext;
163
163
  }
164
- function assertNonMixedDesign(pageFilesAll, pageConfigs) {
165
- if (pageFilesAll.length === 0 || pageConfigs.length === 0)
166
- return;
167
- const indent = '- ';
168
- const v1Files = unique(pageConfigs
169
- .map((p) => Object.values(p.configValues)
170
- .map(getConfigValueFilePathToShowToUser)
171
- .filter(isNotNullish)
172
- .map((filePathToShowToUser) => indent + filePathToShowToUser))
173
- .flat(2));
174
- assertUsage(false, [
175
- 'Mixing the new V1 design with the old V0.4 design is forbidden.',
176
- 'V1 files:',
177
- ...v1Files,
178
- 'V0.4 files:',
179
- ...pageFilesAll.map((p) => indent + p.filePath)
180
- ].join('\n'));
164
+ function assertV1Design(pageFilesAll, pageConfigs) {
165
+ const isV1Design = pageConfigs.length !== 0;
166
+ const isDesignOld = pageFilesAll.length !== 0;
167
+ if (isV1Design && isDesignOld) {
168
+ const indent = '- ';
169
+ const v1Files = unique(pageConfigs
170
+ .map((p) => Object.values(p.configValues)
171
+ .map(getConfigValueFilePathToShowToUser)
172
+ .filter(isNotNullish)
173
+ .map((filePathToShowToUser) => indent + filePathToShowToUser))
174
+ .flat(2));
175
+ assertUsage(false, [
176
+ 'Mixing the new V1 design with the old V0.4 design is forbidden.',
177
+ 'V1 files:',
178
+ ...v1Files,
179
+ 'V0.4 files:',
180
+ ...pageFilesAll.map((p) => indent + p.filePath)
181
+ ].join('\n'));
182
+ }
183
+ assertWarning(!isDesignOld, 'You are using the old deprecated design, update to the new V1 design, see https://vike.dev/migration/v1-design', { onlyOnce: true });
181
184
  }
@@ -2,7 +2,7 @@ export { renderPage };
2
2
  export { renderPage_addWrapper };
3
3
  import { getRenderContext, getPageContextInitEnhanced, renderPageAlreadyRouted } from './renderPage/renderPageAlreadyRouted.js';
4
4
  import { route } from '../../shared/route/index.js';
5
- import { assert, hasProp, objectAssign, isParsable, parseUrl, assertEnv, assertWarning, getGlobalObject, checkType, assertUsage, normalizeUrlPathname, removeBaseServer, modifyUrlPathname, prependBase, removeUrlOrigin, addUrlOrigin } from './utils.js';
5
+ import { assert, hasProp, objectAssign, isParsable, parseUrl, assertEnv, assertWarning, getGlobalObject, checkType, assertUsage, normalizeUrlPathname, removeBaseServer, modifyUrlPathname, prependBase, removeUrlOrigin, addUrlOrigin, createUrlFromComponents } from './utils.js';
6
6
  import { assertNoInfiniteAbortLoop, getPageContextFromAllRewrites, isAbortError, logAbortErrorHandled } from '../../shared/route/abort.js';
7
7
  import { getGlobalContext, initGlobalContext } from './globalContext.js';
8
8
  import { handlePageContextRequestUrl } from './renderPage/handlePageContextRequestUrl.js';
@@ -34,17 +34,17 @@ async function renderPage(pageContextInit) {
34
34
  assertArguments(...arguments);
35
35
  assert(hasProp(pageContextInit, 'urlOriginal', 'string'));
36
36
  assertEnv();
37
- if (skipRequest(pageContextInit.urlOriginal)) {
38
- const pageContextHttpReponseNull = getPageContextHttpResponseNull(pageContextInit);
39
- checkType(pageContextHttpReponseNull);
40
- return pageContextHttpReponseNull;
37
+ if (isIgnoredUrl(pageContextInit.urlOriginal)) {
38
+ const pageContextHttpResponseNull = getPageContextHttpResponseNull(pageContextInit);
39
+ checkType(pageContextHttpResponseNull);
40
+ return pageContextHttpResponseNull;
41
41
  }
42
42
  const httpRequestId = getRequestId();
43
- const urlToShowToUser = pageContextInit.urlOriginal;
44
- logHttpRequest(urlToShowToUser, httpRequestId);
43
+ const { urlOriginal } = pageContextInit;
44
+ logHttpRequest(urlOriginal, httpRequestId);
45
45
  globalObject.pendingRequestsCount++;
46
46
  const { pageContextReturn, onRequestDone } = await renderPage_wrapper(httpRequestId, () => renderPageAndPrepare(pageContextInit, httpRequestId));
47
- logHttpResponse(urlToShowToUser, httpRequestId, pageContextReturn);
47
+ logHttpResponse(urlOriginal, httpRequestId, pageContextReturn);
48
48
  globalObject.pendingRequestsCount--;
49
49
  onRequestDone();
50
50
  checkType(pageContextReturn);
@@ -54,8 +54,8 @@ async function renderPageAndPrepare(pageContextInit, httpRequestId) {
54
54
  // Invalid config
55
55
  const handleInvalidConfig = () => {
56
56
  logRuntimeInfo?.(pc.bold(pc.red("Couldn't load configuration: see error above.")), httpRequestId, 'error');
57
- const pageContextHttpReponseNull = getPageContextHttpResponseNull(pageContextInit);
58
- return pageContextHttpReponseNull;
57
+ const pageContextHttpResponseNull = getPageContextHttpResponseNull(pageContextInit);
58
+ return pageContextHttpResponseNull;
59
59
  };
60
60
  if (isConfigInvalid) {
61
61
  return handleInvalidConfig();
@@ -71,8 +71,8 @@ async function renderPageAndPrepare(pageContextInit, httpRequestId) {
71
71
  // initGlobalContext() and getRenderContext() don't call any user hooks => err isn't thrown from user code
72
72
  assert(!isAbortError(err));
73
73
  logRuntimeError(err, httpRequestId);
74
- const pageContextHttpReponseNull = getPageContextHttpResponseNullWithError(err, pageContextInit);
75
- return pageContextHttpReponseNull;
74
+ const pageContextHttpResponseNull = getPageContextHttpResponseNullWithError(err, pageContextInit);
75
+ return pageContextHttpResponseNull;
76
76
  }
77
77
  if (isConfigInvalid) {
78
78
  return handleInvalidConfig();
@@ -80,15 +80,23 @@ async function renderPageAndPrepare(pageContextInit, httpRequestId) {
80
80
  else {
81
81
  // From now on, renderContext.pageConfigs contains all the configuration data; getVikeConfig() isn't called anymore for this request
82
82
  }
83
+ // Check Base URL
84
+ {
85
+ const pageContextHttpResponse = checkBaseUrl(pageContextInit, httpRequestId);
86
+ if (pageContextHttpResponse)
87
+ return pageContextHttpResponse;
88
+ }
89
+ // Normalize URL
83
90
  {
84
- const pageContextHttpReponse = normalizeUrl(pageContextInit, httpRequestId);
85
- if (pageContextHttpReponse)
86
- return pageContextHttpReponse;
91
+ const pageContextHttpResponse = normalizeUrl(pageContextInit, httpRequestId);
92
+ if (pageContextHttpResponse)
93
+ return pageContextHttpResponse;
87
94
  }
95
+ // Permanent redirects (HTTP status code `301`)
88
96
  {
89
- const pageContextHttpReponse = getPermanentRedirect(pageContextInit, httpRequestId);
90
- if (pageContextHttpReponse)
91
- return pageContextHttpReponse;
97
+ const pageContextHttpResponse = getPermanentRedirect(pageContextInit, httpRequestId);
98
+ if (pageContextHttpResponse)
99
+ return pageContextHttpResponse;
92
100
  }
93
101
  return await renderPageAlreadyPrepared(pageContextInit, httpRequestId, renderContext, []);
94
102
  }
@@ -171,8 +179,8 @@ async function renderPageAlreadyPrepared(pageContextInit, httpRequestId, renderC
171
179
  if (!handled.pageContextReturn) {
172
180
  const pageContextAbort = errErrorPage._pageContextAbort;
173
181
  assertWarning(false, `Failed to render error page because ${pc.cyan(pageContextAbort._abortCall)} was called: make sure ${pc.cyan(pageContextAbort._abortCaller)} doesn't occur while the error page is being rendered.`, { onlyOnce: false });
174
- const pageContextHttpReponseNull = getPageContextHttpResponseNullWithError(errNominalPage, pageContextInit);
175
- return pageContextHttpReponseNull;
182
+ const pageContextHttpResponseNull = getPageContextHttpResponseNullWithError(errNominalPage, pageContextInit);
183
+ return pageContextHttpResponseNull;
176
184
  }
177
185
  // `throw redirect()` / `throw render(url)`
178
186
  return handled.pageContextReturn;
@@ -180,18 +188,28 @@ async function renderPageAlreadyPrepared(pageContextInit, httpRequestId, renderC
180
188
  if (isNewError(errErrorPage, errNominalPage)) {
181
189
  logRuntimeError(errErrorPage, httpRequestId);
182
190
  }
183
- const pageContextHttpReponseNull = getPageContextHttpResponseNullWithError(errNominalPage, pageContextInit);
184
- return pageContextHttpReponseNull;
191
+ const pageContextHttpResponseNull = getPageContextHttpResponseNullWithError(errNominalPage, pageContextInit);
192
+ return pageContextHttpResponseNull;
185
193
  }
186
194
  return pageContextErrorPage;
187
195
  }
188
196
  }
189
- function logHttpRequest(urlToShowToUser, httpRequestId) {
197
+ function logHttpRequest(urlOriginal, httpRequestId) {
190
198
  const clearErrors = globalObject.pendingRequestsCount === 0;
191
- logRuntimeInfo?.(`HTTP request: ${pc.bold(urlToShowToUser)}`, httpRequestId, 'info', clearErrors);
199
+ logRuntimeInfo?.(getRequestInfoMessage(urlOriginal), httpRequestId, 'info', clearErrors);
192
200
  }
193
- function logHttpResponse(urlToShowToUser, httpRequestId, pageContextReturn) {
201
+ function getRequestInfoMessage(urlOriginal) {
202
+ return `HTTP request: ${pc.bold(urlOriginal)}`;
203
+ }
204
+ function logHttpResponse(urlOriginal, httpRequestId, pageContextReturn) {
194
205
  const statusCode = pageContextReturn.httpResponse?.statusCode ?? null;
206
+ {
207
+ // If URL doesn't include Base URL
208
+ const { errorWhileRendering } = pageContextReturn;
209
+ const isSkipped = statusCode === null && (errorWhileRendering === null || errorWhileRendering === undefined);
210
+ if (isSkipped)
211
+ return;
212
+ }
195
213
  const isSuccess = statusCode !== null && statusCode >= 200 && statusCode <= 399;
196
214
  const isNominal = isSuccess || statusCode === 404;
197
215
  const color = (s) => pc.bold(isSuccess ? pc.green(String(s)) : pc.red(String(s)));
@@ -205,39 +223,30 @@ function logHttpResponse(urlToShowToUser, httpRequestId, pageContextReturn) {
205
223
  .find((header) => header[0] === 'Location');
206
224
  assert(headerRedirect);
207
225
  const urlRedirect = headerRedirect[1];
208
- urlToShowToUser = urlRedirect;
226
+ urlOriginal = urlRedirect;
209
227
  }
210
- logRuntimeInfo?.(`HTTP ${type} ${pc.bold(urlToShowToUser)} ${color(statusCode ?? 'ERR')}`, httpRequestId, isNominal ? 'info' : 'error');
228
+ logRuntimeInfo?.(`HTTP ${type} ${pc.bold(urlOriginal)} ${color(statusCode ?? 'ERR')}`, httpRequestId, isNominal ? 'info' : 'error');
211
229
  }
212
230
  function getPageContextHttpResponseNullWithError(err, pageContextInit) {
213
- const pageContextHttpReponseNull = {};
214
- objectAssign(pageContextHttpReponseNull, pageContextInit);
215
- objectAssign(pageContextHttpReponseNull, {
231
+ const pageContextHttpResponseNull = {};
232
+ objectAssign(pageContextHttpResponseNull, pageContextInit);
233
+ objectAssign(pageContextHttpResponseNull, {
216
234
  httpResponse: null,
217
235
  errorWhileRendering: err
218
236
  });
219
- return pageContextHttpReponseNull;
237
+ return pageContextHttpResponseNull;
220
238
  }
221
239
  function getPageContextHttpResponseNull(pageContextInit) {
222
- const pageContextHttpReponseNull = {};
223
- objectAssign(pageContextHttpReponseNull, pageContextInit);
224
- objectAssign(pageContextHttpReponseNull, {
240
+ const pageContextHttpResponseNull = {};
241
+ objectAssign(pageContextHttpResponseNull, pageContextInit);
242
+ objectAssign(pageContextHttpResponseNull, {
225
243
  httpResponse: null,
226
244
  errorWhileRendering: null
227
245
  });
228
- return pageContextHttpReponseNull;
246
+ return pageContextHttpResponseNull;
229
247
  }
230
248
  async function renderPageNominal(pageContext) {
231
249
  objectAssign(pageContext, { errorWhileRendering: null });
232
- // Check Base URL
233
- {
234
- const { urlWithoutPageContextRequestSuffix } = handlePageContextRequestUrl(pageContext.urlOriginal);
235
- const hasBaseServer = parseUrl(urlWithoutPageContextRequestSuffix, pageContext._baseServer).hasBaseServer || !!pageContext._urlRewrite;
236
- if (!hasBaseServer) {
237
- objectAssign(pageContext, { httpResponse: null });
238
- return pageContext;
239
- }
240
- }
241
250
  // Route
242
251
  {
243
252
  const pageContextFromRoute = await route(pageContext);
@@ -303,7 +312,7 @@ function getRequestId() {
303
312
  assert(httpRequestId >= 1);
304
313
  return httpRequestId;
305
314
  }
306
- function skipRequest(urlOriginal) {
315
+ function isIgnoredUrl(urlOriginal) {
307
316
  const isViteClientRequest = urlOriginal.endsWith('/@vite/client') || urlOriginal.startsWith('/@fs/');
308
317
  assertWarning(!isViteClientRequest, `The vike middleware renderPage() was called with the URL ${urlOriginal} which is unexpected because the HTTP request should have already been handled by Vite's development middleware. Make sure to 1. install Vite's development middleware and 2. add Vite's middleware *before* Vike's middleware, see https://vike.dev/renderPage`, { onlyOnce: true });
309
318
  return (urlOriginal.endsWith('/__vite_ping') ||
@@ -327,10 +336,8 @@ function normalizeUrl(pageContextInit, httpRequestId) {
327
336
  function getPermanentRedirect(pageContextInit, httpRequestId) {
328
337
  const { redirects, baseServer } = getGlobalContext();
329
338
  const urlWithoutBase = removeBaseServer(pageContextInit.urlOriginal, baseServer);
330
- let urlOriginalPathnameWithouBase;
331
339
  let origin = null;
332
340
  let urlTarget = modifyUrlPathname(urlWithoutBase, (urlPathname) => {
333
- urlOriginalPathnameWithouBase = urlPathname;
334
341
  const urlTargetWithOrigin = resolveRedirects(redirects, urlPathname);
335
342
  if (urlTargetWithOrigin === null)
336
343
  return null;
@@ -340,13 +347,12 @@ function getPermanentRedirect(pageContextInit, httpRequestId) {
340
347
  });
341
348
  if (origin)
342
349
  urlTarget = addUrlOrigin(urlTarget, origin);
343
- assert(urlOriginalPathnameWithouBase);
344
350
  if (urlTarget === urlWithoutBase)
345
351
  return null;
346
352
  logRuntimeInfo?.(`Permanent redirect defined by your config.redirects (https://vike.dev/redirects)`, httpRequestId, 'info');
347
353
  urlTarget = prependBase(urlTarget, baseServer);
348
354
  assert(urlTarget !== pageContextInit.urlOriginal);
349
- const httpResponse = createHttpResponseObjectRedirect({ url: urlTarget, statusCode: 301 }, urlOriginalPathnameWithouBase);
355
+ const httpResponse = createHttpResponseObjectRedirect({ url: urlTarget, statusCode: 301 }, urlWithoutBase);
350
356
  const pageContextHttpResponse = { ...pageContextInit, httpResponse };
351
357
  return pageContextHttpResponse;
352
358
  }
@@ -390,10 +396,28 @@ async function handleAbortError(errAbort, pageContextsFromRewrite, pageContextIn
390
396
  ...pageContextInit,
391
397
  ...pageContextAbort
392
398
  };
393
- const httpResponse = createHttpResponseObjectRedirect(pageContextAbort._urlRedirect, pageContextNominalPageInit.urlPathname);
399
+ const httpResponse = createHttpResponseObjectRedirect(pageContextAbort._urlRedirect, (() => {
400
+ const { pathname, searchOriginal } = pageContextNominalPageInit.urlParsed;
401
+ const urlLogical = createUrlFromComponents(null, pathname, searchOriginal,
402
+ // The server-side doesn't have access to the hash
403
+ null);
404
+ return urlLogical;
405
+ })());
394
406
  objectAssign(pageContextReturn, { httpResponse });
395
407
  return { pageContextReturn };
396
408
  }
397
409
  assert(pageContextAbort.abortStatusCode);
398
410
  return { pageContextAbort };
399
411
  }
412
+ function checkBaseUrl(pageContextInit, httpRequestId) {
413
+ const { baseServer } = getGlobalContext();
414
+ const { urlOriginal } = pageContextInit;
415
+ const { urlWithoutPageContextRequestSuffix } = handlePageContextRequestUrl(urlOriginal);
416
+ const { hasBaseServer } = parseUrl(urlWithoutPageContextRequestSuffix, baseServer);
417
+ if (!hasBaseServer) {
418
+ logRuntimeInfo?.(`${getRequestInfoMessage(urlOriginal)} skipped because URL ${pc.bold(urlOriginal)} doesn't start with Base URL ${pc.bold(baseServer)} (https://vike.dev/base-url)`, httpRequestId, 'info');
419
+ const pageContextHttpResponseNull = getPageContextHttpResponseNull(pageContextInit);
420
+ return pageContextHttpResponseNull;
421
+ }
422
+ return null;
423
+ }
@@ -3,7 +3,7 @@ import { assert, hasProp, isCallable, isObject, cast, assertUsage } from '../uti
3
3
  import { assertExportValues } from './assert_exports_old_design.js';
4
4
  import { getPageFileObject } from './getPageFileObject.js';
5
5
  import { fileTypes } from './fileTypes.js';
6
- import { assertPageConfigGlobalSerialized, assertPageConfigsSerialized } from '../page-configs/serialize/assertPageConfigs.js';
6
+ import { assertPageConfigGlobalSerialized, assertPageConfigsSerialized } from '../page-configs/serialize/assertPageConfigsSerialized.js';
7
7
  import { parsePageConfigs } from '../page-configs/serialize/parsePageConfigs.js';
8
8
  function parseGlobResults(pageFilesExports) {
9
9
  assert(hasProp(pageFilesExports, 'isGeneratedFile'));
@@ -1,5 +1,5 @@
1
1
  export { executeHook };
2
2
  export { isUserHookError };
3
- import type { HookLoc, HookName } from './getHook.js';
3
+ import type { Hook, HookLoc } from './getHook.js';
4
4
  declare function isUserHookError(err: unknown): false | HookLoc;
5
- declare function executeHook<T = unknown>(hookFn: () => T, hookName: HookName, hookFilePath: string): Promise<T>;
5
+ declare function executeHook<T = unknown>(hookFnCaller: () => T, hook: Omit<Hook, 'hookFn'>): Promise<T>;
@@ -12,8 +12,8 @@ function isUserHookError(err) {
12
12
  return false;
13
13
  return globalObject.userHookErrors.get(err) ?? false;
14
14
  }
15
- function executeHook(hookFn, hookName, hookFilePath) {
16
- const { timeoutErr, timeoutWarn } = getTimeouts(hookName);
15
+ function executeHook(hookFnCaller, hook) {
16
+ const { hookName, hookFilePath, hookTimeout: { error: timeoutErr, warning: timeoutWarn } } = hook;
17
17
  let resolve;
18
18
  let reject;
19
19
  const promise = new Promise((resolve_, reject_) => {
@@ -27,19 +27,23 @@ function executeHook(hookFn, hookName, hookFilePath) {
27
27
  };
28
28
  });
29
29
  const clearTimeouts = () => {
30
- clearTimeout(t1);
31
- clearTimeout(t2);
30
+ if (currentTimeoutWarn)
31
+ clearTimeout(currentTimeoutWarn);
32
+ if (currentTimeoutErr)
33
+ clearTimeout(currentTimeoutErr);
32
34
  };
33
- const t1 = setTimeout(() => {
34
- assertWarning(false, `The ${hookName}() hook defined by ${hookFilePath} is taking more than ${humanizeTime(timeoutWarn)}`, { onlyOnce: false });
35
- }, timeoutWarn);
36
- const t2 = setTimeout(() => {
37
- const err = getProjectError(`Hook timeout: the ${hookName}() hook defined by ${hookFilePath} didn't finish after ${humanizeTime(timeoutErr)}`);
38
- reject(err);
39
- }, timeoutErr);
35
+ const currentTimeoutWarn = isNotDisabled(timeoutWarn) &&
36
+ setTimeout(() => {
37
+ assertWarning(false, `The ${hookName}() hook defined by ${hookFilePath} is slow: it's taking more than ${humanizeTime(timeoutWarn)} (https://vike.dev/hooksTimeout)`, { onlyOnce: false });
38
+ }, timeoutWarn);
39
+ const currentTimeoutErr = isNotDisabled(timeoutErr) &&
40
+ setTimeout(() => {
41
+ const err = getProjectError(`The ${hookName}() hook defined by ${hookFilePath} timed out: it didn't finish after ${humanizeTime(timeoutErr)} (https://vike.dev/hooksTimeout)`);
42
+ reject(err);
43
+ }, timeoutErr);
40
44
  (async () => {
41
45
  try {
42
- const ret = await hookFn();
46
+ const ret = await hookFnCaller();
43
47
  resolve(ret);
44
48
  }
45
49
  catch (err) {
@@ -51,21 +55,6 @@ function executeHook(hookFn, hookName, hookFilePath) {
51
55
  })();
52
56
  return promise;
53
57
  }
54
- function getTimeouts(hookName) {
55
- if (hookName === 'onBeforeRoute') {
56
- return {
57
- timeoutErr: 5 * 1000,
58
- timeoutWarn: 1 * 1000
59
- };
60
- }
61
- if (hookName === 'onBeforePrerender') {
62
- return {
63
- timeoutErr: 10 * 60 * 1000,
64
- timeoutWarn: 30 * 1000
65
- };
66
- }
67
- return {
68
- timeoutErr: 40 * 1000,
69
- timeoutWarn: 4 * 1000
70
- };
58
+ function isNotDisabled(timeout) {
59
+ return !!timeout && timeout !== Infinity;
71
60
  }
@@ -1,24 +1,34 @@
1
1
  export { getHook };
2
+ export { getHookFromPageConfig };
3
+ export { getHookFromPageConfigGlobal };
2
4
  export { assertHook };
3
- export { assertHookFn };
4
5
  export type { Hook };
5
6
  export type { HookName };
6
7
  export type { HookLoc };
7
- import { PageContextExports } from '../getPageFiles.js';
8
- import type { HookName } from '../page-configs/Config.js';
8
+ export type { HookTimeout };
9
+ export type { HooksTimeoutProvidedByUser };
10
+ export { getHookTimeoutDefault };
11
+ import type { PageContextExports } from '../getPageFiles.js';
12
+ import type { HookName, HookNamePage, HookNameGlobal } from '../page-configs/Config.js';
13
+ import type { PageConfigBuildTime, PageConfigGlobalRuntime, PageConfigRuntime } from '../page-configs/PageConfig.js';
9
14
  type Hook = HookLoc & {
10
15
  hookFn: HookFn;
16
+ hookTimeout: HookTimeout;
11
17
  };
12
18
  type HookLoc = {
13
19
  hookName: HookName;
14
20
  hookFilePath: string;
15
21
  };
16
22
  type HookFn = (arg: unknown) => unknown;
23
+ type HookTimeout = {
24
+ error: number | false;
25
+ warning: number | false;
26
+ };
27
+ type HooksTimeoutProvidedByUser = false | Partial<Record<HookName, false | Partial<HookTimeout>>>;
17
28
  declare function getHook(pageContext: PageContextExports, hookName: HookName): null | Hook;
29
+ declare function getHookFromPageConfig(pageConfig: PageConfigRuntime | PageConfigBuildTime, hookName: HookNamePage): null | Hook;
30
+ declare function getHookFromPageConfigGlobal(pageConfigGlobal: PageConfigGlobalRuntime, hookName: HookNameGlobal): null | Hook;
18
31
  declare function assertHook<TPageContext extends PageContextExports, THookName extends PropertyKey & HookName>(pageContext: TPageContext, hookName: THookName): asserts pageContext is TPageContext & {
19
32
  exports: Record<THookName, Function | undefined>;
20
33
  };
21
- declare function assertHookFn(hookFn: unknown, { hookName, hookFilePath }: {
22
- hookName: HookName;
23
- hookFilePath: string;
24
- }): asserts hookFn is HookFn;
34
+ declare function getHookTimeoutDefault(hookName: HookName): HookTimeout;
@@ -1,11 +1,19 @@
1
1
  export { getHook };
2
+ export { getHookFromPageConfig };
3
+ export { getHookFromPageConfigGlobal };
2
4
  export { assertHook };
3
- export { assertHookFn };
4
- import { assert, assertUsage, checkType, isCallable } from '../utils.js';
5
+ // TODO/v1-release: remove
6
+ // We export for old V0.4 design which doesn't support config.hooksTimeout
7
+ export { getHookTimeoutDefault };
8
+ import { getConfigValue, getHookFilePathToShowToUser } from '../page-configs/helpers.js';
9
+ import { assert, assertUsage, checkType, isCallable, isObject } from '../utils.js';
10
+ import pc from '@brillout/picocolors';
5
11
  function getHook(pageContext, hookName) {
6
12
  if (!(hookName in pageContext.exports)) {
7
13
  return null;
8
14
  }
15
+ const { hooksTimeout } = pageContext.config;
16
+ const hookTimeout = getHookTimeout(hooksTimeout, hookName);
9
17
  const hookFn = pageContext.exports[hookName];
10
18
  const file = pageContext.exportsAll[hookName][0];
11
19
  assert(file.exportValue === hookFn);
@@ -15,7 +23,37 @@ function getHook(pageContext, hookName) {
15
23
  assert(hookFilePath);
16
24
  assert(!hookFilePath.endsWith(' '));
17
25
  assertHookFn(hookFn, { hookName, hookFilePath });
18
- return { hookFn, hookName, hookFilePath };
26
+ return { hookFn, hookName, hookFilePath, hookTimeout };
27
+ }
28
+ function getHookFromPageConfig(pageConfig, hookName) {
29
+ const configValue = getConfigValue(pageConfig, hookName);
30
+ const hooksTimeout = getConfigValue(pageConfig, 'hooksTimeout')?.value;
31
+ if (!configValue)
32
+ return null;
33
+ const hookFn = configValue.value;
34
+ if (!hookFn)
35
+ return null;
36
+ const hookFilePath = getHookFilePathToShowToUser(configValue);
37
+ // hook isn't a computed nor a cumulative config => definedAt should always be defined
38
+ assert(hookFilePath);
39
+ assertHookFn(hookFn, { hookName, hookFilePath });
40
+ const hookTimeout = getHookTimeout(hooksTimeout, hookName);
41
+ return { hookFn, hookName, hookFilePath, hookTimeout };
42
+ }
43
+ function getHookFromPageConfigGlobal(pageConfigGlobal, hookName) {
44
+ const configValue = pageConfigGlobal.configValues[hookName];
45
+ if (!configValue)
46
+ return null;
47
+ const hookFn = configValue.value;
48
+ if (!hookFn)
49
+ return null;
50
+ const hookFilePath = getHookFilePathToShowToUser(configValue);
51
+ // hook isn't a computed nor a cumulative config => definedAt should always be defined
52
+ assert(hookFilePath);
53
+ assertHookFn(hookFn, { hookName, hookFilePath });
54
+ // We could use the global value of config.hooksTimeout but it requires some non-trivial refactoring
55
+ const hookTimeout = getHookTimeoutDefault(hookName);
56
+ return { hookFn, hookName, hookFilePath, hookTimeout };
19
57
  }
20
58
  function assertHook(pageContext, hookName) {
21
59
  getHook(pageContext, hookName);
@@ -26,3 +64,65 @@ function assertHookFn(hookFn, { hookName, hookFilePath }) {
26
64
  assertUsage(isCallable(hookFn), `Hook ${hookName}() defined by ${hookFilePath} should be a function`);
27
65
  checkType(hookFn);
28
66
  }
67
+ function getHookTimeout(hooksTimeoutProvidedByUser, hookName) {
68
+ const hooksTimeoutProvidedbyUserNormalized = getHooksTimeoutProvidedByUserNormalized(hooksTimeoutProvidedByUser);
69
+ if (hooksTimeoutProvidedbyUserNormalized === false)
70
+ return { error: false, warning: false };
71
+ const providedbyUser = hooksTimeoutProvidedbyUserNormalized[hookName];
72
+ const hookTimeout = getHookTimeoutDefault(hookName);
73
+ if (providedbyUser?.error !== undefined)
74
+ hookTimeout.error = providedbyUser.error;
75
+ if (providedbyUser?.warning !== undefined)
76
+ hookTimeout.warning = providedbyUser.warning;
77
+ return hookTimeout;
78
+ }
79
+ // Ideally this should be called only once and at build-time (to avoid bloating the client-side bundle), but we didn't implement any mechanism to valide config values at build-time yet
80
+ function getHooksTimeoutProvidedByUserNormalized(hooksTimeoutProvidedByUser) {
81
+ if (hooksTimeoutProvidedByUser === undefined)
82
+ return {};
83
+ if (hooksTimeoutProvidedByUser === false)
84
+ return false;
85
+ assertUsage(isObject(hooksTimeoutProvidedByUser), `Setting ${pc.cyan('hooksTimeout')} should be ${pc.cyan('false')} or an object`);
86
+ const hooksTimeoutProvidedByUserNormalized = {};
87
+ Object.entries(hooksTimeoutProvidedByUser).forEach(([hookName, hookTimeoutProvidedbyUser]) => {
88
+ if (hookTimeoutProvidedbyUser === false) {
89
+ hooksTimeoutProvidedByUserNormalized[hookName] = { error: false, warning: false };
90
+ return;
91
+ }
92
+ assertUsage(isObject(hookTimeoutProvidedbyUser), `Setting ${pc.cyan(`hooksTimeout.${hookName}`)} should be ${pc.cyan('false')} or an object`);
93
+ const [error, warning] = ['error', 'warning'].map((timeoutName) => {
94
+ const timeoutVal = hookTimeoutProvidedbyUser[timeoutName];
95
+ if (timeoutVal === undefined || timeoutVal === false)
96
+ return timeoutVal;
97
+ const errPrefix = `Setting ${pc.cyan(`hooksTimeout.${hookName}.${timeoutName}`)} should be`;
98
+ assertUsage(typeof timeoutVal === 'number', `${errPrefix} ${pc.cyan('false')} or a number`);
99
+ assertUsage(timeoutVal > 0, `${errPrefix} a positive number`);
100
+ return timeoutVal;
101
+ });
102
+ hooksTimeoutProvidedByUserNormalized[hookName] = { error, warning };
103
+ });
104
+ return hooksTimeoutProvidedByUserNormalized;
105
+ }
106
+ function getHookTimeoutDefault(hookName) {
107
+ if (hookName === 'onBeforeRoute') {
108
+ return {
109
+ error: 5 * 1000,
110
+ warning: 1 * 1000
111
+ };
112
+ }
113
+ if (hookName === 'onPrerenderStart' ||
114
+ hookName === 'onBeforePrerenderStart' ||
115
+ // TODO/v1-release: remove
116
+ // Old V0.4 design hooks (https://vike.dev/migration/v1-design#renamed-hooks)
117
+ hookName === 'onBeforePrerender' ||
118
+ hookName === 'prerender') {
119
+ return {
120
+ error: 10 * 60 * 1000,
121
+ warning: 30 * 1000
122
+ };
123
+ }
124
+ return {
125
+ error: 30 * 1000,
126
+ warning: 4 * 1000
127
+ };
128
+ }