vike 0.4.146 → 0.4.147-commit-f9a91f3

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 (85) 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 +75 -51
  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/shared/route/resolveRedirects.js +8 -5
  26. package/dist/cjs/utils/assertKeys.js +28 -0
  27. package/dist/cjs/utils/joinEnglish.js +3 -3
  28. package/dist/cjs/utils/parseUrl-extras.js +22 -8
  29. package/dist/cjs/utils/parseUrl.js +24 -16
  30. package/dist/cjs/utils/projectInfo.js +3 -2
  31. package/dist/esm/client/client-routing-runtime/getPageContextFromHooks.js +25 -11
  32. package/dist/esm/client/client-routing-runtime/index.d.ts +1 -0
  33. package/dist/esm/client/client-routing-runtime/index.js +1 -0
  34. package/dist/esm/client/client-routing-runtime/onBrowserHistoryNavigation.js +2 -2
  35. package/dist/esm/client/shared/getPageContextSerializedInHtml.js +1 -1
  36. package/dist/esm/node/plugin/index.d.ts +1 -0
  37. package/dist/esm/node/plugin/index.js +1 -0
  38. package/dist/esm/node/plugin/plugins/devConfig/determineOptimizeDeps.js +3 -4
  39. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getConfigValuesSerialized.d.ts +5 -0
  40. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getConfigValuesSerialized.js +70 -0
  41. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/configDefinitionsBuiltIn.js +58 -37
  42. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.d.ts +5 -0
  43. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.js +98 -0
  44. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +63 -76
  45. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigValuesAll.js +43 -17
  46. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigs.d.ts +0 -3
  47. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigs.js +13 -68
  48. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/isRuntimeEnvMatch.js +11 -8
  49. package/dist/esm/node/plugin/shared/getConfigValueSourcesNotOverriden.d.ts +5 -0
  50. package/dist/esm/node/plugin/shared/{getConfigValueSourcesRelevant.js → getConfigValueSourcesNotOverriden.js} +2 -2
  51. package/dist/esm/node/plugin/utils.d.ts +2 -0
  52. package/dist/esm/node/plugin/utils.js +2 -0
  53. package/dist/esm/node/prerender/runPrerender.js +75 -67
  54. package/dist/esm/node/runtime/html/injectAssets/injectAssets__public.js +1 -1
  55. package/dist/esm/node/runtime/index-common.d.ts +1 -0
  56. package/dist/esm/node/runtime/index-common.js +1 -0
  57. package/dist/esm/node/runtime/renderPage/analyzePage.js +2 -2
  58. package/dist/esm/node/runtime/renderPage/createHttpResponseObject/assertNoInfiniteHttpRedirect.d.ts +1 -1
  59. package/dist/esm/node/runtime/renderPage/createHttpResponseObject/assertNoInfiniteHttpRedirect.js +13 -13
  60. package/dist/esm/node/runtime/renderPage/createHttpResponseObject.d.ts +1 -1
  61. package/dist/esm/node/runtime/renderPage/createHttpResponseObject.js +3 -3
  62. package/dist/esm/node/runtime/renderPage/executeOnRenderHtmlHook.js +1 -2
  63. package/dist/esm/node/runtime/renderPage/getHttpResponseBody.js +1 -1
  64. package/dist/esm/node/runtime/renderPage.js +76 -52
  65. package/dist/esm/shared/getPageFiles/analyzePageClientSide/determineClientEntry.js +1 -0
  66. package/dist/esm/shared/page-configs/PageConfig.d.ts +14 -4
  67. package/dist/esm/shared/page-configs/loadConfigValues.js +12 -3
  68. package/dist/esm/shared/page-configs/serialize/parseConfigValuesSerialized.d.ts +4 -0
  69. package/dist/esm/shared/page-configs/serialize/parseConfigValuesSerialized.js +16 -0
  70. package/dist/esm/shared/page-configs/serialize/parsePageConfigs.js +4 -13
  71. package/dist/esm/shared/route/resolveRedirects.js +8 -5
  72. package/dist/esm/utils/assertKeys.d.ts +4 -0
  73. package/dist/esm/utils/assertKeys.js +22 -0
  74. package/dist/esm/utils/joinEnglish.d.ts +1 -1
  75. package/dist/esm/utils/joinEnglish.js +3 -3
  76. package/dist/esm/utils/parseUrl-extras.d.ts +3 -1
  77. package/dist/esm/utils/parseUrl-extras.js +21 -7
  78. package/dist/esm/utils/parseUrl.js +24 -16
  79. package/dist/esm/utils/projectInfo.d.ts +3 -1
  80. package/dist/esm/utils/projectInfo.js +2 -1
  81. package/package.json +3 -3
  82. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/helpers.js +0 -28
  83. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/helpers.d.ts +0 -5
  84. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/helpers.js +0 -25
  85. package/dist/esm/node/plugin/shared/getConfigValueSourcesRelevant.d.ts +0 -5
@@ -27,7 +27,7 @@ async function getPageContextFromHooks_firstRender(pageContext) {
27
27
  objectAssign(pageContextFromHooks, await loadPageFilesClientSide(pageContextFromHooks._pageId, pageContext));
28
28
  {
29
29
  const pageContextForHook = { ...pageContext, ...pageContextFromHooks };
30
- if (await onBeforeRenderClientOnlyExists(pageContextForHook)) {
30
+ if (onBeforeRenderClientOnlyExists(pageContextForHook)) {
31
31
  const pageContextFromHook = await executeOnBeforeRenderHookClientSide(pageContextForHook);
32
32
  objectAssign(pageContextFromHooks, pageContextFromHook);
33
33
  }
@@ -57,13 +57,17 @@ async function getPageContextFromHooks_uponNavigation(pageContext) {
57
57
  }
58
58
  async function getPageContextAlreadyRouted(pageContext, isErrorPage) {
59
59
  let pageContextFromHooks = {};
60
+ objectAssign(pageContextFromHooks, { _hasPageContextFromClient: false });
60
61
  objectAssign(pageContextFromHooks, await loadPageFilesClientSide(pageContext._pageId, pageContext));
62
+ let pageContextFetchedFromServer = false;
61
63
  // Needs to be called before any client-side hook, because it may contain pageContextInit.user which is needed for guard() and onBeforeRender()
62
64
  if (
63
65
  // For the error page, we cannot fetch pageContext from the server because the pageContext JSON request is based on the URL
64
66
  !isErrorPage &&
67
+ // true if pageContextInit has some client data or the onBeforeRender hook is server-side only:
65
68
  (await hasPageContextServer({ ...pageContext, ...pageContextFromHooks }))) {
66
69
  const pageContextFromServer = await fetchPageContextFromServer(pageContext);
70
+ pageContextFetchedFromServer = true;
67
71
  if (!pageContextFromServer['_isError']) {
68
72
  objectAssign(pageContextFromHooks, pageContextFromServer);
69
73
  }
@@ -72,6 +76,7 @@ async function getPageContextAlreadyRouted(pageContext, isErrorPage) {
72
76
  assert(errorPageId);
73
77
  pageContextFromHooks = {};
74
78
  objectAssign(pageContextFromHooks, {
79
+ _hasPageContextFromClient: false,
75
80
  isHydration: false,
76
81
  _pageId: errorPageId
77
82
  });
@@ -91,25 +96,29 @@ async function getPageContextAlreadyRouted(pageContext, isErrorPage) {
91
96
  if (!isErrorPage) {
92
97
  // Should we really call the guard() hook on the client-side? Shouldn't we make the guard() hook a server-side only hook? Or maybe make its env configurable like onBeforeRender()?
93
98
  await executeGuardHook({
94
- _hasPageContextFromClient: false,
95
99
  ...pageContext,
96
100
  ...pageContextFromHooks
97
101
  }, (pageContext) => preparePageContextForUserConsumptionClientSide(pageContext, true));
98
102
  }
99
103
  }
104
+ // For the error page, we also execute the client-side onBeforeRender() hook, but maybe we shouldn't? The server-side does it as well (but maybe it shouldn't).
100
105
  {
101
- // For the error page, we also execute the client-side onBeforeRender() hook, but maybe we shouldn't? The server-side does it as well (but maybe it shouldn't).
102
- const pageContextFromOnBeforeRender = await executeOnBeforeRenderHookClientSide({
103
- ...pageContext,
104
- ...pageContextFromHooks
105
- });
106
- objectAssign(pageContextFromHooks, pageContextFromOnBeforeRender);
106
+ const pageContextForHook = { ...pageContext, ...pageContextFromHooks };
107
+ if (onBeforeRenderClientOnlyExists(pageContextForHook) || !pageContextFetchedFromServer) {
108
+ // This won't do anything if no hook has been defined or if the hook's env.client is false.
109
+ const pageContextFromHook = await executeOnBeforeRenderHookClientSide(pageContextForHook);
110
+ objectAssign(pageContextFromHooks, pageContextFromHook);
111
+ }
112
+ else {
113
+ assert(pageContextFetchedFromServer);
114
+ }
107
115
  }
108
116
  return pageContextFromHooks;
109
117
  }
110
118
  async function executeOnBeforeRenderHookClientSide(pageContext) {
111
119
  const hook = getHook(pageContext, 'onBeforeRender');
112
120
  if (!hook) {
121
+ // No hook defined or hook's env.client is false
113
122
  const pageContextFromOnBeforeRender = {
114
123
  _hasPageContextFromClient: false
115
124
  };
@@ -153,7 +162,9 @@ async function onBeforeRenderServerOnlyExists(pageContext) {
153
162
  if (pageContext._pageConfigs.length > 0) {
154
163
  // V1
155
164
  const pageConfig = getPageConfig(pageContext._pageId, pageContext._pageConfigs);
156
- return getConfigValue(pageConfig, 'onBeforeRenderEnv')?.value === 'server-only';
165
+ const onBeforeRenderEnv = getConfigValue(pageConfig, 'onBeforeRenderEnv')?.value ?? {};
166
+ assert(isObject(onBeforeRenderEnv));
167
+ return !!onBeforeRenderEnv.server && !onBeforeRenderEnv.client;
157
168
  }
158
169
  else {
159
170
  // TODO/v1-release: remove
@@ -162,14 +173,17 @@ async function onBeforeRenderServerOnlyExists(pageContext) {
162
173
  return hasOnBeforeRenderServerSideOnlyHook;
163
174
  }
164
175
  }
165
- async function onBeforeRenderClientOnlyExists(pageContext) {
176
+ function onBeforeRenderClientOnlyExists(pageContext) {
166
177
  if (pageContext._pageConfigs.length > 0) {
167
178
  // V1
168
179
  const pageConfig = getPageConfig(pageContext._pageId, pageContext._pageConfigs);
169
- return getConfigValue(pageConfig, 'onBeforeRenderEnv')?.value === 'client-only';
180
+ const onBeforeRenderEnv = getConfigValue(pageConfig, 'onBeforeRenderEnv')?.value ?? {};
181
+ assert(isObject(onBeforeRenderEnv));
182
+ return !!onBeforeRenderEnv.client && !onBeforeRenderEnv.server;
170
183
  }
171
184
  else {
172
185
  // TODO/v1-release: remove
186
+ // Client-only onBeforeRender() hooks were never supported for the V0.4 design
173
187
  return false;
174
188
  }
175
189
  }
@@ -1,5 +1,6 @@
1
1
  export { navigate, reload } from './navigate.js';
2
2
  export { prefetch } from './prefetch.js';
3
+ export { PROJECT_VERSION } from './utils.js';
3
4
  import type { PageContextBuiltInClientWithClientRouting } from '../../shared/types.js';
4
5
  /** @deprecated
5
6
  * Replace:
@@ -5,3 +5,4 @@
5
5
  // Use package.json#exports to make the imports isomorphic.
6
6
  export { navigate, reload } from './navigate.js';
7
7
  export { prefetch } from './prefetch.js';
8
+ export { PROJECT_VERSION } from './utils.js';
@@ -14,8 +14,8 @@ function onBrowserHistoryNavigation() {
14
14
  // - By user clicking on a hash link `<a href="#some-hash" />`
15
15
  // - The popstate event is *only* triggered if `href` starts with '#' (even if `href` is '/#some-hash' while the current URL's pathname is '/' then the popstate still isn't triggered)
16
16
  // - By JavaScript: `location.hash = 'some-hash'`
17
- // - The `event` of `window.addEventListener('popstate', (event) => /*...*/)` is useless: the History API doesn't provide the previous state (the popped state), see https://stackoverflow.com/questions/48055323/is-history-state-always-the-same-as-popstate-event-state
18
- window.addEventListener('popstate', () => {
17
+ // - The `event` argument of `window.addEventListener('popstate', (event) => /*...*/)` is useless: the History API doesn't provide the previous state (the popped state), see https://stackoverflow.com/questions/48055323/is-history-state-always-the-same-as-popstate-event-state
18
+ window.addEventListener('popstate', (ev) => {
19
19
  const currentState = getState();
20
20
  const scrollTarget = currentState.historyState.scrollPosition || 'scroll-to-top-or-hash';
21
21
  const isUserLandPushStateNavigation = currentState.historyState.triggedBy === 'user';
@@ -4,7 +4,7 @@ export { getPageContextSerializedInHtml };
4
4
  function getPageContextSerializedInHtml() {
5
5
  const id = 'vike_pageContext';
6
6
  const elem = document.getElementById(id);
7
- assertUsage(elem, `The element #${id} (which vike automatically injects into the HTML) is missing from the DOM. This may happen if your HTML is malformed. Make sure your HTML isn't malformed, and make sure you don't remove #${id} from the HTML nor from the DOM.`);
7
+ assertUsage(elem, `The element #${id} (which Vike automatically injects into the HTML) is missing from the DOM. This may happen if your HTML is malformed. Make sure your HTML isn't malformed, and make sure you don't remove #${id} from the HTML nor from the DOM.`);
8
8
  const pageContextJson = elem.textContent;
9
9
  assert(pageContextJson);
10
10
  const pageContextSerializedInHtml = parse(pageContextJson);
@@ -2,5 +2,6 @@ export default plugin;
2
2
  export { plugin };
3
3
  export { plugin as ssr };
4
4
  export type { ConfigVikeUserProvided as UserConfig };
5
+ export { PROJECT_VERSION as version } from './utils.js';
5
6
  import type { ConfigVikeUserProvided } from '../../shared/ConfigVike.js';
6
7
  declare function plugin(vikeConfig?: ConfigVikeUserProvided): any;
@@ -2,6 +2,7 @@ export default plugin;
2
2
  export { plugin };
3
3
  // TODO/v1-release: remove
4
4
  export { plugin as ssr };
5
+ export { PROJECT_VERSION as version } from './utils.js';
5
6
  import { assertUsage, markEnvAsVite } from './utils.js';
6
7
  import { buildConfig } from './plugins/buildConfig.js';
7
8
  import { previewConfig } from './plugins/previewConfig.js';
@@ -2,7 +2,7 @@ export { determineOptimizeDeps };
2
2
  import { findPageFiles } from '../../shared/findPageFiles.js';
3
3
  import { assert, getFilePathAbsolute, isNotNullish, isNpmPackageImport, unique } from '../../utils.js';
4
4
  import { getVikeConfig } from '../importUserCode/v1-design/getVikeConfig.js';
5
- import { getConfigValueSourcesRelevant } from '../../shared/getConfigValueSourcesRelevant.js';
5
+ import { getConfigValueSourcesNotOverriden } from '../../shared/getConfigValueSourcesNotOverriden.js';
6
6
  import { analyzeClientEntries } from '../buildConfig.js';
7
7
  import { virtualFileIdImportUserCodeClientCR, virtualFileIdImportUserCodeClientSR } from '../../../shared/virtual-files/virtualFileImportUserCode.js';
8
8
  async function determineOptimizeDeps(config, configVike, isDev) {
@@ -30,12 +30,11 @@ async function getPageDeps(config, pageConfigs, isDev) {
30
30
  // V1 design
31
31
  {
32
32
  pageConfigs.forEach((pageConfig) => {
33
- const configValueSourcesRelevant = getConfigValueSourcesRelevant(pageConfig);
34
- configValueSourcesRelevant.forEach((configValueSource) => {
33
+ getConfigValueSourcesNotOverriden(pageConfig).forEach((configValueSource) => {
35
34
  if (!configValueSource.valueIsImportedAtRuntime)
36
35
  return;
37
36
  const { definedAt, configEnv } = configValueSource;
38
- if (configEnv !== 'client-only' && configEnv !== 'server-and-client')
37
+ if (!configEnv.client)
39
38
  return;
40
39
  if (definedAt.filePathRelativeToUserRootDir !== null) {
41
40
  const { filePathAbsoluteFilesystem } = definedAt;
@@ -0,0 +1,5 @@
1
+ export { getConfigValuesSerialized };
2
+ export { assertConfigValueIsSerializable };
3
+ import type { ConfigEnvInternal, ConfigValueSource, DefinedAt, PageConfigBuildTime } from '../../../../../shared/page-configs/PageConfig.js';
4
+ declare function getConfigValuesSerialized(pageConfig: PageConfigBuildTime, isEnvMatch: (configEnv: ConfigEnvInternal, configValueSource?: ConfigValueSource) => boolean): string;
5
+ declare function assertConfigValueIsSerializable(value: unknown, configName: string, definedAt: DefinedAt): void;
@@ -0,0 +1,70 @@
1
+ export { getConfigValuesSerialized };
2
+ export { assertConfigValueIsSerializable };
3
+ import { assert, assertUsage, getPropAccessNotation } from '../../../utils.js';
4
+ import { isJsonSerializerError, stringify } from '@brillout/json-serializer/stringify';
5
+ import pc from '@brillout/picocolors';
6
+ import { getConfigValueFilePathToShowToUser } from '../../../../../shared/page-configs/helpers.js';
7
+ import { serializeConfigValue } from '../../../../../shared/page-configs/serialize/serializeConfigValue.js';
8
+ import { getConfigValueSourcesNotOverriden } from '../../../shared/getConfigValueSourcesNotOverriden.js';
9
+ function getConfigValuesSerialized(pageConfig, isEnvMatch) {
10
+ const lines = [];
11
+ Object.entries(pageConfig.configValuesComputed).forEach(([configName, configValuesComputed]) => {
12
+ const { value, configEnv } = configValuesComputed;
13
+ if (!isEnvMatch(configEnv))
14
+ return;
15
+ // configValeSources has higher precedence
16
+ if (pageConfig.configValueSources[configName])
17
+ return;
18
+ const configValue = pageConfig.configValues[configName];
19
+ assert(configValue);
20
+ const { definedAt } = configValue;
21
+ const valueSerialized = getConfigValueSerialized(value, configName, definedAt);
22
+ serializeConfigValue(lines, configName, { definedAt, valueSerialized });
23
+ });
24
+ getConfigValueSourcesNotOverriden(pageConfig).forEach((configValueSource) => {
25
+ const { configName, configEnv } = configValueSource;
26
+ const configValue = pageConfig.configValues[configName];
27
+ if (!configValue)
28
+ return;
29
+ if (!isEnvMatch(configEnv, configValueSource)) {
30
+ return;
31
+ }
32
+ const { value, definedAt } = configValue;
33
+ const valueSerialized = getConfigValueSerialized(value, configName, definedAt);
34
+ serializeConfigValue(lines, configName, { definedAt, valueSerialized });
35
+ });
36
+ const code = lines.join('\n');
37
+ return code;
38
+ }
39
+ function assertConfigValueIsSerializable(value, configName, definedAt) {
40
+ // Contains asserts
41
+ getConfigValueSerialized(value, configName, definedAt);
42
+ }
43
+ function getConfigValueSerialized(value, configName, definedAt) {
44
+ const valueName = `config${getPropAccessNotation(configName)}`;
45
+ let configValueSerialized;
46
+ try {
47
+ configValueSerialized = stringify(value, { valueName, forbidReactElements: true });
48
+ }
49
+ catch (err) {
50
+ let serializationErrMsg = '';
51
+ 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';
59
+ }
60
+ const configValueFilePathToShowToUser = getConfigValueFilePathToShowToUser({ definedAt });
61
+ assert(configValueFilePathToShowToUser);
62
+ 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.`
66
+ ].join(' '));
67
+ }
68
+ configValueSerialized = JSON.stringify(configValueSerialized);
69
+ return configValueSerialized;
70
+ }
@@ -1,98 +1,119 @@
1
1
  export { configDefinitionsBuiltIn };
2
2
  export { configDefinitionsBuiltInGlobal };
3
- import { getConfigEnv, isConfigSet } from '../helpers.js';
3
+ import { assert } from '../../../../utils.js';
4
4
  const configDefinitionsBuiltIn = {
5
5
  onRenderHtml: {
6
- env: 'server-only'
6
+ env: { server: true }
7
7
  },
8
8
  onRenderClient: {
9
- env: 'client-only'
9
+ env: { client: true }
10
10
  },
11
11
  onHydrationEnd: {
12
- env: 'client-only'
12
+ env: { client: true }
13
13
  },
14
14
  onPageTransitionStart: {
15
- env: 'client-only'
15
+ env: { client: true }
16
16
  },
17
17
  onPageTransitionEnd: {
18
- env: 'client-only'
18
+ env: { client: true }
19
19
  },
20
20
  onBeforeRender: {
21
- env: 'server-only'
21
+ env: { server: true }
22
22
  },
23
23
  onBeforePrerenderStart: {
24
- env: 'server-only'
24
+ env: { server: true }
25
25
  },
26
26
  Page: {
27
- env: 'server-and-client'
27
+ env: { server: true, client: true }
28
28
  },
29
29
  passToClient: {
30
- env: 'server-only',
30
+ env: { server: true, config: true },
31
31
  cumulative: true
32
32
  },
33
33
  route: {
34
- env: '_routing-eager'
34
+ env: { server: true, client: 'if-client-routing', eager: true }
35
35
  },
36
36
  guard: {
37
- env: '_routing-lazy'
37
+ env: { server: true, client: 'if-client-routing' }
38
38
  },
39
39
  iKnowThePerformanceRisksOfAsyncRouteFunctions: {
40
- env: '_routing-eager'
40
+ env: { server: true, client: 'if-client-routing', eager: true }
41
41
  },
42
42
  filesystemRoutingRoot: {
43
- env: 'config-only'
43
+ env: { config: true }
44
44
  },
45
45
  client: {
46
46
  // The value of the client config is merely the file path to the client entry file, which is only needed on the sever-side
47
- env: 'server-only',
47
+ env: { server: true },
48
48
  _valueIsFilePath: true
49
49
  },
50
50
  clientRouting: {
51
- // We could make it 'server-only' (we don't yet because of some legacy V0.4 design code)
52
- env: 'server-and-client'
51
+ // We could make it { client: false } but we don't yet because of some legacy V0.4 design code
52
+ env: { server: true, client: true, config: true, eager: true }
53
53
  },
54
54
  prerender: {
55
- env: 'config-only'
55
+ env: { config: true }
56
56
  },
57
57
  hydrationCanBeAborted: {
58
- env: 'client-only'
58
+ env: { client: true }
59
59
  },
60
60
  prefetchStaticAssets: {
61
- env: 'client-only'
61
+ env: { client: true }
62
62
  },
63
63
  extends: {
64
- env: 'config-only'
64
+ env: { config: true }
65
65
  },
66
66
  meta: {
67
- env: 'config-only'
67
+ env: { config: true }
68
68
  },
69
69
  isClientSideRenderable: {
70
- env: 'server-and-client',
70
+ env: { server: true, client: true, eager: true },
71
71
  _computed: (configValueSources) => isConfigSet(configValueSources, 'onRenderClient') &&
72
72
  isConfigSet(configValueSources, 'Page') &&
73
- getConfigEnv(configValueSources, 'Page') !== 'server-only'
73
+ !!getConfigEnv(configValueSources, 'Page')?.client
74
74
  },
75
75
  onBeforeRenderEnv: {
76
- env: 'client-only',
76
+ env: { client: true },
77
77
  _computed: (configValueSources) => !isConfigSet(configValueSources, 'onBeforeRender') ? null : getConfigEnv(configValueSources, 'onBeforeRender')
78
78
  }
79
79
  };
80
80
  const configDefinitionsBuiltInGlobal = {
81
81
  onPrerenderStart: {
82
- env: 'server-only'
82
+ env: { server: true }
83
83
  },
84
84
  onBeforeRoute: {
85
- env: '_routing-eager'
85
+ env: { server: true, client: 'if-client-routing', eager: true }
86
86
  },
87
87
  prerender: {
88
- env: 'config-only'
89
- },
90
- extensions: { env: 'config-only' },
91
- disableAutoFullBuild: { env: 'config-only' },
92
- includeAssetsImportedByServer: { env: 'config-only' },
93
- baseAssets: { env: 'config-only' },
94
- baseServer: { env: 'config-only' },
95
- redirects: { env: 'server-only' },
96
- trailingSlash: { env: 'server-only' },
97
- disableUrlNormalization: { env: 'server-only' }
88
+ env: { config: true }
89
+ },
90
+ extensions: { env: { config: true } },
91
+ disableAutoFullBuild: { env: { config: true } },
92
+ includeAssetsImportedByServer: { env: { config: true } },
93
+ baseAssets: { env: { config: true } },
94
+ baseServer: { env: { config: true } },
95
+ redirects: { env: { server: true } },
96
+ trailingSlash: { env: { server: true } },
97
+ disableUrlNormalization: { env: { server: true } }
98
98
  };
99
+ function getConfigEnv(configValueSources, configName) {
100
+ const configValueSource = getConfigValueSource(configValueSources, configName);
101
+ if (!configValueSource)
102
+ return null;
103
+ return configValueSource.configEnv;
104
+ }
105
+ function isConfigSet(configValueSources, configName) {
106
+ const configValueSource = getConfigValueSource(configValueSources, configName);
107
+ // Enable users to suppress global config values by overriding the config's value to null
108
+ if (configValueSource?.value === null)
109
+ return false;
110
+ return !!configValueSource;
111
+ }
112
+ function getConfigValueSource(configValueSources, configName) {
113
+ const sources = configValueSources[configName];
114
+ if (!sources)
115
+ return null;
116
+ const configValueSource = sources[0];
117
+ assert(configValueSource);
118
+ return configValueSource;
119
+ }
@@ -0,0 +1,5 @@
1
+ export { crawlPlusFiles };
2
+ declare function crawlPlusFiles(userRootDir: string, outDirAbsoluteFilesystem: string, isDev: boolean): Promise<{
3
+ filePathRelativeToUserRootDir: string;
4
+ filePathAbsoluteFilesystem: string;
5
+ }[]>;
@@ -0,0 +1,98 @@
1
+ export { crawlPlusFiles };
2
+ import { assertPosixPath, assert, toPosixPath, assertWarning, scriptFileExtensionList, scriptFileExtensions } from '../../../../utils.js';
3
+ import path from 'path';
4
+ import glob from 'fast-glob';
5
+ import { exec } from 'child_process';
6
+ import { promisify } from 'util';
7
+ const execA = promisify(exec);
8
+ async function crawlPlusFiles(userRootDir, outDirAbsoluteFilesystem, isDev) {
9
+ assertPosixPath(userRootDir);
10
+ assertPosixPath(outDirAbsoluteFilesystem);
11
+ assert(outDirAbsoluteFilesystem.startsWith(userRootDir));
12
+ const outDir = path.posix.relative(userRootDir, outDirAbsoluteFilesystem);
13
+ assert(!outDir.startsWith('.'));
14
+ const timeBase = new Date().getTime();
15
+ let files = [];
16
+ const res = await gitLsFiles(userRootDir, outDir);
17
+ if (res &&
18
+ // 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)
19
+ res.length > 0) {
20
+ files = res;
21
+ }
22
+ else {
23
+ files = await fastGlob(userRootDir, outDir);
24
+ }
25
+ {
26
+ const time = new Date().getTime() - timeBase;
27
+ if (isDev) {
28
+ // 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
29
+ assertWarning(time < 2 * 1000, `Crawling your user files took an unexpected long time (${time}ms). Create a new issue on Vike's GitHub.`, {
30
+ onlyOnce: 'slow-page-files-search'
31
+ });
32
+ }
33
+ }
34
+ const plusFiles = files.map((p) => {
35
+ p = toPosixPath(p);
36
+ assert(!p.startsWith(userRootDir));
37
+ const filePathRelativeToUserRootDir = path.posix.join('/', p);
38
+ const filePathAbsoluteFilesystem = path.posix.join(userRootDir, p);
39
+ return {
40
+ filePathRelativeToUserRootDir,
41
+ filePathAbsoluteFilesystem
42
+ };
43
+ });
44
+ return plusFiles;
45
+ }
46
+ // Same as fastGlob() but using `$ git ls-files`
47
+ async function gitLsFiles(userRootDir, outDir) {
48
+ const cmd = [
49
+ 'git ls-files',
50
+ ...scriptFileExtensionList.map((ext) => `"**/+*.${ext}"`),
51
+ ...getIgnorePatterns(outDir).map((pattern) => `--exclude="${pattern}"`),
52
+ // --others lists untracked files only (but using .gitignore because --exclude-standard)
53
+ // --cached adds the tracked files to the output
54
+ '--others --cached --exclude-standard'
55
+ ].join(' ');
56
+ let stdout;
57
+ try {
58
+ const res = await execA(cmd, { cwd: userRootDir });
59
+ stdout = res.stdout;
60
+ }
61
+ catch (err) {
62
+ if (err.message.includes('not a git repository'))
63
+ return null;
64
+ throw err;
65
+ }
66
+ let files = stdout.split('\n').filter(Boolean);
67
+ assert(!outDir.startsWith('/'));
68
+ files = files.filter(
69
+ // 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.)
70
+ (file) => getIgnoreFilter(file, outDir));
71
+ return files;
72
+ }
73
+ // Same as gitLsFiles() but using fast-glob
74
+ async function fastGlob(userRootDir, outDir) {
75
+ const files = await glob(`**/+*.${scriptFileExtensions}`, {
76
+ ignore: getIgnorePatterns(outDir),
77
+ cwd: userRootDir,
78
+ dot: false
79
+ });
80
+ return files;
81
+ }
82
+ // Same as getIgnoreFilter() but as glob pattern
83
+ function getIgnorePatterns(outDir) {
84
+ return [
85
+ '**/node_modules/**',
86
+ `${outDir}/**`,
87
+ // Allow:
88
+ // ```
89
+ // +Page.js
90
+ // +Page.telefunc.js
91
+ // ```
92
+ '**/*.telefunc.*'
93
+ ];
94
+ }
95
+ // Same as getIgnorePatterns() but for Array.filter()
96
+ function getIgnoreFilter(file, outDir) {
97
+ return !file.includes('node_modules/') && !file.includes('.telefunc.') && !file.startsWith(`${outDir}/`);
98
+ }