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
@@ -53,22 +53,27 @@ function getConfigValueSerialized(value, configName, definedAt) {
53
53
  configValueSerialized = (0, stringify_1.stringify)(value, { valueName, forbidReactElements: true });
54
54
  }
55
55
  catch (err) {
56
- let serializationErrMsg = '';
57
- if ((0, stringify_1.isJsonSerializerError)(err)) {
58
- serializationErrMsg = err.messageCore;
59
- }
60
- else {
61
- // When a property getter throws an error
62
- console.error('Serialization error:');
63
- console.error(err);
64
- serializationErrMsg = 'see serialization error printed above';
56
+ /*
57
+ let serializationErrMsg = ''
58
+ if (isJsonSerializerError(err)) {
59
+ serializationErrMsg = err.messageCore
60
+ } else {
61
+ // When a property getter throws an error
62
+ console.error('Serialization error:')
63
+ console.error(err)
64
+ serializationErrMsg = 'see serialization error printed above'
65
65
  }
66
+ */
66
67
  const configValueFilePathToShowToUser = (0, helpers_js_1.getConfigValueFilePathToShowToUser)({ definedAt });
67
68
  (0, utils_js_1.assert)(configValueFilePathToShowToUser);
68
69
  (0, utils_js_1.assertUsage)(false, [
69
- `The value of the config ${picocolors_1.default.cyan(configName)} cannot be defined inside the file ${configValueFilePathToShowToUser}:`,
70
- `its value must be defined in an another file and then imported by ${configValueFilePathToShowToUser}. (Because its value isn't serializable: ${serializationErrMsg}.)`,
71
- `Only serializable config values can be defined inside +config.h.js files, see https://vike.dev/header-file.`
70
+ `The code of ${picocolors_1.default.cyan(configName)} cannot live inside ${configValueFilePathToShowToUser},`,
71
+ 'see https://vike.dev/header-file#runtime-code'
72
+ /* I guess showing this is more confusing than adding value.
73
+ `(technically speaking: the value of ${pc.cyan(
74
+ configName
75
+ )} isn't serializable (${serializationErrMsg}) and it's therefore runtime code that needs to be imported).`
76
+ //*/
72
77
  ].join(' '));
73
78
  }
74
79
  configValueSerialized = JSON.stringify(configValueSerialized);
@@ -76,6 +76,9 @@ const configDefinitionsBuiltIn = {
76
76
  onBeforeRenderEnv: {
77
77
  env: { client: true },
78
78
  _computed: (configValueSources) => !isConfigSet(configValueSources, 'onBeforeRender') ? null : getConfigEnv(configValueSources, 'onBeforeRender')
79
+ },
80
+ hooksTimeout: {
81
+ env: { server: true, client: true }
79
82
  }
80
83
  };
81
84
  exports.configDefinitionsBuiltIn = configDefinitionsBuiltIn;
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.crawlPlusFiles = void 0;
7
+ const utils_js_1 = require("../../../../utils.js");
8
+ const path_1 = __importDefault(require("path"));
9
+ const fast_glob_1 = __importDefault(require("fast-glob"));
10
+ const child_process_1 = require("child_process");
11
+ const util_1 = require("util");
12
+ const execA = (0, util_1.promisify)(child_process_1.exec);
13
+ async function crawlPlusFiles(userRootDir, outDirAbsoluteFilesystem, isDev) {
14
+ (0, utils_js_1.assertPosixPath)(userRootDir);
15
+ (0, utils_js_1.assertPosixPath)(outDirAbsoluteFilesystem);
16
+ (0, utils_js_1.assert)(outDirAbsoluteFilesystem.startsWith(userRootDir));
17
+ const outDir = path_1.default.posix.relative(userRootDir, outDirAbsoluteFilesystem);
18
+ (0, utils_js_1.assert)(!outDir.startsWith('.'));
19
+ const timeBase = new Date().getTime();
20
+ let files = [];
21
+ const res = await gitLsFiles(userRootDir, outDir);
22
+ if (res &&
23
+ // Fallback to fast-glob for users that dynamically generate plus files (we assume generetad plus files to be skipped because they are usually included in .gitignore)
24
+ res.length > 0) {
25
+ files = res;
26
+ }
27
+ else {
28
+ files = await fastGlob(userRootDir, outDir);
29
+ }
30
+ {
31
+ const time = new Date().getTime() - timeBase;
32
+ if (isDev) {
33
+ // We only warn in dev, because while building it's expected to take a long time as fast-glob is competing for resources with other tasks
34
+ (0, utils_js_1.assertWarning)(time < 2 * 1000, `Crawling your user files took an unexpected long time (${time}ms). Create a new issue on Vike's GitHub.`, {
35
+ onlyOnce: 'slow-page-files-search'
36
+ });
37
+ }
38
+ }
39
+ const plusFiles = files.map((p) => {
40
+ p = (0, utils_js_1.toPosixPath)(p);
41
+ (0, utils_js_1.assert)(!p.startsWith(userRootDir));
42
+ const filePathRelativeToUserRootDir = path_1.default.posix.join('/', p);
43
+ const filePathAbsoluteFilesystem = path_1.default.posix.join(userRootDir, p);
44
+ return {
45
+ filePathRelativeToUserRootDir,
46
+ filePathAbsoluteFilesystem
47
+ };
48
+ });
49
+ return plusFiles;
50
+ }
51
+ exports.crawlPlusFiles = crawlPlusFiles;
52
+ // Same as fastGlob() but using `$ git ls-files`
53
+ async function gitLsFiles(userRootDir, outDir) {
54
+ // Test if Git is installed
55
+ {
56
+ let stdout;
57
+ try {
58
+ const res = await execA('git --version', { cwd: userRootDir });
59
+ stdout = res.stdout;
60
+ }
61
+ catch {
62
+ return null;
63
+ }
64
+ (0, utils_js_1.assert)(stdout.startsWith('git version '));
65
+ }
66
+ const cmd = [
67
+ 'git ls-files',
68
+ ...utils_js_1.scriptFileExtensionList.map((ext) => `"**/+*.${ext}"`),
69
+ ...getIgnorePatterns(outDir).map((pattern) => `--exclude="${pattern}"`),
70
+ // --others lists untracked files only (but using .gitignore because --exclude-standard)
71
+ // --cached adds the tracked files to the output
72
+ '--others --cached --exclude-standard'
73
+ ].join(' ');
74
+ let stdout;
75
+ try {
76
+ const res = await execA(cmd, { cwd: userRootDir });
77
+ stdout = res.stdout;
78
+ }
79
+ catch (err) {
80
+ if (err.message.includes('not a git repository'))
81
+ return null;
82
+ throw err;
83
+ }
84
+ let files = stdout.split('\n').filter(Boolean);
85
+ (0, utils_js_1.assert)(!outDir.startsWith('/'));
86
+ files = files.filter(
87
+ // We have to repeat the same exclusion logic here because the `git ls-files` option --exclude only applies to untracked files. (We use --exclude only to speed up the command.)
88
+ (file) => getIgnoreFilter(file, outDir));
89
+ return files;
90
+ }
91
+ // Same as gitLsFiles() but using fast-glob
92
+ async function fastGlob(userRootDir, outDir) {
93
+ const files = await (0, fast_glob_1.default)(`**/+*.${utils_js_1.scriptFileExtensions}`, {
94
+ ignore: getIgnorePatterns(outDir),
95
+ cwd: userRootDir,
96
+ dot: false
97
+ });
98
+ return files;
99
+ }
100
+ // Same as getIgnoreFilter() but as glob pattern
101
+ function getIgnorePatterns(outDir) {
102
+ return [
103
+ '**/node_modules/**',
104
+ `${outDir}/**`,
105
+ // Allow:
106
+ // ```
107
+ // +Page.js
108
+ // +Page.telefunc.js
109
+ // ```
110
+ '**/*.telefunc.*'
111
+ ];
112
+ }
113
+ // Same as getIgnorePatterns() but for Array.filter()
114
+ function getIgnoreFilter(file, outDir) {
115
+ return !file.includes('node_modules/') && !file.includes('.telefunc.') && !file.startsWith(`${outDir}/`);
116
+ }
@@ -7,7 +7,6 @@ exports.isVikeConfigFile = exports.vikeConfigDependencies = exports.reloadVikeCo
7
7
  const utils_js_1 = require("../../../utils.js");
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const configDefinitionsBuiltIn_js_1 = require("./getVikeConfig/configDefinitionsBuiltIn.js");
10
- const fast_glob_1 = __importDefault(require("fast-glob"));
11
10
  const filesystemRouting_js_1 = require("./getVikeConfig/filesystemRouting.js");
12
11
  const transpileAndExecuteFile_js_1 = require("./transpileAndExecuteFile.js");
13
12
  const replaceImportStatements_js_1 = require("./replaceImportStatements.js");
@@ -20,6 +19,7 @@ const helpers_js_1 = require("../../../../../shared/page-configs/helpers.js");
20
19
  const assertExports_js_1 = require("../../../../../shared/page-configs/assertExports.js");
21
20
  const getConfigVike_js_1 = require("../../../../shared/getConfigVike.js");
22
21
  const getConfigValuesSerialized_js_1 = require("./getConfigValuesSerialized.js");
22
+ const crawlPlusFiles_js_1 = require("./getVikeConfig/crawlPlusFiles.js");
23
23
  (0, utils_js_1.assertIsNotProductionRuntime)();
24
24
  let devServerIsCorrupt = false;
25
25
  let wasConfigInvalid = null;
@@ -75,7 +75,7 @@ async function getVikeConfig(config, isDev, tolerateInvalidConfig = false, exten
75
75
  }
76
76
  exports.getVikeConfig = getVikeConfig;
77
77
  async function loadInterfaceFiles(userRootDir, outDirRoot, isDev, extensions) {
78
- const plusFiles = await findPlusFiles(userRootDir, [outDirRoot], isDev, extensions);
78
+ const plusFiles = await findPlusFiles(userRootDir, outDirRoot, isDev, extensions);
79
79
  const configFiles = [];
80
80
  const valueFiles = [];
81
81
  plusFiles.forEach((f) => {
@@ -127,6 +127,7 @@ async function loadInterfaceFiles(userRootDir, outDirRoot, isDev, extensions) {
127
127
  interfaceFilesByLocationId[locationId].push(interfaceFile);
128
128
  }
129
129
  }));
130
+ assertAllConfigsAreKnown(interfaceFilesByLocationId);
130
131
  return interfaceFilesByLocationId;
131
132
  }
132
133
  function getConfigDefinition(configDefinitionsRelevant, configName, filePathToShowToUser) {
@@ -180,6 +181,18 @@ function getInterfaceFileFromConfigFile(configFile, isConfigExtend) {
180
181
  });
181
182
  return interfaceFile;
182
183
  }
184
+ /** Show error message upon unknown config */
185
+ function assertAllConfigsAreKnown(interfaceFilesByLocationId) {
186
+ Object.entries(interfaceFilesByLocationId).forEach(([locationId, interfaceFiles]) => {
187
+ const interfaceFilesRelevant = getInterfaceFilesRelevant(interfaceFilesByLocationId, locationId);
188
+ const configDefinitionsRelevant = getConfigDefinitions(interfaceFilesRelevant);
189
+ interfaceFiles.forEach((interfaceFile) => {
190
+ Object.keys(interfaceFile.configMap).forEach((configName) => {
191
+ assertConfigExists(configName, Object.keys(configDefinitionsRelevant), interfaceFile.filePath.filePathToShowToUser);
192
+ });
193
+ });
194
+ });
195
+ }
183
196
  async function loadVikeConfig_withErrorHandling(userRootDir, outDirRoot, isDev, extensions, tolerateInvalidConfig) {
184
197
  let hasError = false;
185
198
  let ret;
@@ -270,18 +283,23 @@ async function loadVikeConfig(userRootDir, outDirRoot, isDev, extensions) {
270
283
  };
271
284
  return pageConfig;
272
285
  }));
273
- // Show error message upon unknown config
274
- Object.entries(interfaceFilesByLocationId).forEach(([locationId, interfaceFiles]) => {
275
- const interfaceFilesRelevant = getInterfaceFilesRelevant(interfaceFilesByLocationId, locationId);
276
- const configDefinitionsRelevant = getConfigDefinitions(interfaceFilesRelevant);
277
- interfaceFiles.forEach((interfaceFile) => {
278
- Object.keys(interfaceFile.configMap).forEach((configName) => {
279
- assertConfigExists(configName, Object.keys(configDefinitionsRelevant), interfaceFile.filePath.filePathToShowToUser);
280
- });
281
- });
282
- });
286
+ assertPageConfigs(pageConfigs);
283
287
  return { pageConfigs, pageConfigGlobal, globalVikeConfig };
284
288
  }
289
+ function assertPageConfigs(pageConfigs) {
290
+ pageConfigs.forEach((pageConfig) => {
291
+ assertOnBeforeRenderEnv(pageConfig);
292
+ });
293
+ }
294
+ function assertOnBeforeRenderEnv(pageConfig) {
295
+ const onBeforeRenderConfig = pageConfig.configValueSources.onBeforeRender?.[0];
296
+ if (!onBeforeRenderConfig)
297
+ return;
298
+ const onBeforeRenderEnv = onBeforeRenderConfig.configEnv;
299
+ const isClientRouting = !!pageConfig.configValues.clientRouting?.value;
300
+ // 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
301
+ (0, utils_js_1.assertUsage)(!(onBeforeRenderEnv.client && !isClientRouting), `Page ${pageConfig.pageId} has an onBeforeRender() hook with env ${picocolors_1.default.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.`);
302
+ }
285
303
  function interfacefileIsAlreaydLoaded(interfaceFile) {
286
304
  const configMapValues = Object.values(interfaceFile.configMap);
287
305
  const isAlreadyLoaded = configMapValues.some((conf) => 'configValue' in conf);
@@ -781,39 +799,9 @@ function getComputed(configValueSources, configDefinitionsRelevant) {
781
799
  });
782
800
  return configValuesComputed;
783
801
  }
784
- async function findPlusFiles(userRootDir, ignoreDirs, isDev, extensions) {
785
- const timeBase = new Date().getTime();
786
- (0, utils_js_1.assertPosixPath)(userRootDir);
787
- const ignorePatterns = [];
788
- for (const dir of ignoreDirs) {
789
- (0, utils_js_1.assertPosixPath)(dir);
790
- ignorePatterns.push(`${path_1.default.posix.relative(userRootDir, dir)}/**`);
791
- }
792
- const result = await (0, fast_glob_1.default)(`**/+*.${utils_js_1.scriptFileExtensions}`, {
793
- ignore: [
794
- '**/node_modules/**',
795
- // Allow:
796
- // ```
797
- // +Page.js
798
- // +Page.telefunc.js
799
- // ```
800
- '**/*.telefunc.*',
801
- ...ignorePatterns
802
- ],
803
- cwd: userRootDir,
804
- dot: false
805
- });
806
- const time = new Date().getTime() - timeBase;
807
- if (isDev) {
808
- // We only warn in dev, because while building it's expected to take a long time as fast-glob is competing for resources with other tasks
809
- (0, utils_js_1.assertWarning)(time < 2 * 1000, `Crawling your user files took an unexpected long time (${time}ms). Create a new issue on Vike's GitHub.`, {
810
- onlyOnce: 'slow-page-files-search'
811
- });
812
- }
813
- const plusFiles = result.map((p) => {
814
- p = (0, utils_js_1.toPosixPath)(p);
815
- const filePathRelativeToUserRootDir = path_1.default.posix.join('/', p);
816
- const filePathAbsoluteFilesystem = path_1.default.posix.join(userRootDir, p);
802
+ async function findPlusFiles(userRootDir, outDirRoot, isDev, extensions) {
803
+ const files = await (0, crawlPlusFiles_js_1.crawlPlusFiles)(userRootDir, outDirRoot, isDev);
804
+ const plusFiles = files.map(({ filePathRelativeToUserRootDir, filePathAbsoluteFilesystem }) => {
817
805
  return {
818
806
  filePathRelativeToUserRootDir,
819
807
  filePathAbsoluteVite: filePathRelativeToUserRootDir,
@@ -102,16 +102,22 @@ async function runPrerender(options, manuallyTriggered) {
102
102
  await callOnBeforePrerenderStartHooks(prerenderContext, renderContext, concurrencyLimit, doNotPrerenderList);
103
103
  await handlePagesWithStaticRoutes(prerenderContext, renderContext, doNotPrerenderList, concurrencyLimit);
104
104
  await callOnPrerenderStartHook(prerenderContext, renderContext);
105
- const prerenderedPages = {};
106
- const htmlFiles = [];
107
- await routeAndPrerender(prerenderContext, htmlFiles, prerenderedPages, concurrencyLimit);
108
- warnContradictoryNoPrerenderList(prerenderedPages, doNotPrerenderList);
109
- await prerender404(htmlFiles, renderContext, prerenderContext);
105
+ const prerenderedPageContexts = {};
106
+ let prerenderedCount = 0;
107
+ const onComplete = async (htmlFile) => {
108
+ prerenderedCount++;
109
+ if (htmlFile.pageId) {
110
+ prerenderedPageContexts[htmlFile.pageId] = htmlFile.pageContext;
111
+ }
112
+ await writeFiles(htmlFile, root, outDirClient, options.onPagePrerender, logLevel);
113
+ };
114
+ await routeAndPrerender(prerenderContext, concurrencyLimit, onComplete);
115
+ warnContradictoryNoPrerenderList(prerenderedPageContexts, doNotPrerenderList);
116
+ await prerender404(prerenderedPageContexts, renderContext, prerenderContext, onComplete);
110
117
  if (logLevel === 'info') {
111
- console.log(`${picocolors_1.default.green(`✓`)} ${htmlFiles.length} HTML documents pre-rendered.`);
118
+ console.log(`${picocolors_1.default.green(`✓`)} ${prerenderedCount} HTML documents pre-rendered.`);
112
119
  }
113
- await Promise.all(htmlFiles.map((htmlFile) => writeHtmlFile(htmlFile, root, outDirClient, concurrencyLimit, options.onPagePrerender, logLevel)));
114
- warnMissingPages(prerenderedPages, doNotPrerenderList, renderContext, partial);
120
+ warnMissingPages(prerenderedPageContexts, doNotPrerenderList, renderContext, partial);
115
121
  }
116
122
  async function collectDoNoPrerenderList(renderContext, pageConfigs, doNotPrerenderList, concurrencyLimit) {
117
123
  // V1 design
@@ -179,18 +185,16 @@ async function callOnBeforePrerenderStartHooks(prerenderContext, renderContext,
179
185
  await Promise.all(renderContext.pageConfigs.map((pageConfig) => concurrencyLimit(async () => {
180
186
  const hookName = 'onBeforePrerenderStart';
181
187
  const pageConfigLoaded = await (0, loadConfigValues_js_1.loadConfigValues)(pageConfig, false);
182
- const configValue = (0, helpers_js_1.getConfigValue)(pageConfigLoaded, hookName);
183
- if (!configValue)
188
+ const hook = (0, getHook_js_1.getHookFromPageConfig)(pageConfigLoaded, hookName);
189
+ if (!hook)
184
190
  return;
185
- const hookFn = configValue.value;
186
- const hookFilePath = (0, helpers_js_1.getHookFilePathToShowToUser)(configValue);
187
- (0, utils_js_1.assert)(hookFilePath);
188
- (0, getHook_js_1.assertHookFn)(hookFn, { hookName, hookFilePath });
191
+ const { hookFn, hookFilePath, hookTimeout } = hook;
189
192
  onBeforePrerenderStartHooks.push({
190
193
  hookFn,
191
194
  hookName: 'onBeforePrerenderStart',
192
195
  hookFilePath,
193
- pageId: pageConfig.pageId
196
+ pageId: pageConfig.pageId,
197
+ hookTimeout
194
198
  });
195
199
  })));
196
200
  // 0.4 design
@@ -214,14 +218,15 @@ async function callOnBeforePrerenderStartHooks(prerenderContext, renderContext,
214
218
  hookFn,
215
219
  hookName: 'prerender',
216
220
  hookFilePath,
217
- pageId: p.pageId
221
+ pageId: p.pageId,
222
+ hookTimeout: (0, getHook_js_1.getHookTimeoutDefault)('onBeforePrerenderStart')
218
223
  });
219
224
  })));
220
- await Promise.all(onBeforePrerenderStartHooks.map(({ hookFn, hookName, hookFilePath, pageId }) => concurrencyLimit(async () => {
225
+ await Promise.all(onBeforePrerenderStartHooks.map(({ hookFn, hookName, hookFilePath, pageId, hookTimeout }) => concurrencyLimit(async () => {
221
226
  if (doNotPrerenderList.find((p) => p.pageId === pageId)) {
222
227
  return;
223
228
  }
224
- const prerenderResult = await hookFn();
229
+ const prerenderResult = await (0, utils_js_1.executeHook)(() => hookFn(), { hookName, hookFilePath, hookTimeout });
225
230
  const result = normalizeOnPrerenderHookResult(prerenderResult, hookFilePath, hookName);
226
231
  result.forEach(({ url, pageContext }) => {
227
232
  {
@@ -320,23 +325,21 @@ async function callOnPrerenderStartHook(prerenderContext, renderContext) {
320
325
  let onPrerenderStartHook;
321
326
  // V1 design
322
327
  if (renderContext.pageConfigs.length > 0) {
323
- const { pageConfigGlobal } = renderContext;
324
- const configValue = pageConfigGlobal.configValues.onPrerenderStart;
325
- if (configValue?.value) {
326
- const { value: hookFn } = configValue;
327
- // config.onPrerenderStart isn't a computed nor a cumulative config => definedAt should always be defined
328
- const hookFilePath = (0, helpers_js_1.getHookFilePathToShowToUser)(configValue);
329
- (0, utils_js_1.assert)(hookFilePath);
328
+ const hookName = 'onPrerenderStart';
329
+ const hook = (0, getHook_js_1.getHookFromPageConfigGlobal)(renderContext.pageConfigGlobal, hookName);
330
+ if (hook) {
331
+ (0, utils_js_1.assert)(hook.hookName === 'onPrerenderStart');
330
332
  onPrerenderStartHook = {
331
- hookFn,
332
- hookName: 'onPrerenderStart',
333
- hookFilePath
333
+ ...hook,
334
+ // Make TypeScript happy
335
+ hookName
334
336
  };
335
337
  }
336
338
  }
337
339
  // Old design
338
340
  // TODO/v1-release: remove
339
341
  if (renderContext.pageConfigs.length === 0) {
342
+ const hookTimeout = (0, getHook_js_1.getHookTimeoutDefault)('onBeforePrerender');
340
343
  const pageFilesWithOnBeforePrerenderHook = renderContext.pageFilesAll.filter((p) => {
341
344
  assertExportNames(p);
342
345
  if (!p.exportNames?.includes('onBeforePrerender'))
@@ -362,7 +365,8 @@ async function callOnPrerenderStartHook(prerenderContext, renderContext) {
362
365
  onPrerenderStartHook = {
363
366
  hookFn: hook.onBeforePrerender,
364
367
  hookFilePath: hook.hookFilePath,
365
- hookName: 'onBeforePrerender'
368
+ hookName: 'onBeforePrerender',
369
+ hookTimeout
366
370
  };
367
371
  }
368
372
  if (!onPrerenderStartHook) {
@@ -397,7 +401,7 @@ async function callOnPrerenderStartHook(prerenderContext, renderContext) {
397
401
  });
398
402
  return prerenderContext.pageContexts;
399
403
  }
400
- }), hookName, hookFilePath);
404
+ }), onPrerenderStartHook);
401
405
  if (result === null || result === undefined) {
402
406
  return;
403
407
  }
@@ -439,7 +443,7 @@ async function callOnPrerenderStartHook(prerenderContext, renderContext) {
439
443
  (0, addUrlComputedProps_js_1.addUrlComputedProps)(pageContext);
440
444
  });
441
445
  }
442
- async function routeAndPrerender(prerenderContext, htmlFiles, prerenderedPages, concurrencyLimit) {
446
+ async function routeAndPrerender(prerenderContext, concurrencyLimit, onComplete) {
443
447
  const globalContext = (0, globalContext_js_1.getGlobalContext)();
444
448
  (0, utils_js_1.assert)(globalContext.isPrerendering);
445
449
  // Route all URLs
@@ -499,7 +503,7 @@ async function routeAndPrerender(prerenderContext, htmlFiles, prerenderedPages,
499
503
  throw err;
500
504
  }
501
505
  const { documentHtml, pageContextSerialized } = res;
502
- htmlFiles.push({
506
+ await onComplete({
503
507
  urlOriginal,
504
508
  pageContext,
505
509
  htmlString: documentHtml,
@@ -507,11 +511,10 @@ async function routeAndPrerender(prerenderContext, htmlFiles, prerenderedPages,
507
511
  doNotCreateExtraDirectory: prerenderContext._noExtraDir,
508
512
  pageId
509
513
  });
510
- prerenderedPages[pageId] = pageContext;
511
514
  })));
512
515
  }
513
- function warnContradictoryNoPrerenderList(prerenderedPages, doNotPrerenderList) {
514
- Object.entries(prerenderedPages).forEach(([pageId, pageContext]) => {
516
+ function warnContradictoryNoPrerenderList(prerenderedPageContexts, doNotPrerenderList) {
517
+ Object.entries(prerenderedPageContexts).forEach(([pageId, pageContext]) => {
515
518
  const doNotPrerenderListEntry = doNotPrerenderList.find((p) => p.pageId === pageId);
516
519
  const { urlOriginal, _providedByHook: providedByHook } = pageContext;
517
520
  {
@@ -523,7 +526,7 @@ function warnContradictoryNoPrerenderList(prerenderedPages, doNotPrerenderList)
523
526
  (0, utils_js_1.assertWarning)(false, `The ${providedByHook.hookName}() hook defined by ${providedByHook.hookFilePath} returns the URL ${picocolors_1.default.cyan(urlOriginal)}, while ${setByConfigFile} sets the config ${picocolors_1.default.cyan(setByConfigName)} to ${picocolors_1.default.cyan(String(setByConfigValue))}. This is contradictory: either don't set the config ${picocolors_1.default.cyan(setByConfigName)} to ${picocolors_1.default.cyan(String(setByConfigValue))} or remove the URL ${picocolors_1.default.cyan(urlOriginal)} from the list of URLs to be pre-rendered.`, { onlyOnce: true });
524
527
  });
525
528
  }
526
- function warnMissingPages(prerenderedPages, doNotPrerenderList, renderContext, partial) {
529
+ function warnMissingPages(prerenderedPageContexts, doNotPrerenderList, renderContext, partial) {
527
530
  const isV1 = renderContext.pageConfigs.length > 0;
528
531
  const hookName = isV1 ? 'onBeforePrerenderStart' : 'prerender';
529
532
  /* TODO/after-v1-design-release: document setting `prerender: false` as an alternative to using prerender.partial (both in the warnings and the docs)
@@ -531,7 +534,7 @@ function warnMissingPages(prerenderedPages, doNotPrerenderList, renderContext, p
531
534
  const msgAddendum = `Explicitly opt-out by setting the config ${optOutName} to ${isV1 ? 'false' : 'true'} or use the option prerender.partial`
532
535
  */
533
536
  renderContext.allPageIds
534
- .filter((pageId) => !prerenderedPages[pageId])
537
+ .filter((pageId) => !prerenderedPageContexts[pageId])
535
538
  .filter((pageId) => !doNotPrerenderList.find((p) => p.pageId === pageId))
536
539
  .filter((pageId) => !(0, error_page_js_1.isErrorPage)(pageId, renderContext.pageConfigs))
537
540
  .forEach((pageId) => {
@@ -539,8 +542,8 @@ function warnMissingPages(prerenderedPages, doNotPrerenderList, renderContext, p
539
542
  (0, utils_js_1.assertWarning)(partial, `Cannot pre-render page ${pageAt} because it has a non-static route, while no ${hookName}() hook returned any URL matching the page's route. You need to use a ${hookName}() hook (https://vike.dev/${hookName}) providing a list of URLs for ${pageAt} that should be pre-rendered. If you don't want to pre-render ${pageAt} then use the option prerender.partial (https://vike.dev/prerender-config#partial) to suppress this warning.`, { onlyOnce: true });
540
543
  });
541
544
  }
542
- async function prerender404(htmlFiles, renderContext, prerenderContext) {
543
- if (!htmlFiles.find(({ urlOriginal }) => urlOriginal === '/404')) {
545
+ async function prerender404(prerenderedPageContexts, renderContext, prerenderContext, onComplete) {
546
+ if (!Object.values(prerenderedPageContexts).find(({ urlOriginal }) => urlOriginal === '/404')) {
544
547
  let result;
545
548
  try {
546
549
  result = await (0, renderPageAlreadyRouted_js_1.prerender404Page)(renderContext, prerenderContext.pageContextInit);
@@ -552,7 +555,7 @@ async function prerender404(htmlFiles, renderContext, prerenderContext) {
552
555
  if (result) {
553
556
  const urlOriginal = '/404';
554
557
  const { documentHtml, pageContext } = result;
555
- htmlFiles.push({
558
+ await onComplete({
556
559
  urlOriginal,
557
560
  pageContext,
558
561
  htmlString: documentHtml,
@@ -563,59 +566,57 @@ async function prerender404(htmlFiles, renderContext, prerenderContext) {
563
566
  }
564
567
  }
565
568
  }
566
- async function writeHtmlFile({ urlOriginal, pageContext, htmlString, pageContextSerialized, doNotCreateExtraDirectory }, root, outDirClient, concurrencyLimit, onPagePrerender, logLevel) {
569
+ async function writeFiles({ urlOriginal, pageContext, htmlString, pageContextSerialized, doNotCreateExtraDirectory }, root, outDirClient, onPagePrerender, logLevel) {
567
570
  (0, utils_js_1.assert)(urlOriginal.startsWith('/'));
568
571
  const writeJobs = [
569
- write(urlOriginal, pageContext, '.html', htmlString, root, outDirClient, doNotCreateExtraDirectory, concurrencyLimit, onPagePrerender, logLevel)
572
+ write(urlOriginal, pageContext, '.html', htmlString, root, outDirClient, doNotCreateExtraDirectory, onPagePrerender, logLevel)
570
573
  ];
571
574
  if (pageContextSerialized !== null) {
572
- writeJobs.push(write(urlOriginal, pageContext, '.pageContext.json', pageContextSerialized, root, outDirClient, doNotCreateExtraDirectory, concurrencyLimit, onPagePrerender, logLevel));
575
+ writeJobs.push(write(urlOriginal, pageContext, '.pageContext.json', pageContextSerialized, root, outDirClient, doNotCreateExtraDirectory, onPagePrerender, logLevel));
573
576
  }
574
577
  await Promise.all(writeJobs);
575
578
  }
576
- function write(urlOriginal, pageContext, fileExtension, fileContent, root, outDirClient, doNotCreateExtraDirectory, concurrencyLimit, onPagePrerender, logLevel) {
577
- return concurrencyLimit(async () => {
578
- let fileUrl;
579
- if (fileExtension === '.html') {
580
- fileUrl = (0, utils_js_1.urlToFile)(urlOriginal, '.html', doNotCreateExtraDirectory);
581
- }
582
- else {
583
- fileUrl = (0, getPageContextRequestUrl_js_1.getPageContextRequestUrl)(urlOriginal);
584
- }
585
- (0, utils_js_1.assertPosixPath)(fileUrl);
586
- (0, utils_js_1.assert)(fileUrl.startsWith('/'));
587
- const filePathRelative = fileUrl.slice(1);
588
- (0, utils_js_1.assert)(!filePathRelative.startsWith('/'));
589
- (0, utils_js_1.assertPosixPath)(outDirClient);
590
- (0, utils_js_1.assertPosixPath)(filePathRelative);
591
- const filePath = path_1.default.posix.join(outDirClient, filePathRelative);
592
- if (onPagePrerender) {
593
- const prerenderPageContext = {};
594
- (0, utils_js_1.objectAssign)(prerenderPageContext, pageContext);
595
- (0, utils_js_1.objectAssign)(prerenderPageContext, {
596
- _prerenderResult: {
597
- filePath,
598
- fileContent
599
- }
600
- });
601
- await onPagePrerender(prerenderPageContext);
602
- }
603
- else {
604
- const { promises } = await Promise.resolve().then(() => __importStar(require('fs')));
605
- const { writeFile, mkdir } = promises;
606
- await mkdir(path_1.default.posix.dirname(filePath), { recursive: true });
607
- await writeFile(filePath, fileContent);
608
- if (logLevel === 'info') {
609
- (0, utils_js_1.assertPosixPath)(root);
610
- (0, utils_js_1.assertPosixPath)(outDirClient);
611
- let outDirClientRelative = path_1.default.posix.relative(root, outDirClient);
612
- if (!outDirClientRelative.endsWith('/')) {
613
- outDirClientRelative = outDirClientRelative + '/';
614
- }
615
- console.log(`${picocolors_1.default.dim(outDirClientRelative)}${picocolors_1.default.blue(filePathRelative)}`);
579
+ async function write(urlOriginal, pageContext, fileExtension, fileContent, root, outDirClient, doNotCreateExtraDirectory, onPagePrerender, logLevel) {
580
+ let fileUrl;
581
+ if (fileExtension === '.html') {
582
+ fileUrl = (0, utils_js_1.urlToFile)(urlOriginal, '.html', doNotCreateExtraDirectory);
583
+ }
584
+ else {
585
+ fileUrl = (0, getPageContextRequestUrl_js_1.getPageContextRequestUrl)(urlOriginal);
586
+ }
587
+ (0, utils_js_1.assertPosixPath)(fileUrl);
588
+ (0, utils_js_1.assert)(fileUrl.startsWith('/'));
589
+ const filePathRelative = fileUrl.slice(1);
590
+ (0, utils_js_1.assert)(!filePathRelative.startsWith('/'));
591
+ (0, utils_js_1.assertPosixPath)(outDirClient);
592
+ (0, utils_js_1.assertPosixPath)(filePathRelative);
593
+ const filePath = path_1.default.posix.join(outDirClient, filePathRelative);
594
+ if (onPagePrerender) {
595
+ const prerenderPageContext = {};
596
+ (0, utils_js_1.objectAssign)(prerenderPageContext, pageContext);
597
+ (0, utils_js_1.objectAssign)(prerenderPageContext, {
598
+ _prerenderResult: {
599
+ filePath,
600
+ fileContent
601
+ }
602
+ });
603
+ await onPagePrerender(prerenderPageContext);
604
+ }
605
+ else {
606
+ const { promises } = await Promise.resolve().then(() => __importStar(require('fs')));
607
+ const { writeFile, mkdir } = promises;
608
+ await mkdir(path_1.default.posix.dirname(filePath), { recursive: true });
609
+ await writeFile(filePath, fileContent);
610
+ if (logLevel === 'info') {
611
+ (0, utils_js_1.assertPosixPath)(root);
612
+ (0, utils_js_1.assertPosixPath)(outDirClient);
613
+ let outDirClientRelative = path_1.default.posix.relative(root, outDirClient);
614
+ if (!outDirClientRelative.endsWith('/')) {
615
+ outDirClientRelative = outDirClientRelative + '/';
616
616
  }
617
+ console.log(`${picocolors_1.default.dim(outDirClientRelative)}${picocolors_1.default.blue(filePathRelative)}`);
617
618
  }
618
- });
619
+ }
619
620
  }
620
621
  function normalizeOnPrerenderHookResult(prerenderResult, prerenderHookFile, hookName) {
621
622
  if (Array.isArray(prerenderResult)) {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.injectAssets__public = void 0;
4
4
  const utils_js_1 = require("../../utils.js");
5
5
  const injectAssets_js_1 = require("../injectAssets.js");
6
- // TODO: remove this on next semver major
6
+ // TODO/v1-release: remove
7
7
  async function injectAssets__public(htmlString, pageContext) {
8
8
  (0, utils_js_1.assertWarning)(false, '`_injectAssets()` is deprecated and will be removed.', { onlyOnce: true, showStackTrace: true });
9
9
  (0, utils_js_1.assertUsage)(typeof htmlString === 'string', '[injectAssets(htmlString, pageContext)]: Argument `htmlString` should be a string.', { showStackTrace: true });
@@ -179,7 +179,7 @@ async function renderTemplate(templateContent, pageContext) {
179
179
  };
180
180
  (0, utils_js_1.assertUsage)(!(0, utils_js_1.isPromise)(templateVar), getErrMsg('a promise', `Did you forget to ${picocolors_1.default.cyan('await')} the promise?`));
181
181
  if (templateVar === undefined || templateVar === null) {
182
- (0, utils_js_1.assertWarning)(false, getErrMsg(`${picocolors_1.default.cyan(String(templateVar))} which will be converted to an empty string`, `Pass an empty string instead of ${picocolors_1.default.cyan(String(templateVar))} to remove this warning.`), { onlyOnce: false });
182
+ (0, utils_js_1.assertWarning)(false, getErrMsg(`${picocolors_1.default.cyan(String(templateVar))} which will be converted to an empty string`, `Pass the empty string ${picocolors_1.default.cyan("''")} instead of ${picocolors_1.default.cyan(String(templateVar))} to remove this warning.`), { onlyOnce: false });
183
183
  templateVar = '';
184
184
  }
185
185
  {