vike 0.4.147-commit-f9a91f3 → 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 (52) 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 +12 -0
  4. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +28 -10
  5. package/dist/cjs/node/prerender/runPrerender.js +20 -22
  6. package/dist/cjs/node/runtime/html/renderHtml.js +1 -1
  7. package/dist/cjs/node/runtime/renderPage/executeOnBeforeRenderHook.js +1 -1
  8. package/dist/cjs/node/runtime/renderPage/executeOnRenderHtmlHook.js +3 -3
  9. package/dist/cjs/node/runtime/renderPage/renderPageAlreadyRouted.js +21 -18
  10. package/dist/cjs/shared/getPageFiles/parseGlobResults.js +3 -3
  11. package/dist/cjs/shared/hooks/executeHook.js +18 -29
  12. package/dist/cjs/shared/hooks/getHook.js +104 -3
  13. package/dist/cjs/shared/page-configs/helpers/getConfigDefinedAtString.js +1 -1
  14. package/dist/cjs/shared/route/executeGuardHook.js +3 -2
  15. package/dist/cjs/shared/route/executeOnBeforeRouteHook.js +4 -4
  16. package/dist/cjs/shared/route/loadPageRoutes.js +10 -15
  17. package/dist/cjs/utils/projectInfo.js +1 -1
  18. package/dist/esm/client/client-routing-runtime/createPageContext.d.ts +1 -1
  19. package/dist/esm/client/client-routing-runtime/getPageContextFromHooks.js +1 -1
  20. package/dist/esm/client/client-routing-runtime/renderPageClientSide.js +18 -12
  21. package/dist/esm/client/shared/executeOnRenderClientHook.js +1 -1
  22. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getConfigValuesSerialized.js +17 -12
  23. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/configDefinitionsBuiltIn.js +3 -0
  24. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.js +12 -0
  25. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +28 -10
  26. package/dist/esm/node/prerender/runPrerender.js +22 -24
  27. package/dist/esm/node/runtime/html/renderHtml.js +1 -1
  28. package/dist/esm/node/runtime/renderPage/executeOnBeforeRenderHook.js +1 -1
  29. package/dist/esm/node/runtime/renderPage/executeOnRenderHtmlHook.d.ts +2 -2
  30. package/dist/esm/node/runtime/renderPage/executeOnRenderHtmlHook.js +3 -3
  31. package/dist/esm/node/runtime/renderPage/renderPageAlreadyRouted.d.ts +7 -7
  32. package/dist/esm/node/runtime/renderPage/renderPageAlreadyRouted.js +22 -19
  33. package/dist/esm/shared/getPageFiles/parseGlobResults.js +1 -1
  34. package/dist/esm/shared/hooks/executeHook.d.ts +2 -2
  35. package/dist/esm/shared/hooks/executeHook.js +18 -29
  36. package/dist/esm/shared/hooks/getHook.d.ts +17 -7
  37. package/dist/esm/shared/hooks/getHook.js +103 -3
  38. package/dist/esm/shared/page-configs/Config.d.ts +21 -13
  39. package/dist/esm/shared/page-configs/helpers/getConfigDefinedAtString.d.ts +1 -1
  40. package/dist/esm/shared/page-configs/helpers/getConfigDefinedAtString.js +1 -1
  41. package/dist/esm/shared/route/executeGuardHook.js +4 -3
  42. package/dist/esm/shared/route/executeOnBeforeRouteHook.d.ts +1 -8
  43. package/dist/esm/shared/route/executeOnBeforeRouteHook.js +6 -6
  44. package/dist/esm/shared/route/index.d.ts +2 -2
  45. package/dist/esm/shared/route/loadPageRoutes.d.ts +2 -2
  46. package/dist/esm/shared/route/loadPageRoutes.js +11 -16
  47. package/dist/esm/utils/projectInfo.d.ts +2 -2
  48. package/dist/esm/utils/projectInfo.js +1 -1
  49. package/package.json +1 -1
  50. /package/dist/cjs/shared/page-configs/serialize/{assertPageConfigs.js → assertPageConfigsSerialized.js} +0 -0
  51. /package/dist/esm/shared/page-configs/serialize/{assertPageConfigs.d.ts → assertPageConfigsSerialized.d.ts} +0 -0
  52. /package/dist/esm/shared/page-configs/serialize/{assertPageConfigs.js → assertPageConfigsSerialized.js} +0 -0
@@ -7,6 +7,7 @@ const deduceRouteStringFromFilesystemPath_js_1 = require("./deduceRouteStringFro
7
7
  const utils_js_2 = require("../utils.js");
8
8
  const helpers_js_1 = require("../page-configs/helpers.js");
9
9
  const resolveRouteFunction_js_1 = require("./resolveRouteFunction.js");
10
+ const getHook_js_1 = require("../hooks/getHook.js");
10
11
  async function loadPageRoutes(
11
12
  // Remove all arguments and use GlobalContext instead?
12
13
  pageFilesAll, pageConfigs, pageConfigGlobal, allPageIds) {
@@ -139,20 +140,8 @@ function getPageRoutes(filesystemRoots, pageFilesAll, pageConfigs, allPageIds) {
139
140
  function getGlobalHooks(pageFilesAll, pageConfigs, pageConfigGlobal) {
140
141
  // V1 Design
141
142
  if (pageConfigs.length > 0) {
142
- const hookName = 'onBeforeRoute';
143
- if (pageConfigGlobal.configValues[hookName]?.value) {
144
- const configValue = pageConfigGlobal.configValues[hookName];
145
- const { value: hookFn } = configValue;
146
- const hookFilePath = (0, helpers_js_1.getHookFilePathToShowToUser)(configValue);
147
- const hookDefinedAt = (0, helpers_js_1.getConfigDefinedAtString)('Hook', hookName, configValue);
148
- (0, utils_js_1.assertUsage)((0, utils_js_2.isCallable)(hookFn), `${hookDefinedAt} should be a function.`);
149
- const onBeforeRouteHook = {
150
- hookFilePath: hookFilePath,
151
- onBeforeRoute: hookFn
152
- };
153
- return { onBeforeRouteHook, filesystemRoots: null };
154
- }
155
- return { onBeforeRouteHook: null, filesystemRoots: null };
143
+ const hook = (0, getHook_js_1.getHookFromPageConfigGlobal)(pageConfigGlobal, 'onBeforeRoute');
144
+ return { onBeforeRouteHook: hook, filesystemRoots: null };
156
145
  }
157
146
  // Old design
158
147
  // TODO/v1-release: remove
@@ -165,7 +154,13 @@ function getGlobalHooks(pageFilesAll, pageConfigs, pageConfigGlobal) {
165
154
  if ('onBeforeRoute' in fileExports) {
166
155
  (0, utils_js_1.assertUsage)((0, utils_js_1.hasProp)(fileExports, 'onBeforeRoute', 'function'), `\`export { onBeforeRoute }\` of ${filePath} should be a function.`);
167
156
  const { onBeforeRoute } = fileExports;
168
- onBeforeRouteHook = { hookFilePath: `${filePath} > \`export { onBeforeRoute }\``, onBeforeRoute };
157
+ const hookName = 'onBeforeRoute';
158
+ onBeforeRouteHook = {
159
+ hookFilePath: filePath,
160
+ hookFn: onBeforeRoute,
161
+ hookName,
162
+ hookTimeout: (0, getHook_js_1.getHookTimeoutDefault)(hookName)
163
+ };
169
164
  }
170
165
  if ('filesystemRoutingRoot' in fileExports) {
171
166
  (0, utils_js_1.assertUsage)((0, utils_js_1.hasProp)(fileExports, 'filesystemRoutingRoot', 'string'), `\`export { filesystemRoutingRoot }\` of ${filePath} should be a string.`);
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PROJECT_VERSION = exports.projectInfo = void 0;
4
4
  const assertSingleInstance_js_1 = require("./assertSingleInstance.js");
5
- const PROJECT_VERSION = '0.4.147-commit-f9a91f3';
5
+ const PROJECT_VERSION = '0.4.148-commit-7596dcd';
6
6
  exports.PROJECT_VERSION = PROJECT_VERSION;
7
7
  const projectInfo = {
8
8
  projectName: 'Vike',
@@ -11,7 +11,7 @@ declare function createPageContext(urlOriginal: string): Promise<{
11
11
  _pageConfigGlobal: import("../../shared/page-configs/PageConfig.js").PageConfigGlobalRuntime;
12
12
  _allPageIds: string[];
13
13
  _pageRoutes: import("../../shared/route/loadPageRoutes.js").PageRoutes;
14
- _onBeforeRouteHook: import("../../shared/route/executeOnBeforeRouteHook.js").OnBeforeRouteHook | null;
14
+ _onBeforeRouteHook: import("../../shared/hooks/getHook.js").Hook | null;
15
15
  } & import("../../shared/addUrlComputedProps.js").PageContextUrlComputedPropsClient & {
16
16
  _urlRewrite: string | null;
17
17
  }>;
@@ -132,7 +132,7 @@ async function executeOnBeforeRenderHookClientSide(pageContext) {
132
132
  ...pageContext,
133
133
  ...pageContextFromOnBeforeRender
134
134
  }, true);
135
- const hookResult = await executeHook(() => onBeforeRender(pageContextForUserConsumption), 'onBeforeRender', hook.hookFilePath);
135
+ const hookResult = await executeHook(() => onBeforeRender(pageContextForUserConsumption), hook);
136
136
  assertOnBeforeRenderHookReturn(hookResult, hook.hookFilePath);
137
137
  const pageContextFromHook = hookResult?.pageContext;
138
138
  objectAssign(pageContextFromOnBeforeRender, pageContextFromHook);
@@ -7,7 +7,7 @@ import { createPageContext } from './createPageContext.js';
7
7
  import { addLinkPrefetchHandlers } from './prefetch.js';
8
8
  import { assertInfo, assertWarning, isReact } from './utils.js';
9
9
  import { executeOnRenderClientHook } from '../shared/executeOnRenderClientHook.js';
10
- import { assertHook } from '../../shared/hooks/getHook.js';
10
+ import { assertHook, getHook } from '../../shared/hooks/getHook.js';
11
11
  import { isErrorFetchingStaticAssets } from '../shared/loadPageFilesClientSide.js';
12
12
  import { pushHistory } from './history.js';
13
13
  import { assertNoInfiniteAbortLoop, getPageContextFromAllRewrites, isAbortError, logAbortErrorHandled } from '../../shared/route/abort.js';
@@ -85,7 +85,11 @@ async function renderPageClientSide(renderArgs) {
85
85
  const callTransitionHooks = !isFirstRender;
86
86
  if (callTransitionHooks) {
87
87
  if (!globalObject.isTransitioning) {
88
- await globalObject.onPageTransitionStart?.(pageContext);
88
+ if (globalObject.onPageTransitionStart) {
89
+ const hook = globalObject.onPageTransitionStart;
90
+ const { hookFn } = hook;
91
+ await executeHook(() => hookFn(pageContext), hook);
92
+ }
89
93
  globalObject.isTransitioning = true;
90
94
  if (abortRender())
91
95
  return;
@@ -207,13 +211,14 @@ async function renderPageClientSide(renderArgs) {
207
211
  objectAssign(pageContext, pageContextFromHooks);
208
212
  // Set global onPageTransitionStart()
209
213
  assertHook(pageContext, 'onPageTransitionStart');
210
- globalObject.onPageTransitionStart = pageContext.exports.onPageTransitionStart;
214
+ const onPageTransitionStartHook = getHook(pageContext, 'onPageTransitionStart');
215
+ globalObject.onPageTransitionStart = onPageTransitionStartHook;
211
216
  // Set global hydrationCanBeAborted
212
217
  if (pageContext.exports.hydrationCanBeAborted) {
213
218
  setHydrationCanBeAborted();
214
219
  }
215
220
  else {
216
- assertWarning(!isReact(), 'You seem to be using React; we recommend setting hydrationCanBeAborted to true, see https://vike.dev/clientRouting', { onlyOnce: true });
221
+ assertWarning(!isReact(), 'You seem to be using React; we recommend setting hydrationCanBeAborted to true, see https://vike.dev/hydrationCanBeAborted', { onlyOnce: true });
217
222
  }
218
223
  // There wasn't any `await` but result may change because we just called setHydrationCanBeAborted()
219
224
  if (abortRender())
@@ -242,11 +247,10 @@ async function renderPageClientSide(renderArgs) {
242
247
  // onHydrationEnd()
243
248
  if (isFirstRender) {
244
249
  assertHook(pageContext, 'onHydrationEnd');
245
- const { onHydrationEnd } = pageContext.exports;
246
- if (onHydrationEnd) {
247
- const hookFilePath = pageContext.exportsAll.onHydrationEnd[0].exportSource;
248
- assert(hookFilePath);
249
- await executeHook(() => onHydrationEnd(pageContext), 'onHydrationEnd', hookFilePath);
250
+ const hook = getHook(pageContext, 'onHydrationEnd');
251
+ if (hook) {
252
+ const { hookFn } = hook;
253
+ await executeHook(() => hookFn(pageContext), hook);
250
254
  if (abortRender(true))
251
255
  return;
252
256
  }
@@ -256,9 +260,11 @@ async function renderPageClientSide(renderArgs) {
256
260
  return;
257
261
  // onPageTransitionEnd()
258
262
  if (callTransitionHooks) {
259
- if (pageContext.exports.onPageTransitionEnd) {
260
- assertHook(pageContext, 'onPageTransitionEnd');
261
- await pageContext.exports.onPageTransitionEnd(pageContext);
263
+ assertHook(pageContext, 'onPageTransitionEnd');
264
+ const hook = getHook(pageContext, 'onPageTransitionEnd');
265
+ if (hook) {
266
+ const { hookFn } = hook;
267
+ await executeHook(() => hookFn(pageContext), hook);
262
268
  if (abortRender(true))
263
269
  return;
264
270
  }
@@ -45,7 +45,7 @@ async function executeOnRenderClientHook(pageContext, isClientRouting) {
45
45
  const renderHook = hook.hookFn;
46
46
  assert(hookName);
47
47
  // We don't use a try-catch wrapper because rendering errors are usually handled by the UI framework. (E.g. React's Error Boundaries.)
48
- const hookResult = await executeHook(() => renderHook(pageContextForUserConsumption), hookName, hook.hookFilePath);
48
+ const hookResult = await executeHook(() => renderHook(pageContextForUserConsumption), hook);
49
49
  assertUsage(hookResult === undefined, `The ${hookName}() hook defined by ${hook.hookFilePath} isn't allowed to return a value`);
50
50
  }
51
51
  function getUrlToShowToUser(pageContext) {
@@ -1,7 +1,7 @@
1
1
  export { getConfigValuesSerialized };
2
2
  export { assertConfigValueIsSerializable };
3
3
  import { assert, assertUsage, getPropAccessNotation } from '../../../utils.js';
4
- import { isJsonSerializerError, stringify } from '@brillout/json-serializer/stringify';
4
+ import { stringify } from '@brillout/json-serializer/stringify';
5
5
  import pc from '@brillout/picocolors';
6
6
  import { getConfigValueFilePathToShowToUser } from '../../../../../shared/page-configs/helpers.js';
7
7
  import { serializeConfigValue } from '../../../../../shared/page-configs/serialize/serializeConfigValue.js';
@@ -47,22 +47,27 @@ function getConfigValueSerialized(value, configName, definedAt) {
47
47
  configValueSerialized = stringify(value, { valueName, forbidReactElements: true });
48
48
  }
49
49
  catch (err) {
50
- let serializationErrMsg = '';
50
+ /*
51
+ let serializationErrMsg = ''
51
52
  if (isJsonSerializerError(err)) {
52
- serializationErrMsg = err.messageCore;
53
- }
54
- else {
55
- // When a property getter throws an error
56
- console.error('Serialization error:');
57
- console.error(err);
58
- serializationErrMsg = 'see serialization error printed above';
53
+ serializationErrMsg = err.messageCore
54
+ } else {
55
+ // When a property getter throws an error
56
+ console.error('Serialization error:')
57
+ console.error(err)
58
+ serializationErrMsg = 'see serialization error printed above'
59
59
  }
60
+ */
60
61
  const configValueFilePathToShowToUser = getConfigValueFilePathToShowToUser({ definedAt });
61
62
  assert(configValueFilePathToShowToUser);
62
63
  assertUsage(false, [
63
- `The value of the config ${pc.cyan(configName)} cannot be defined inside the file ${configValueFilePathToShowToUser}:`,
64
- `its value must be defined in an another file and then imported by ${configValueFilePathToShowToUser}. (Because its value isn't serializable: ${serializationErrMsg}.)`,
65
- `Only serializable config values can be defined inside +config.h.js files, see https://vike.dev/header-file.`
64
+ `The code of ${pc.cyan(configName)} cannot live inside ${configValueFilePathToShowToUser},`,
65
+ 'see https://vike.dev/header-file#runtime-code'
66
+ /* I guess showing this is more confusing than adding value.
67
+ `(technically speaking: the value of ${pc.cyan(
68
+ configName
69
+ )} isn't serializable (${serializationErrMsg}) and it's therefore runtime code that needs to be imported).`
70
+ //*/
66
71
  ].join(' '));
67
72
  }
68
73
  configValueSerialized = JSON.stringify(configValueSerialized);
@@ -75,6 +75,9 @@ const configDefinitionsBuiltIn = {
75
75
  onBeforeRenderEnv: {
76
76
  env: { client: true },
77
77
  _computed: (configValueSources) => !isConfigSet(configValueSources, 'onBeforeRender') ? null : getConfigEnv(configValueSources, 'onBeforeRender')
78
+ },
79
+ hooksTimeout: {
80
+ env: { server: true, client: true }
78
81
  }
79
82
  };
80
83
  const configDefinitionsBuiltInGlobal = {
@@ -45,6 +45,18 @@ async function crawlPlusFiles(userRootDir, outDirAbsoluteFilesystem, isDev) {
45
45
  }
46
46
  // Same as fastGlob() but using `$ git ls-files`
47
47
  async function gitLsFiles(userRootDir, outDir) {
48
+ // Test if Git is installed
49
+ {
50
+ let stdout;
51
+ try {
52
+ const res = await execA('git --version', { cwd: userRootDir });
53
+ stdout = res.stdout;
54
+ }
55
+ catch {
56
+ return null;
57
+ }
58
+ assert(stdout.startsWith('git version '));
59
+ }
48
60
  const cmd = [
49
61
  'git ls-files',
50
62
  ...scriptFileExtensionList.map((ext) => `"**/+*.${ext}"`),
@@ -122,6 +122,7 @@ async function loadInterfaceFiles(userRootDir, outDirRoot, isDev, extensions) {
122
122
  interfaceFilesByLocationId[locationId].push(interfaceFile);
123
123
  }
124
124
  }));
125
+ assertAllConfigsAreKnown(interfaceFilesByLocationId);
125
126
  return interfaceFilesByLocationId;
126
127
  }
127
128
  function getConfigDefinition(configDefinitionsRelevant, configName, filePathToShowToUser) {
@@ -175,6 +176,18 @@ function getInterfaceFileFromConfigFile(configFile, isConfigExtend) {
175
176
  });
176
177
  return interfaceFile;
177
178
  }
179
+ /** Show error message upon unknown config */
180
+ function assertAllConfigsAreKnown(interfaceFilesByLocationId) {
181
+ Object.entries(interfaceFilesByLocationId).forEach(([locationId, interfaceFiles]) => {
182
+ const interfaceFilesRelevant = getInterfaceFilesRelevant(interfaceFilesByLocationId, locationId);
183
+ const configDefinitionsRelevant = getConfigDefinitions(interfaceFilesRelevant);
184
+ interfaceFiles.forEach((interfaceFile) => {
185
+ Object.keys(interfaceFile.configMap).forEach((configName) => {
186
+ assertConfigExists(configName, Object.keys(configDefinitionsRelevant), interfaceFile.filePath.filePathToShowToUser);
187
+ });
188
+ });
189
+ });
190
+ }
178
191
  async function loadVikeConfig_withErrorHandling(userRootDir, outDirRoot, isDev, extensions, tolerateInvalidConfig) {
179
192
  let hasError = false;
180
193
  let ret;
@@ -265,18 +278,23 @@ async function loadVikeConfig(userRootDir, outDirRoot, isDev, extensions) {
265
278
  };
266
279
  return pageConfig;
267
280
  }));
268
- // Show error message upon unknown config
269
- Object.entries(interfaceFilesByLocationId).forEach(([locationId, interfaceFiles]) => {
270
- const interfaceFilesRelevant = getInterfaceFilesRelevant(interfaceFilesByLocationId, locationId);
271
- const configDefinitionsRelevant = getConfigDefinitions(interfaceFilesRelevant);
272
- interfaceFiles.forEach((interfaceFile) => {
273
- Object.keys(interfaceFile.configMap).forEach((configName) => {
274
- assertConfigExists(configName, Object.keys(configDefinitionsRelevant), interfaceFile.filePath.filePathToShowToUser);
275
- });
276
- });
277
- });
281
+ assertPageConfigs(pageConfigs);
278
282
  return { pageConfigs, pageConfigGlobal, globalVikeConfig };
279
283
  }
284
+ function assertPageConfigs(pageConfigs) {
285
+ pageConfigs.forEach((pageConfig) => {
286
+ assertOnBeforeRenderEnv(pageConfig);
287
+ });
288
+ }
289
+ function assertOnBeforeRenderEnv(pageConfig) {
290
+ const onBeforeRenderConfig = pageConfig.configValueSources.onBeforeRender?.[0];
291
+ if (!onBeforeRenderConfig)
292
+ return;
293
+ const onBeforeRenderEnv = onBeforeRenderConfig.configEnv;
294
+ const isClientRouting = !!pageConfig.configValues.clientRouting?.value;
295
+ // When using Server Routing, loading a onBeforeRender() hook on the client-side hasn't any effect (the Server Routing's client runtime never calls it); it unnecessarily bloats client bundle sizes
296
+ assertUsage(!(onBeforeRenderEnv.client && !isClientRouting), `Page ${pageConfig.pageId} has an onBeforeRender() hook with env ${pc.cyan(JSON.stringify(onBeforeRenderEnv))} which doesn't make sense because the page is using Server Routing: onBeforeRender() can be run in the client only when using Client Routing.`);
297
+ }
280
298
  function interfacefileIsAlreaydLoaded(interfaceFile) {
281
299
  const configMapValues = Object.values(interfaceFile.configMap);
282
300
  const isAlreadyLoaded = configMapValues.some((conf) => 'configValue' in conf);
@@ -16,14 +16,14 @@ import { getConfigVike } from '../shared/getConfigVike.js';
16
16
  import { getPageFilesServerSide } from '../../shared/getPageFiles.js';
17
17
  import { getPageContextRequestUrl } from '../../shared/getPageContextRequestUrl.js';
18
18
  import { getUrlFromRouteString } from '../../shared/route/resolveRouteString.js';
19
- import { getConfigValue, getConfigValueFilePathToShowToUser, getHookFilePathToShowToUser } from '../../shared/page-configs/helpers.js';
19
+ import { getConfigValue, getConfigValueFilePathToShowToUser } from '../../shared/page-configs/helpers.js';
20
20
  import { loadConfigValues } from '../../shared/page-configs/loadConfigValues.js';
21
21
  import { isErrorPage } from '../../shared/error-page.js';
22
22
  import { addUrlComputedProps } from '../../shared/addUrlComputedProps.js';
23
23
  import { assertPathIsFilesystemAbsolute } from '../../utils/assertPathIsFilesystemAbsolute.js';
24
24
  import { isAbortError } from '../../shared/route/abort.js';
25
25
  import { loadPageFilesServerSide } from '../runtime/renderPage/loadPageFilesServerSide.js';
26
- import { assertHookFn } from '../../shared/hooks/getHook.js';
26
+ import { getHookFromPageConfig, getHookFromPageConfigGlobal, getHookTimeoutDefault } from '../../shared/hooks/getHook.js';
27
27
  import { noRouteMatch } from '../../shared/route/noRouteMatch.js';
28
28
  import { getVikeConfig } from '../plugin/plugins/importUserCode/v1-design/getVikeConfig.js';
29
29
  async function prerenderFromAPI(options = {}) {
@@ -157,18 +157,16 @@ async function callOnBeforePrerenderStartHooks(prerenderContext, renderContext,
157
157
  await Promise.all(renderContext.pageConfigs.map((pageConfig) => concurrencyLimit(async () => {
158
158
  const hookName = 'onBeforePrerenderStart';
159
159
  const pageConfigLoaded = await loadConfigValues(pageConfig, false);
160
- const configValue = getConfigValue(pageConfigLoaded, hookName);
161
- if (!configValue)
160
+ const hook = getHookFromPageConfig(pageConfigLoaded, hookName);
161
+ if (!hook)
162
162
  return;
163
- const hookFn = configValue.value;
164
- const hookFilePath = getHookFilePathToShowToUser(configValue);
165
- assert(hookFilePath);
166
- assertHookFn(hookFn, { hookName, hookFilePath });
163
+ const { hookFn, hookFilePath, hookTimeout } = hook;
167
164
  onBeforePrerenderStartHooks.push({
168
165
  hookFn,
169
166
  hookName: 'onBeforePrerenderStart',
170
167
  hookFilePath,
171
- pageId: pageConfig.pageId
168
+ pageId: pageConfig.pageId,
169
+ hookTimeout
172
170
  });
173
171
  })));
174
172
  // 0.4 design
@@ -192,14 +190,15 @@ async function callOnBeforePrerenderStartHooks(prerenderContext, renderContext,
192
190
  hookFn,
193
191
  hookName: 'prerender',
194
192
  hookFilePath,
195
- pageId: p.pageId
193
+ pageId: p.pageId,
194
+ hookTimeout: getHookTimeoutDefault('onBeforePrerenderStart')
196
195
  });
197
196
  })));
198
- await Promise.all(onBeforePrerenderStartHooks.map(({ hookFn, hookName, hookFilePath, pageId }) => concurrencyLimit(async () => {
197
+ await Promise.all(onBeforePrerenderStartHooks.map(({ hookFn, hookName, hookFilePath, pageId, hookTimeout }) => concurrencyLimit(async () => {
199
198
  if (doNotPrerenderList.find((p) => p.pageId === pageId)) {
200
199
  return;
201
200
  }
202
- const prerenderResult = await hookFn();
201
+ const prerenderResult = await executeHook(() => hookFn(), { hookName, hookFilePath, hookTimeout });
203
202
  const result = normalizeOnPrerenderHookResult(prerenderResult, hookFilePath, hookName);
204
203
  result.forEach(({ url, pageContext }) => {
205
204
  {
@@ -298,23 +297,21 @@ async function callOnPrerenderStartHook(prerenderContext, renderContext) {
298
297
  let onPrerenderStartHook;
299
298
  // V1 design
300
299
  if (renderContext.pageConfigs.length > 0) {
301
- const { pageConfigGlobal } = renderContext;
302
- const configValue = pageConfigGlobal.configValues.onPrerenderStart;
303
- if (configValue?.value) {
304
- const { value: hookFn } = configValue;
305
- // config.onPrerenderStart isn't a computed nor a cumulative config => definedAt should always be defined
306
- const hookFilePath = getHookFilePathToShowToUser(configValue);
307
- assert(hookFilePath);
300
+ const hookName = 'onPrerenderStart';
301
+ const hook = getHookFromPageConfigGlobal(renderContext.pageConfigGlobal, hookName);
302
+ if (hook) {
303
+ assert(hook.hookName === 'onPrerenderStart');
308
304
  onPrerenderStartHook = {
309
- hookFn,
310
- hookName: 'onPrerenderStart',
311
- hookFilePath
305
+ ...hook,
306
+ // Make TypeScript happy
307
+ hookName
312
308
  };
313
309
  }
314
310
  }
315
311
  // Old design
316
312
  // TODO/v1-release: remove
317
313
  if (renderContext.pageConfigs.length === 0) {
314
+ const hookTimeout = getHookTimeoutDefault('onBeforePrerender');
318
315
  const pageFilesWithOnBeforePrerenderHook = renderContext.pageFilesAll.filter((p) => {
319
316
  assertExportNames(p);
320
317
  if (!p.exportNames?.includes('onBeforePrerender'))
@@ -340,7 +337,8 @@ async function callOnPrerenderStartHook(prerenderContext, renderContext) {
340
337
  onPrerenderStartHook = {
341
338
  hookFn: hook.onBeforePrerender,
342
339
  hookFilePath: hook.hookFilePath,
343
- hookName: 'onBeforePrerender'
340
+ hookName: 'onBeforePrerender',
341
+ hookTimeout
344
342
  };
345
343
  }
346
344
  if (!onPrerenderStartHook) {
@@ -375,7 +373,7 @@ async function callOnPrerenderStartHook(prerenderContext, renderContext) {
375
373
  });
376
374
  return prerenderContext.pageContexts;
377
375
  }
378
- }), hookName, hookFilePath);
376
+ }), onPrerenderStartHook);
379
377
  if (result === null || result === undefined) {
380
378
  return;
381
379
  }
@@ -174,7 +174,7 @@ async function renderTemplate(templateContent, pageContext) {
174
174
  };
175
175
  assertUsage(!isPromise(templateVar), getErrMsg('a promise', `Did you forget to ${pc.cyan('await')} the promise?`));
176
176
  if (templateVar === undefined || templateVar === null) {
177
- assertWarning(false, getErrMsg(`${pc.cyan(String(templateVar))} which will be converted to an empty string`, `Pass an empty string instead of ${pc.cyan(String(templateVar))} to remove this warning.`), { onlyOnce: false });
177
+ assertWarning(false, getErrMsg(`${pc.cyan(String(templateVar))} which will be converted to an empty string`, `Pass the empty string ${pc.cyan("''")} instead of ${pc.cyan(String(templateVar))} to remove this warning.`), { onlyOnce: false });
178
178
  templateVar = '';
179
179
  }
180
180
  {
@@ -13,7 +13,7 @@ async function executeOnBeforeRenderHooks(pageContext) {
13
13
  }
14
14
  const onBeforeRender = hook.hookFn;
15
15
  preparePageContextForUserConsumptionServerSide(pageContext);
16
- const hookResult = await executeHook(() => onBeforeRender(pageContext), 'onBeforeRender', hook.hookFilePath);
16
+ const hookResult = await executeHook(() => onBeforeRender(pageContext), hook);
17
17
  assertOnBeforeRenderHookReturn(hookResult, hook.hookFilePath);
18
18
  const pageContextFromHook = hookResult?.pageContext;
19
19
  Object.assign(pageContext, pageContextFromHook);
@@ -1,13 +1,13 @@
1
1
  export { executeOnRenderHtmlHook };
2
2
  export type { RenderHook };
3
3
  import { type HtmlRender } from '../html/renderHtml.js';
4
+ import { type Hook } from '../../../shared/hooks/getHook.js';
4
5
  import type { PageAsset } from './getPageAssets.js';
5
6
  import { type PageContextForUserConsumptionServerSide } from './preparePageContextForUserConsumptionServerSide.js';
6
7
  import type { PageConfigRuntime } from '../../../shared/page-configs/PageConfig.js';
7
8
  import type { PageContextSerialization } from '../html/serializePageContextClientSide.js';
8
9
  type GetPageAssets = () => Promise<PageAsset[]>;
9
- type RenderHook = {
10
- hookFilePath: string;
10
+ type RenderHook = Hook & {
11
11
  hookName: HookName;
12
12
  };
13
13
  type HookName = 'onRenderHtml' | 'render';
@@ -12,7 +12,7 @@ async function executeOnRenderHtmlHook(pageContext) {
12
12
  const { renderHook, hookFn } = getRenderHook(pageContext);
13
13
  objectAssign(pageContext, { _renderHook: renderHook });
14
14
  preparePageContextForUserConsumptionServerSide(pageContext);
15
- const hookReturnValue = await executeHook(() => hookFn(pageContext), renderHook.hookName, renderHook.hookFilePath);
15
+ const hookReturnValue = await executeHook(() => hookFn(pageContext), renderHook);
16
16
  const { documentHtml, pageContextProvidedByRenderHook, pageContextPromise, injectFilter } = processHookReturnValue(hookReturnValue, renderHook);
17
17
  Object.assign(pageContext, pageContextProvidedByRenderHook);
18
18
  objectAssign(pageContext, { _pageContextPromise: pageContextPromise });
@@ -50,10 +50,10 @@ function getRenderHook(pageContext) {
50
50
  }
51
51
  if (hook) {
52
52
  assert(hookName);
53
- const { hookFilePath, hookFn } = hook;
53
+ const { hookFilePath, hookFn, hookTimeout } = hook;
54
54
  hookFound = {
55
55
  hookFn,
56
- renderHook: { hookFilePath, hookName }
56
+ renderHook: { hookFn, hookFilePath, hookName, hookTimeout }
57
57
  };
58
58
  }
59
59
  }
@@ -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
  }
@@ -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>;