vike 0.4.146-commit-701e2e5 → 0.4.147-commit-2fa53b2

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 (80) hide show
  1. package/dist/cjs/node/plugin/index.js +6 -4
  2. package/dist/cjs/node/plugin/plugins/devConfig/determineOptimizeDeps.js +3 -4
  3. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getConfigValuesSerialized.js +76 -0
  4. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/configDefinitionsBuiltIn.js +61 -40
  5. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.js +104 -0
  6. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +62 -75
  7. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigValuesAll.js +43 -17
  8. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigs.js +12 -70
  9. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/isRuntimeEnvMatch.js +11 -8
  10. package/dist/cjs/node/plugin/shared/{getConfigValueSourcesRelevant.js → getConfigValueSourcesNotOverriden.js} +3 -3
  11. package/dist/cjs/node/plugin/utils.js +2 -0
  12. package/dist/cjs/node/prerender/runPrerender.js +75 -67
  13. package/dist/cjs/node/runtime/html/injectAssets/injectAssets__public.js +1 -1
  14. package/dist/cjs/node/runtime/index-common.js +3 -1
  15. package/dist/cjs/node/runtime/renderPage/analyzePage.js +2 -2
  16. package/dist/cjs/node/runtime/renderPage/createHttpResponseObject/assertNoInfiniteHttpRedirect.js +12 -12
  17. package/dist/cjs/node/runtime/renderPage/createHttpResponseObject.js +3 -3
  18. package/dist/cjs/node/runtime/renderPage/executeOnRenderHtmlHook.js +1 -2
  19. package/dist/cjs/node/runtime/renderPage/getHttpResponseBody.js +1 -1
  20. package/dist/cjs/node/runtime/renderPage.js +8 -5
  21. package/dist/cjs/shared/getPageFiles/analyzePageClientSide/determineClientEntry.js +1 -0
  22. package/dist/cjs/shared/page-configs/loadConfigValues.js +12 -3
  23. package/dist/cjs/shared/page-configs/serialize/parseConfigValuesSerialized.js +19 -0
  24. package/dist/cjs/shared/page-configs/serialize/parsePageConfigs.js +3 -12
  25. package/dist/cjs/utils/assertKeys.js +28 -0
  26. package/dist/cjs/utils/joinEnglish.js +3 -3
  27. package/dist/cjs/utils/parseUrl.js +24 -16
  28. package/dist/cjs/utils/projectInfo.js +3 -2
  29. package/dist/esm/client/client-routing-runtime/getPageContextFromHooks.js +25 -11
  30. package/dist/esm/client/client-routing-runtime/index.d.ts +1 -0
  31. package/dist/esm/client/client-routing-runtime/index.js +1 -0
  32. package/dist/esm/client/client-routing-runtime/onBrowserHistoryNavigation.js +2 -2
  33. package/dist/esm/client/shared/getPageContextSerializedInHtml.js +1 -1
  34. package/dist/esm/node/plugin/index.d.ts +1 -0
  35. package/dist/esm/node/plugin/index.js +1 -0
  36. package/dist/esm/node/plugin/plugins/devConfig/determineOptimizeDeps.js +3 -4
  37. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getConfigValuesSerialized.d.ts +5 -0
  38. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getConfigValuesSerialized.js +70 -0
  39. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/configDefinitionsBuiltIn.js +58 -37
  40. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.d.ts +5 -0
  41. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.js +98 -0
  42. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +63 -76
  43. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigValuesAll.js +43 -17
  44. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigs.d.ts +0 -3
  45. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigs.js +13 -68
  46. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/isRuntimeEnvMatch.js +11 -8
  47. package/dist/esm/node/plugin/shared/getConfigValueSourcesNotOverriden.d.ts +5 -0
  48. package/dist/esm/node/plugin/shared/{getConfigValueSourcesRelevant.js → getConfigValueSourcesNotOverriden.js} +2 -2
  49. package/dist/esm/node/plugin/utils.d.ts +2 -0
  50. package/dist/esm/node/plugin/utils.js +2 -0
  51. package/dist/esm/node/prerender/runPrerender.js +75 -67
  52. package/dist/esm/node/runtime/html/injectAssets/injectAssets__public.js +1 -1
  53. package/dist/esm/node/runtime/index-common.d.ts +1 -0
  54. package/dist/esm/node/runtime/index-common.js +1 -0
  55. package/dist/esm/node/runtime/renderPage/analyzePage.js +2 -2
  56. package/dist/esm/node/runtime/renderPage/createHttpResponseObject/assertNoInfiniteHttpRedirect.d.ts +1 -1
  57. package/dist/esm/node/runtime/renderPage/createHttpResponseObject/assertNoInfiniteHttpRedirect.js +12 -12
  58. package/dist/esm/node/runtime/renderPage/createHttpResponseObject.d.ts +1 -1
  59. package/dist/esm/node/runtime/renderPage/createHttpResponseObject.js +3 -3
  60. package/dist/esm/node/runtime/renderPage/executeOnRenderHtmlHook.js +1 -2
  61. package/dist/esm/node/runtime/renderPage/getHttpResponseBody.js +1 -1
  62. package/dist/esm/node/runtime/renderPage.js +9 -6
  63. package/dist/esm/shared/getPageFiles/analyzePageClientSide/determineClientEntry.js +1 -0
  64. package/dist/esm/shared/page-configs/PageConfig.d.ts +14 -4
  65. package/dist/esm/shared/page-configs/loadConfigValues.js +12 -3
  66. package/dist/esm/shared/page-configs/serialize/parseConfigValuesSerialized.d.ts +4 -0
  67. package/dist/esm/shared/page-configs/serialize/parseConfigValuesSerialized.js +16 -0
  68. package/dist/esm/shared/page-configs/serialize/parsePageConfigs.js +4 -13
  69. package/dist/esm/utils/assertKeys.d.ts +4 -0
  70. package/dist/esm/utils/assertKeys.js +22 -0
  71. package/dist/esm/utils/joinEnglish.d.ts +1 -1
  72. package/dist/esm/utils/joinEnglish.js +3 -3
  73. package/dist/esm/utils/parseUrl.js +24 -16
  74. package/dist/esm/utils/projectInfo.d.ts +3 -1
  75. package/dist/esm/utils/projectInfo.js +2 -1
  76. package/package.json +3 -3
  77. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/helpers.js +0 -28
  78. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/helpers.d.ts +0 -5
  79. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/helpers.js +0 -25
  80. package/dist/esm/node/plugin/shared/getConfigValueSourcesRelevant.d.ts +0 -5
@@ -1,15 +1,11 @@
1
1
  export { getVirtualFilePageConfigs };
2
- export { getConfigValueSerialized };
3
- import { assert, assertUsage, getPropAccessNotation, objectEntries } from '../../../utils.js';
2
+ import { assert, objectEntries } from '../../../utils.js';
4
3
  import { getVirtualFileIdPageConfigValuesAll } from '../../../../shared/virtual-files/virtualFilePageConfigValuesAll.js';
5
4
  import { debug } from './debug.js';
6
- import { isJsonSerializerError, stringify } from '@brillout/json-serializer/stringify';
7
- import { getConfigEnv } from './helpers.js';
8
- import pc from '@brillout/picocolors';
9
5
  import { getVikeConfig } from './getVikeConfig.js';
10
6
  import { isRuntimeEnvMatch } from './isRuntimeEnvMatch.js';
11
- import { getConfigValueFilePathToShowToUser } from '../../../../../shared/page-configs/helpers.js';
12
- import { serializeConfigValue, serializeConfigValueImported } from '../../../../../shared/page-configs/serialize/serializeConfigValue.js';
7
+ import { serializeConfigValueImported } from '../../../../../shared/page-configs/serialize/serializeConfigValue.js';
8
+ import { getConfigValuesSerialized } from './getConfigValuesSerialized.js';
13
9
  async function getVirtualFilePageConfigs(isForClientSide, isDev, id, isClientRouting, config) {
14
10
  const { pageConfigs, pageConfigGlobal } = await getVikeConfig(config, isDev, true);
15
11
  return getCode(pageConfigs, pageConfigGlobal, isForClientSide, isDev, id, isClientRouting);
@@ -18,15 +14,18 @@ function getCode(pageConfigs, pageConfigGlobal, isForClientSide, isDev, id, isCl
18
14
  const lines = [];
19
15
  const importStatements = [];
20
16
  const varCounterContainer = { varCounter: 0 };
17
+ lines.push('export const pageConfigsSerialized = [');
21
18
  lines.push(getCodePageConfigsSerialized(pageConfigs, isForClientSide, isClientRouting, importStatements, varCounterContainer));
19
+ lines.push('];');
20
+ lines.push('export const pageConfigGlobalSerialized = {');
22
21
  lines.push(getCodePageConfigGlobalSerialized(pageConfigGlobal, isForClientSide, isDev, importStatements, varCounterContainer));
22
+ lines.push('};');
23
23
  const code = [...importStatements, ...lines].join('\n');
24
24
  debug(id, isForClientSide ? 'CLIENT-SIDE' : 'SERVER-SIDE', code);
25
25
  return code;
26
26
  }
27
27
  function getCodePageConfigsSerialized(pageConfigs, isForClientSide, isClientRouting, importStatements, varCounterContainer) {
28
28
  const lines = [];
29
- lines.push('export const pageConfigsSerialized = [');
30
29
  pageConfigs.forEach((pageConfig) => {
31
30
  const { pageId, routeFilesystem, isErrorPage } = pageConfig;
32
31
  const virtualFileIdPageConfigValuesAll = getVirtualFileIdPageConfigValuesAll(pageId, isForClientSide);
@@ -34,35 +33,13 @@ function getCodePageConfigsSerialized(pageConfigs, isForClientSide, isClientRout
34
33
  lines.push(` pageId: ${JSON.stringify(pageId)},`);
35
34
  lines.push(` isErrorPage: ${JSON.stringify(isErrorPage)},`);
36
35
  lines.push(` routeFilesystem: ${JSON.stringify(routeFilesystem)},`);
37
- lines.push(` loadConfigValuesAll: async () => (await import(${JSON.stringify(virtualFileIdPageConfigValuesAll)})).default,`);
36
+ lines.push(` loadConfigValuesAll: () => import(${JSON.stringify(virtualFileIdPageConfigValuesAll)}),`);
37
+ // Serialized config values
38
38
  lines.push(` configValuesSerialized: {`);
39
- Object.entries(pageConfig.configValuesComputed).forEach(([configName, configValuesComputed]) => {
40
- const { value, configEnv } = configValuesComputed;
41
- if (!isRuntimeEnvMatch(configEnv, { isForClientSide, isClientRouting, isEager: true }))
42
- return;
43
- if (pageConfig.configValueSources[configName])
44
- return;
45
- const configValue = pageConfig.configValues[configName];
46
- assert(configValue);
47
- const { definedAt } = configValue;
48
- const valueSerialized = getConfigValueSerialized(value, configName, definedAt);
49
- serializeConfigValue(lines, configName, { definedAt, valueSerialized });
50
- });
51
- Object.entries(pageConfig.configValueSources).forEach(([configName]) => {
52
- const configValue = pageConfig.configValues[configName];
53
- if (configValue) {
54
- const configEnv = getConfigEnv(pageConfig.configValueSources, configName);
55
- assert(configEnv, configName);
56
- const isEnvMatch = isRuntimeEnvMatch(configEnv, { isForClientSide, isClientRouting, isEager: true });
57
- if (!isEnvMatch)
58
- return;
59
- const { value, definedAt } = configValue;
60
- const valueSerialized = getConfigValueSerialized(value, configName, definedAt);
61
- serializeConfigValue(lines, configName, { definedAt, valueSerialized });
62
- }
63
- });
39
+ lines.push(getConfigValuesSerialized(pageConfig, (configEnv) => isRuntimeEnvMatch(configEnv, { isForClientSide, isClientRouting, isEager: true })));
64
40
  lines.push(` },`);
65
- let whitespace = ' ';
41
+ // Imported config values
42
+ const whitespace = ' ';
66
43
  lines.push(`${whitespace}configValuesImported: [`);
67
44
  Object.entries(pageConfig.configValueSources).forEach(([configName, sources]) => {
68
45
  const configValue = pageConfig.configValues[configName];
@@ -70,21 +47,18 @@ function getCodePageConfigsSerialized(pageConfigs, isForClientSide, isClientRout
70
47
  return;
71
48
  const configValueSource = sources[0];
72
49
  assert(configValueSource);
73
- if (configValueSource.configEnv !== '_routing-eager')
50
+ if (!configValueSource.configEnv.eager)
74
51
  return;
75
52
  lines.push(...serializeConfigValueImported(configValueSource, configName, whitespace, varCounterContainer, importStatements));
76
53
  });
77
54
  lines.push(`${whitespace}],`);
78
- // pageConfig end
79
55
  lines.push(` },`);
80
56
  });
81
- lines.push('];');
82
57
  const code = lines.join('\n');
83
58
  return code;
84
59
  }
85
60
  function getCodePageConfigGlobalSerialized(pageConfigGlobal, isForClientSide, isDev, importStatements, varCounterContainer) {
86
61
  const lines = [];
87
- lines.push('export const pageConfigGlobalSerialized = {');
88
62
  /* Nothing (yet)
89
63
  lines.push(` configValuesSerialized: {`)
90
64
  lines.push(` },`)
@@ -109,35 +83,6 @@ function getCodePageConfigGlobalSerialized(pageConfigGlobal, isForClientSide, is
109
83
  lines.push(...serializeConfigValueImported(configValueSource, configName, whitespace, varCounterContainer, importStatements));
110
84
  });
111
85
  lines.push(` ],`);
112
- lines.push('};');
113
86
  const code = lines.join('\n');
114
87
  return code;
115
88
  }
116
- function getConfigValueSerialized(value, configName, definedAt) {
117
- const valueName = `config${getPropAccessNotation(configName)}`;
118
- let configValueSerialized;
119
- try {
120
- configValueSerialized = stringify(value, { valueName, forbidReactElements: true });
121
- }
122
- catch (err) {
123
- let serializationErrMsg = '';
124
- if (isJsonSerializerError(err)) {
125
- serializationErrMsg = err.messageCore;
126
- }
127
- else {
128
- // When a property getter throws an error
129
- console.error('Serialization error:');
130
- console.error(err);
131
- serializationErrMsg = 'see serialization error printed above';
132
- }
133
- const configValueFilePathToShowToUser = getConfigValueFilePathToShowToUser({ definedAt });
134
- assert(configValueFilePathToShowToUser);
135
- assertUsage(false, [
136
- `The value of the config ${pc.cyan(configName)} cannot be defined inside the file ${configValueFilePathToShowToUser}:`,
137
- `its value must be defined in an another file and then imported by ${configValueFilePathToShowToUser}. (Because its value isn't serializable: ${serializationErrMsg}.)`,
138
- `Only serializable config values can be defined inside +config.h.js files, see https://vike.dev/header-file.`
139
- ].join(' '));
140
- }
141
- configValueSerialized = JSON.stringify(configValueSerialized);
142
- return configValueSerialized;
143
- }
@@ -1,15 +1,18 @@
1
1
  export { isRuntimeEnvMatch };
2
2
  function isRuntimeEnvMatch(configEnv, runtime) {
3
- const { isForClientSide, isClientRouting, isEager } = runtime;
4
- if (configEnv === 'config-only')
5
- return false;
6
- if (configEnv === (isForClientSide ? 'server-only' : 'client-only'))
7
- return false;
8
- if (configEnv === '_routing-eager' || configEnv === '_routing-lazy') {
9
- if (isForClientSide && !isClientRouting)
3
+ // Runtime
4
+ if (!runtime.isForClientSide) {
5
+ if (!configEnv.server)
10
6
  return false;
11
- if (isEager !== (configEnv === '_routing-eager'))
7
+ }
8
+ else {
9
+ if (!configEnv.client)
10
+ return false;
11
+ if (configEnv.client === 'if-client-routing' && !runtime.isClientRouting)
12
12
  return false;
13
13
  }
14
+ // Eager
15
+ if (runtime.isEager !== !!configEnv.eager)
16
+ return false;
14
17
  return true;
15
18
  }
@@ -0,0 +1,5 @@
1
+ export { getConfigValueSourcesNotOverriden };
2
+ import type { ConfigValueSource, PageConfigBuildTime } from '../../../shared/page-configs/PageConfig.js';
3
+ declare function getConfigValueSourcesNotOverriden(pageConfig: PageConfigBuildTime): (ConfigValueSource & {
4
+ configName: string;
5
+ })[];
@@ -1,7 +1,7 @@
1
- export { getConfigValueSourcesRelevant };
1
+ export { getConfigValueSourcesNotOverriden };
2
2
  import { assert, assertIsNotBrowser } from '../../shared/utils.js';
3
3
  assertIsNotBrowser();
4
- function getConfigValueSourcesRelevant(pageConfig) {
4
+ function getConfigValueSourcesNotOverriden(pageConfig) {
5
5
  const configValueSourcesRelevant = Object.entries(pageConfig.configValueSources).map(([configName, sources]) => {
6
6
  const configValueSource = sources[0];
7
7
  assert(configValueSource);
@@ -16,3 +16,5 @@ export * from '../../utils/removeEmptyLines.js';
16
16
  export * from '../../utils/findUserPackageJsonPath.js';
17
17
  export * from '../../utils/getPropAccessNotation.js';
18
18
  export * from '../../utils/mergeCumulativeValues.js';
19
+ export * from '../../utils/deepEqual.js';
20
+ export * from '../../utils/assertKeys.js';
@@ -22,3 +22,5 @@ export * from '../../utils/removeEmptyLines.js';
22
22
  export * from '../../utils/findUserPackageJsonPath.js';
23
23
  export * from '../../utils/getPropAccessNotation.js';
24
24
  export * from '../../utils/mergeCumulativeValues.js';
25
+ export * from '../../utils/deepEqual.js';
26
+ export * from '../../utils/assertKeys.js';
@@ -71,19 +71,25 @@ async function runPrerender(options, manuallyTriggered) {
71
71
  const doNotPrerenderList = [];
72
72
  const vikeConfig = await getVikeConfig(viteConfig, false);
73
73
  await collectDoNoPrerenderList(renderContext, vikeConfig.pageConfigs, doNotPrerenderList, concurrencyLimit);
74
- await callOnBeforePrerenderStartHooks(prerenderContext, renderContext, concurrencyLimit);
74
+ await callOnBeforePrerenderStartHooks(prerenderContext, renderContext, concurrencyLimit, doNotPrerenderList);
75
75
  await handlePagesWithStaticRoutes(prerenderContext, renderContext, doNotPrerenderList, concurrencyLimit);
76
76
  await callOnPrerenderStartHook(prerenderContext, renderContext);
77
- const prerenderPageIds = {};
78
- const htmlFiles = [];
79
- await routeAndPrerender(prerenderContext, htmlFiles, prerenderPageIds, concurrencyLimit);
80
- warnContradictoryNoPrerenderList(prerenderPageIds, doNotPrerenderList);
81
- await prerender404(htmlFiles, renderContext, prerenderContext);
77
+ const prerenderedPageContexts = {};
78
+ let prerenderedCount = 0;
79
+ const onComplete = async (htmlFile) => {
80
+ prerenderedCount++;
81
+ if (htmlFile.pageId) {
82
+ prerenderedPageContexts[htmlFile.pageId] = htmlFile.pageContext;
83
+ }
84
+ await writeFiles(htmlFile, root, outDirClient, options.onPagePrerender, logLevel);
85
+ };
86
+ await routeAndPrerender(prerenderContext, concurrencyLimit, onComplete);
87
+ warnContradictoryNoPrerenderList(prerenderedPageContexts, doNotPrerenderList);
88
+ await prerender404(prerenderedPageContexts, renderContext, prerenderContext, onComplete);
82
89
  if (logLevel === 'info') {
83
- console.log(`${pc.green(`✓`)} ${htmlFiles.length} HTML documents pre-rendered.`);
90
+ console.log(`${pc.green(`✓`)} ${prerenderedCount} HTML documents pre-rendered.`);
84
91
  }
85
- await Promise.all(htmlFiles.map((htmlFile) => writeHtmlFile(htmlFile, root, outDirClient, concurrencyLimit, options.onPagePrerender, logLevel)));
86
- warnMissingPages(prerenderPageIds, doNotPrerenderList, renderContext, partial);
92
+ warnMissingPages(prerenderedPageContexts, doNotPrerenderList, renderContext, partial);
87
93
  }
88
94
  async function collectDoNoPrerenderList(renderContext, pageConfigs, doNotPrerenderList, concurrencyLimit) {
89
95
  // V1 design
@@ -145,7 +151,7 @@ function assertExportNames(pageFile) {
145
151
  const { exportNames, fileType } = pageFile;
146
152
  assert(exportNames || fileType === '.page.route' || fileType === '.css', pageFile.filePath);
147
153
  }
148
- async function callOnBeforePrerenderStartHooks(prerenderContext, renderContext, concurrencyLimit) {
154
+ async function callOnBeforePrerenderStartHooks(prerenderContext, renderContext, concurrencyLimit, doNotPrerenderList) {
149
155
  const onBeforePrerenderStartHooks = [];
150
156
  // V1 design
151
157
  await Promise.all(renderContext.pageConfigs.map((pageConfig) => concurrencyLimit(async () => {
@@ -161,7 +167,8 @@ async function callOnBeforePrerenderStartHooks(prerenderContext, renderContext,
161
167
  onBeforePrerenderStartHooks.push({
162
168
  hookFn,
163
169
  hookName: 'onBeforePrerenderStart',
164
- hookFilePath
170
+ hookFilePath,
171
+ pageId: pageConfig.pageId
165
172
  });
166
173
  })));
167
174
  // 0.4 design
@@ -184,10 +191,14 @@ async function callOnBeforePrerenderStartHooks(prerenderContext, renderContext,
184
191
  onBeforePrerenderStartHooks.push({
185
192
  hookFn,
186
193
  hookName: 'prerender',
187
- hookFilePath
194
+ hookFilePath,
195
+ pageId: p.pageId
188
196
  });
189
197
  })));
190
- await Promise.all(onBeforePrerenderStartHooks.map(({ hookFn, hookName, hookFilePath }) => concurrencyLimit(async () => {
198
+ await Promise.all(onBeforePrerenderStartHooks.map(({ hookFn, hookName, hookFilePath, pageId }) => concurrencyLimit(async () => {
199
+ if (doNotPrerenderList.find((p) => p.pageId === pageId)) {
200
+ return;
201
+ }
191
202
  const prerenderResult = await hookFn();
192
203
  const result = normalizeOnPrerenderHookResult(prerenderResult, hookFilePath, hookName);
193
204
  result.forEach(({ url, pageContext }) => {
@@ -406,7 +417,7 @@ async function callOnPrerenderStartHook(prerenderContext, renderContext) {
406
417
  addUrlComputedProps(pageContext);
407
418
  });
408
419
  }
409
- async function routeAndPrerender(prerenderContext, htmlFiles, prerenderPageIds, concurrencyLimit) {
420
+ async function routeAndPrerender(prerenderContext, concurrencyLimit, onComplete) {
410
421
  const globalContext = getGlobalContext();
411
422
  assert(globalContext.isPrerendering);
412
423
  // Route all URLs
@@ -466,7 +477,7 @@ async function routeAndPrerender(prerenderContext, htmlFiles, prerenderPageIds,
466
477
  throw err;
467
478
  }
468
479
  const { documentHtml, pageContextSerialized } = res;
469
- htmlFiles.push({
480
+ await onComplete({
470
481
  urlOriginal,
471
482
  pageContext,
472
483
  htmlString: documentHtml,
@@ -474,11 +485,10 @@ async function routeAndPrerender(prerenderContext, htmlFiles, prerenderPageIds,
474
485
  doNotCreateExtraDirectory: prerenderContext._noExtraDir,
475
486
  pageId
476
487
  });
477
- prerenderPageIds[pageId] = pageContext;
478
488
  })));
479
489
  }
480
- function warnContradictoryNoPrerenderList(prerenderPageIds, doNotPrerenderList) {
481
- Object.entries(prerenderPageIds).forEach(([pageId, pageContext]) => {
490
+ function warnContradictoryNoPrerenderList(prerenderedPageContexts, doNotPrerenderList) {
491
+ Object.entries(prerenderedPageContexts).forEach(([pageId, pageContext]) => {
482
492
  const doNotPrerenderListEntry = doNotPrerenderList.find((p) => p.pageId === pageId);
483
493
  const { urlOriginal, _providedByHook: providedByHook } = pageContext;
484
494
  {
@@ -490,7 +500,7 @@ function warnContradictoryNoPrerenderList(prerenderPageIds, doNotPrerenderList)
490
500
  assertWarning(false, `The ${providedByHook.hookName}() hook defined by ${providedByHook.hookFilePath} returns the URL ${pc.cyan(urlOriginal)}, while ${setByConfigFile} sets the config ${pc.cyan(setByConfigName)} to ${pc.cyan(String(setByConfigValue))}. This is contradictory: either don't set the config ${pc.cyan(setByConfigName)} to ${pc.cyan(String(setByConfigValue))} or remove the URL ${pc.cyan(urlOriginal)} from the list of URLs to be pre-rendered.`, { onlyOnce: true });
491
501
  });
492
502
  }
493
- function warnMissingPages(prerenderPageIds, doNotPrerenderList, renderContext, partial) {
503
+ function warnMissingPages(prerenderedPageContexts, doNotPrerenderList, renderContext, partial) {
494
504
  const isV1 = renderContext.pageConfigs.length > 0;
495
505
  const hookName = isV1 ? 'onBeforePrerenderStart' : 'prerender';
496
506
  /* TODO/after-v1-design-release: document setting `prerender: false` as an alternative to using prerender.partial (both in the warnings and the docs)
@@ -498,7 +508,7 @@ function warnMissingPages(prerenderPageIds, doNotPrerenderList, renderContext, p
498
508
  const msgAddendum = `Explicitly opt-out by setting the config ${optOutName} to ${isV1 ? 'false' : 'true'} or use the option prerender.partial`
499
509
  */
500
510
  renderContext.allPageIds
501
- .filter((pageId) => !prerenderPageIds[pageId])
511
+ .filter((pageId) => !prerenderedPageContexts[pageId])
502
512
  .filter((pageId) => !doNotPrerenderList.find((p) => p.pageId === pageId))
503
513
  .filter((pageId) => !isErrorPage(pageId, renderContext.pageConfigs))
504
514
  .forEach((pageId) => {
@@ -506,8 +516,8 @@ function warnMissingPages(prerenderPageIds, doNotPrerenderList, renderContext, p
506
516
  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 });
507
517
  });
508
518
  }
509
- async function prerender404(htmlFiles, renderContext, prerenderContext) {
510
- if (!htmlFiles.find(({ urlOriginal }) => urlOriginal === '/404')) {
519
+ async function prerender404(prerenderedPageContexts, renderContext, prerenderContext, onComplete) {
520
+ if (!Object.values(prerenderedPageContexts).find(({ urlOriginal }) => urlOriginal === '/404')) {
511
521
  let result;
512
522
  try {
513
523
  result = await prerender404Page(renderContext, prerenderContext.pageContextInit);
@@ -519,7 +529,7 @@ async function prerender404(htmlFiles, renderContext, prerenderContext) {
519
529
  if (result) {
520
530
  const urlOriginal = '/404';
521
531
  const { documentHtml, pageContext } = result;
522
- htmlFiles.push({
532
+ await onComplete({
523
533
  urlOriginal,
524
534
  pageContext,
525
535
  htmlString: documentHtml,
@@ -530,59 +540,57 @@ async function prerender404(htmlFiles, renderContext, prerenderContext) {
530
540
  }
531
541
  }
532
542
  }
533
- async function writeHtmlFile({ urlOriginal, pageContext, htmlString, pageContextSerialized, doNotCreateExtraDirectory }, root, outDirClient, concurrencyLimit, onPagePrerender, logLevel) {
543
+ async function writeFiles({ urlOriginal, pageContext, htmlString, pageContextSerialized, doNotCreateExtraDirectory }, root, outDirClient, onPagePrerender, logLevel) {
534
544
  assert(urlOriginal.startsWith('/'));
535
545
  const writeJobs = [
536
- write(urlOriginal, pageContext, '.html', htmlString, root, outDirClient, doNotCreateExtraDirectory, concurrencyLimit, onPagePrerender, logLevel)
546
+ write(urlOriginal, pageContext, '.html', htmlString, root, outDirClient, doNotCreateExtraDirectory, onPagePrerender, logLevel)
537
547
  ];
538
548
  if (pageContextSerialized !== null) {
539
- writeJobs.push(write(urlOriginal, pageContext, '.pageContext.json', pageContextSerialized, root, outDirClient, doNotCreateExtraDirectory, concurrencyLimit, onPagePrerender, logLevel));
549
+ writeJobs.push(write(urlOriginal, pageContext, '.pageContext.json', pageContextSerialized, root, outDirClient, doNotCreateExtraDirectory, onPagePrerender, logLevel));
540
550
  }
541
551
  await Promise.all(writeJobs);
542
552
  }
543
- function write(urlOriginal, pageContext, fileExtension, fileContent, root, outDirClient, doNotCreateExtraDirectory, concurrencyLimit, onPagePrerender, logLevel) {
544
- return concurrencyLimit(async () => {
545
- let fileUrl;
546
- if (fileExtension === '.html') {
547
- fileUrl = urlToFile(urlOriginal, '.html', doNotCreateExtraDirectory);
548
- }
549
- else {
550
- fileUrl = getPageContextRequestUrl(urlOriginal);
551
- }
552
- assertPosixPath(fileUrl);
553
- assert(fileUrl.startsWith('/'));
554
- const filePathRelative = fileUrl.slice(1);
555
- assert(!filePathRelative.startsWith('/'));
556
- assertPosixPath(outDirClient);
557
- assertPosixPath(filePathRelative);
558
- const filePath = path.posix.join(outDirClient, filePathRelative);
559
- if (onPagePrerender) {
560
- const prerenderPageContext = {};
561
- objectAssign(prerenderPageContext, pageContext);
562
- objectAssign(prerenderPageContext, {
563
- _prerenderResult: {
564
- filePath,
565
- fileContent
566
- }
567
- });
568
- await onPagePrerender(prerenderPageContext);
569
- }
570
- else {
571
- const { promises } = await import('fs');
572
- const { writeFile, mkdir } = promises;
573
- await mkdir(path.posix.dirname(filePath), { recursive: true });
574
- await writeFile(filePath, fileContent);
575
- if (logLevel === 'info') {
576
- assertPosixPath(root);
577
- assertPosixPath(outDirClient);
578
- let outDirClientRelative = path.posix.relative(root, outDirClient);
579
- if (!outDirClientRelative.endsWith('/')) {
580
- outDirClientRelative = outDirClientRelative + '/';
581
- }
582
- console.log(`${pc.dim(outDirClientRelative)}${pc.blue(filePathRelative)}`);
553
+ async function write(urlOriginal, pageContext, fileExtension, fileContent, root, outDirClient, doNotCreateExtraDirectory, onPagePrerender, logLevel) {
554
+ let fileUrl;
555
+ if (fileExtension === '.html') {
556
+ fileUrl = urlToFile(urlOriginal, '.html', doNotCreateExtraDirectory);
557
+ }
558
+ else {
559
+ fileUrl = getPageContextRequestUrl(urlOriginal);
560
+ }
561
+ assertPosixPath(fileUrl);
562
+ assert(fileUrl.startsWith('/'));
563
+ const filePathRelative = fileUrl.slice(1);
564
+ assert(!filePathRelative.startsWith('/'));
565
+ assertPosixPath(outDirClient);
566
+ assertPosixPath(filePathRelative);
567
+ const filePath = path.posix.join(outDirClient, filePathRelative);
568
+ if (onPagePrerender) {
569
+ const prerenderPageContext = {};
570
+ objectAssign(prerenderPageContext, pageContext);
571
+ objectAssign(prerenderPageContext, {
572
+ _prerenderResult: {
573
+ filePath,
574
+ fileContent
583
575
  }
576
+ });
577
+ await onPagePrerender(prerenderPageContext);
578
+ }
579
+ else {
580
+ const { promises } = await import('fs');
581
+ const { writeFile, mkdir } = promises;
582
+ await mkdir(path.posix.dirname(filePath), { recursive: true });
583
+ await writeFile(filePath, fileContent);
584
+ if (logLevel === 'info') {
585
+ assertPosixPath(root);
586
+ assertPosixPath(outDirClient);
587
+ let outDirClientRelative = path.posix.relative(root, outDirClient);
588
+ if (!outDirClientRelative.endsWith('/')) {
589
+ outDirClientRelative = outDirClientRelative + '/';
590
+ }
591
+ console.log(`${pc.dim(outDirClientRelative)}${pc.blue(filePathRelative)}`);
584
592
  }
585
- });
593
+ }
586
594
  }
587
595
  function normalizeOnPrerenderHookResult(prerenderResult, prerenderHookFile, hookName) {
588
596
  if (Array.isArray(prerenderResult)) {
@@ -1,7 +1,7 @@
1
1
  export { injectAssets__public };
2
2
  import { assertUsage, assertWarning, castProp, hasProp } from '../../utils.js';
3
3
  import { injectHtmlTagsToString } from '../injectAssets.js';
4
- // TODO: remove this on next semver major
4
+ // TODO/v1-release: remove
5
5
  async function injectAssets__public(htmlString, pageContext) {
6
6
  assertWarning(false, '`_injectAssets()` is deprecated and will be removed.', { onlyOnce: true, showStackTrace: true });
7
7
  assertUsage(typeof htmlString === 'string', '[injectAssets(htmlString, pageContext)]: Argument `htmlString` should be a string.', { showStackTrace: true });
@@ -1,6 +1,7 @@
1
1
  export { renderPage } from './renderPage.js';
2
2
  export { escapeInject, dangerouslySkipEscape } from './html/renderHtml.js';
3
3
  export { pipeWebStream, pipeNodeStream, pipeStream, stampPipe } from './html/stream.js';
4
+ export { PROJECT_VERSION as version } from './utils.js';
4
5
  export { injectAssets__public as _injectAssets } from './html/injectAssets/injectAssets__public.js';
5
6
  export { createPageRenderer } from '../createPageRenderer.js';
6
7
  declare global {
@@ -1,6 +1,7 @@
1
1
  export { renderPage } from './renderPage.js';
2
2
  export { escapeInject, dangerouslySkipEscape } from './html/renderHtml.js';
3
3
  export { pipeWebStream, pipeNodeStream, pipeStream, stampPipe } from './html/stream.js';
4
+ export { PROJECT_VERSION as version } from './utils.js';
4
5
  // TODO/v1-release: remove
5
6
  export { injectAssets__public as _injectAssets } from './html/injectAssets/injectAssets__public.js';
6
7
  // TODO/v1-release: remove
@@ -29,8 +29,8 @@ function analyzePage(pageFilesAll, pageConfig, pageId) {
29
29
  if (configElement.importPath) {
30
30
  const { env } = configElement
31
31
  assert(env)
32
- const onlyAssets = env === 'server-only'
33
- const eagerlyImported = env === '_routing-eager'
32
+ const onlyAssets = env === { server: true }
33
+ const eagerlyImported = env === { server: true, client: 'if-client-routing', eager: true }
34
34
  if (onlyAssets || eagerlyImported) {
35
35
  clientDependencies.push({
36
36
  id: configElement.importPath,
@@ -1,2 +1,2 @@
1
1
  export { assertNoInfiniteHttpRedirect };
2
- declare function assertNoInfiniteHttpRedirect(urlRedirectOriginal: string, urlRedirectPathnameLogical: string): void;
2
+ declare function assertNoInfiniteHttpRedirect(urlRedirectTarget: string, urlLogical: string): void;
@@ -4,21 +4,21 @@ import pc from '@brillout/picocolors';
4
4
  const globalObject = getGlobalObject('assertNoInfiniteHttpRedirect.ts', {
5
5
  redirectGraph: {}
6
6
  });
7
- function assertNoInfiniteHttpRedirect(urlRedirectOriginal, urlRedirectPathnameLogical) {
8
- if (urlRedirectOriginal.startsWith('http')) {
9
- // We assume that the redirect points to an external origin, and we can therefore assume that the app doesn't define an infinite loop (in itself).
10
- // - There isn't a reliable way to check whether the redirect points to an external origin or the same origin: the user usually passes the URL without origin.
7
+ function assertNoInfiniteHttpRedirect(urlRedirectTarget, urlLogical) {
8
+ if (urlRedirectTarget.startsWith('http')) {
9
+ // We assume that urlRedirectTarget points to an origin that is external (not the same origin), and we can therefore assume that the app doesn't define an infinite loop (in itself).
10
+ // - There isn't a reliable way to check whether the redirect points to an external origin or the same origin. For same origins, we assume/hope the user to pass the URL without origin.
11
11
  // ```js
12
- // // URL origin is usually missing
12
+ // // For same-origin, the user usually/hopefully passes a URL without origin
13
13
  // renderPage({ urlOriginal: '/some/pathname' })
14
14
  // ```
15
15
  return;
16
16
  }
17
- assert(urlRedirectOriginal.startsWith('/'));
18
- assert(urlRedirectPathnameLogical.startsWith('/'));
17
+ assert(urlRedirectTarget.startsWith('/'));
18
+ assert(urlLogical.startsWith('/'));
19
19
  const graph = copy(globalObject.redirectGraph);
20
- graph[urlRedirectOriginal] ?? (graph[urlRedirectOriginal] = new Set());
21
- graph[urlRedirectOriginal].add(urlRedirectPathnameLogical);
20
+ graph[urlRedirectTarget] ?? (graph[urlRedirectTarget] = new Set());
21
+ graph[urlRedirectTarget].add(urlLogical);
22
22
  validate(graph);
23
23
  globalObject.redirectGraph = graph;
24
24
  }
@@ -26,6 +26,9 @@ function copy(G) {
26
26
  return Object.fromEntries(Object.entries(G).map(([key, val]) => [key, new Set(val)]));
27
27
  }
28
28
  // Adapted from: https://stackoverflow.com/questions/60904464/detect-cycle-in-directed-graph/60907076#60907076
29
+ function validate(G) {
30
+ Object.keys(G).forEach((n) => check(G, n, []));
31
+ }
29
32
  function check(G, n, path) {
30
33
  if (path.includes(n)) {
31
34
  const cycle = path.slice(path.indexOf(n)).concat(n);
@@ -33,6 +36,3 @@ function check(G, n, path) {
33
36
  }
34
37
  G[n]?.forEach((node) => check(G, node, [...path, n]));
35
38
  }
36
- function validate(G) {
37
- Object.keys(G).forEach((n) => check(G, n, []));
38
- }
@@ -25,4 +25,4 @@ declare function createHttpResponseObject(htmlRender: null | HtmlRender, renderH
25
25
  abortStatusCode?: AbortStatusCode;
26
26
  }): Promise<HttpResponse | null>;
27
27
  declare function createHttpResponsePageContextJson(pageContextSerialized: string): Promise<HttpResponse>;
28
- declare function createHttpResponseObjectRedirect({ url, statusCode }: UrlRedirect, urlPathnameLogical: string): HttpResponse;
28
+ declare function createHttpResponseObjectRedirect({ url, statusCode }: UrlRedirect, urlLogical: string): HttpResponse;
@@ -33,9 +33,9 @@ async function createHttpResponsePageContextJson(pageContextSerialized) {
33
33
  return httpResponse;
34
34
  }
35
35
  function createHttpResponseObjectRedirect({ url, statusCode },
36
- // The URL pathname we assume the redirect to be logically based on
37
- urlPathnameLogical) {
38
- assertNoInfiniteHttpRedirect(url, urlPathnameLogical);
36
+ // The URL we assume the redirect to be logically based on
37
+ urlLogical) {
38
+ assertNoInfiniteHttpRedirect(url, urlLogical);
39
39
  assert(url);
40
40
  assert(statusCode);
41
41
  assert(300 <= statusCode && statusCode <= 399);
@@ -9,8 +9,7 @@ import { assertHookReturnedObject } from '../../../shared/assertHookReturnedObje
9
9
  import { logRuntimeError } from './loggerRuntime.js';
10
10
  import pc from '@brillout/picocolors';
11
11
  async function executeOnRenderHtmlHook(pageContext) {
12
- const hookFound = getRenderHook(pageContext);
13
- const { renderHook, hookFn } = hookFound;
12
+ const { renderHook, hookFn } = getRenderHook(pageContext);
14
13
  objectAssign(pageContext, { _renderHook: renderHook });
15
14
  preparePageContextForUserConsumptionServerSide(pageContext);
16
15
  const hookReturnValue = await executeHook(() => hookFn(pageContext), renderHook.hookName, renderHook.hookFilePath);
@@ -7,7 +7,7 @@ import pc from '@brillout/picocolors';
7
7
  const streamDocs = 'See https://vike.dev/stream for more information.';
8
8
  function getHttpResponseBody(htmlRender, renderHook) {
9
9
  if (typeof htmlRender !== 'string') {
10
- assertUsage(false, getErrMsg(htmlRender, renderHook, 'body', `Use ${pc.cyan('pageContext.httpResponse.pipe()')} or ${pc.cyan('pageContext.httpResponse.getBody()')} instead`));
10
+ assertUsage(false, getErrMsg(htmlRender, renderHook, 'body', `Use ${pc.cyan('pageContext.httpResponse.pipe()')} instead`));
11
11
  }
12
12
  const body = htmlRender;
13
13
  return body;
@@ -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';
@@ -327,10 +327,8 @@ function normalizeUrl(pageContextInit, httpRequestId) {
327
327
  function getPermanentRedirect(pageContextInit, httpRequestId) {
328
328
  const { redirects, baseServer } = getGlobalContext();
329
329
  const urlWithoutBase = removeBaseServer(pageContextInit.urlOriginal, baseServer);
330
- let urlOriginalPathnameWithouBase;
331
330
  let origin = null;
332
331
  let urlTarget = modifyUrlPathname(urlWithoutBase, (urlPathname) => {
333
- urlOriginalPathnameWithouBase = urlPathname;
334
332
  const urlTargetWithOrigin = resolveRedirects(redirects, urlPathname);
335
333
  if (urlTargetWithOrigin === null)
336
334
  return null;
@@ -340,13 +338,12 @@ function getPermanentRedirect(pageContextInit, httpRequestId) {
340
338
  });
341
339
  if (origin)
342
340
  urlTarget = addUrlOrigin(urlTarget, origin);
343
- assert(urlOriginalPathnameWithouBase);
344
341
  if (urlTarget === urlWithoutBase)
345
342
  return null;
346
343
  logRuntimeInfo?.(`Permanent redirect defined by your config.redirects (https://vike.dev/redirects)`, httpRequestId, 'info');
347
344
  urlTarget = prependBase(urlTarget, baseServer);
348
345
  assert(urlTarget !== pageContextInit.urlOriginal);
349
- const httpResponse = createHttpResponseObjectRedirect({ url: urlTarget, statusCode: 301 }, urlOriginalPathnameWithouBase);
346
+ const httpResponse = createHttpResponseObjectRedirect({ url: urlTarget, statusCode: 301 }, urlWithoutBase);
350
347
  const pageContextHttpResponse = { ...pageContextInit, httpResponse };
351
348
  return pageContextHttpResponse;
352
349
  }
@@ -390,7 +387,13 @@ async function handleAbortError(errAbort, pageContextsFromRewrite, pageContextIn
390
387
  ...pageContextInit,
391
388
  ...pageContextAbort
392
389
  };
393
- const httpResponse = createHttpResponseObjectRedirect(pageContextAbort._urlRedirect, pageContextNominalPageInit.urlPathname);
390
+ const httpResponse = createHttpResponseObjectRedirect(pageContextAbort._urlRedirect, (() => {
391
+ const { pathname, searchOriginal } = pageContextNominalPageInit.urlParsed;
392
+ const urlLogical = createUrlFromComponents(null, pathname, searchOriginal,
393
+ // The server-side doesn't have access to the hash
394
+ null);
395
+ return urlLogical;
396
+ })());
394
397
  objectAssign(pageContextReturn, { httpResponse });
395
398
  return { pageContextReturn };
396
399
  }
@@ -1,3 +1,4 @@
1
+ // TODO/v1-release: remove
1
2
  export { determineClientEntry };
2
3
  export { getVikeClientEntry };
3
4
  function determineClientEntry({ pageFilesClientSide, pageFilesServerSide, isHtmlOnly, isClientRouting }) {