vike 0.4.220-commit-9a798ce → 0.4.220-commit-af5c91f

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 (124) hide show
  1. package/dist/cjs/node/api/utils.js +1 -1
  2. package/dist/cjs/node/plugin/index.js +1 -1
  3. package/dist/cjs/node/plugin/onLoad.js +1 -1
  4. package/dist/cjs/node/plugin/plugins/buildConfig/fixServerAssets.js +5 -3
  5. package/dist/cjs/node/plugin/plugins/buildConfig.js +7 -5
  6. package/dist/cjs/node/plugin/plugins/buildEntry/index.js +2 -1
  7. package/dist/cjs/node/plugin/plugins/commonConfig.js +1 -2
  8. package/dist/cjs/node/plugin/plugins/extractAssetsPlugin.js +3 -2
  9. package/dist/cjs/node/plugin/plugins/extractExportNamesPlugin.js +2 -1
  10. package/dist/cjs/node/plugin/plugins/importUserCode/getVirtualFileImportUserCode.js +10 -8
  11. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/assertExtensions.js +8 -4
  12. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/loadFileAtConfigTime.js +39 -22
  13. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/resolvePointerImport.js +9 -64
  14. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/transpileAndExecuteFile.js +11 -5
  15. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +319 -350
  16. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigValuesAll.js +2 -1
  17. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigs.js +7 -6
  18. package/dist/cjs/node/plugin/plugins/packageJsonFile.js +2 -2
  19. package/dist/cjs/node/plugin/plugins/previewConfig.js +4 -3
  20. package/dist/cjs/node/plugin/plugins/setGlobalContext.js +2 -1
  21. package/dist/cjs/node/plugin/shared/findPageFiles.js +2 -1
  22. package/dist/cjs/node/plugin/{getOutDirs.js → shared/getOutDirs.js} +24 -27
  23. package/dist/cjs/node/plugin/{resolveClientEntriesDev.js → shared/resolveClientEntriesDev.js} +5 -8
  24. package/dist/cjs/{utils → node/plugin/shared}/viteIsSSR.js +2 -2
  25. package/dist/cjs/node/plugin/utils.js +0 -1
  26. package/dist/cjs/node/prerender/context.js +8 -3
  27. package/dist/cjs/node/prerender/resolvePrerenderConfig.js +26 -5
  28. package/dist/cjs/node/prerender/runPrerender.js +6 -11
  29. package/dist/cjs/node/prerender/utils.js +1 -2
  30. package/dist/cjs/node/runtime/html/injectAssets/getHtmlTags.js +9 -4
  31. package/dist/cjs/node/runtime/renderPage/getEarlyHints.js +2 -27
  32. package/dist/cjs/node/runtime/renderPage/isFontFallback.js +29 -0
  33. package/dist/cjs/node/runtime/utils.js +1 -3
  34. package/dist/cjs/shared/getPageContextUrlComputed.js +6 -1
  35. package/dist/cjs/shared/getPageFiles/fileTypes.js +0 -1
  36. package/dist/cjs/shared/getPageFiles/getAllPageIdFiles.js +0 -3
  37. package/dist/cjs/shared/getPageFiles/getPageFileObject.js +0 -5
  38. package/dist/cjs/shared/page-configs/serialize/serializeConfigValues.js +69 -18
  39. package/dist/cjs/shared/utils.js +0 -1
  40. package/dist/cjs/utils/PROJECT_VERSION.js +1 -1
  41. package/dist/cjs/utils/findFile.js +3 -3
  42. package/dist/cjs/utils/isDev.js +2 -5
  43. package/dist/cjs/utils/isFilePathAbsoluteFilesystem.js +2 -2
  44. package/dist/cjs/utils/path.js +48 -0
  45. package/dist/cjs/utils/requireResolve.js +3 -3
  46. package/dist/esm/node/api/utils.d.ts +1 -1
  47. package/dist/esm/node/api/utils.js +1 -1
  48. package/dist/esm/node/plugin/index.js +1 -1
  49. package/dist/esm/node/plugin/onLoad.js +1 -1
  50. package/dist/esm/node/plugin/plugins/buildConfig/fixServerAssets.js +3 -1
  51. package/dist/esm/node/plugin/plugins/buildConfig.js +3 -1
  52. package/dist/esm/node/plugin/plugins/buildEntry/index.js +2 -1
  53. package/dist/esm/node/plugin/plugins/commonConfig.js +2 -3
  54. package/dist/esm/node/plugin/plugins/extractAssetsPlugin.js +2 -1
  55. package/dist/esm/node/plugin/plugins/extractExportNamesPlugin.js +2 -1
  56. package/dist/esm/node/plugin/plugins/importUserCode/getVirtualFileImportUserCode.js +9 -7
  57. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/assertExtensions.js +9 -5
  58. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/loadFileAtConfigTime.d.ts +15 -9
  59. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/loadFileAtConfigTime.js +40 -23
  60. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/resolvePointerImport.d.ts +8 -18
  61. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/resolvePointerImport.js +10 -65
  62. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/transpileAndExecuteFile.d.ts +6 -2
  63. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/transpileAndExecuteFile.js +12 -6
  64. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.d.ts +25 -8
  65. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +322 -353
  66. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigValuesAll.js +2 -1
  67. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigs.js +7 -6
  68. package/dist/esm/node/plugin/plugins/packageJsonFile.js +1 -1
  69. package/dist/esm/node/plugin/plugins/previewConfig.js +2 -1
  70. package/dist/esm/node/plugin/plugins/setGlobalContext.js +2 -1
  71. package/dist/esm/node/plugin/shared/findPageFiles.js +2 -1
  72. package/dist/esm/node/plugin/{getOutDirs.js → shared/getOutDirs.js} +2 -5
  73. package/dist/esm/node/plugin/{resolveClientEntriesDev.js → shared/resolveClientEntriesDev.js} +5 -8
  74. package/dist/esm/{utils → node/plugin/shared}/viteIsSSR.js +2 -2
  75. package/dist/esm/node/plugin/utils.d.ts +0 -1
  76. package/dist/esm/node/plugin/utils.js +0 -1
  77. package/dist/esm/node/prerender/context.d.ts +2 -0
  78. package/dist/esm/node/prerender/context.js +8 -3
  79. package/dist/esm/node/prerender/resolvePrerenderConfig.d.ts +8 -1
  80. package/dist/esm/node/prerender/resolvePrerenderConfig.js +26 -5
  81. package/dist/esm/node/prerender/runPrerender.js +7 -12
  82. package/dist/esm/node/prerender/utils.d.ts +1 -2
  83. package/dist/esm/node/prerender/utils.js +1 -2
  84. package/dist/esm/node/runtime/html/injectAssets/getHtmlTags.js +9 -4
  85. package/dist/esm/node/runtime/renderPage/getEarlyHints.js +1 -26
  86. package/dist/esm/node/runtime/renderPage/getPageAssets.d.ts +1 -1
  87. package/dist/esm/node/runtime/renderPage/isFontFallback.d.ts +3 -0
  88. package/dist/esm/node/runtime/renderPage/isFontFallback.js +27 -0
  89. package/dist/esm/node/runtime/utils.d.ts +1 -3
  90. package/dist/esm/node/runtime/utils.js +1 -3
  91. package/dist/esm/shared/getPageContextUrlComputed.js +6 -1
  92. package/dist/esm/shared/getPageFiles/fileTypes.js +1 -2
  93. package/dist/esm/shared/getPageFiles/getAllPageIdFiles.js +0 -3
  94. package/dist/esm/shared/getPageFiles/getPageFileObject.js +0 -5
  95. package/dist/esm/shared/page-configs/PageConfig.d.ts +0 -1
  96. package/dist/esm/shared/page-configs/serialize/serializeConfigValues.d.ts +7 -1
  97. package/dist/esm/shared/page-configs/serialize/serializeConfigValues.js +70 -19
  98. package/dist/esm/shared/utils.d.ts +0 -1
  99. package/dist/esm/shared/utils.js +0 -1
  100. package/dist/esm/utils/PROJECT_VERSION.d.ts +1 -1
  101. package/dist/esm/utils/PROJECT_VERSION.js +1 -1
  102. package/dist/esm/utils/findFile.js +1 -1
  103. package/dist/esm/utils/isDev.js +3 -6
  104. package/dist/esm/utils/isFilePathAbsoluteFilesystem.js +1 -1
  105. package/dist/esm/utils/path.d.ts +14 -0
  106. package/dist/esm/utils/path.js +46 -0
  107. package/dist/esm/utils/projectInfo.d.ts +1 -1
  108. package/dist/esm/utils/requireResolve.js +1 -1
  109. package/package.json +1 -1
  110. package/dist/cjs/node/plugin/plugins/importUserCode/addImportStatement.js +0 -29
  111. package/dist/cjs/shared/assertPageFilePath.js +0 -11
  112. package/dist/cjs/utils/path-shim.js +0 -19
  113. package/dist/cjs/utils/toPosixPath.js +0 -18
  114. package/dist/esm/node/plugin/plugins/importUserCode/addImportStatement.d.ts +0 -14
  115. package/dist/esm/node/plugin/plugins/importUserCode/addImportStatement.js +0 -27
  116. package/dist/esm/shared/assertPageFilePath.d.ts +0 -2
  117. package/dist/esm/shared/assertPageFilePath.js +0 -9
  118. package/dist/esm/utils/path-shim.d.ts +0 -2
  119. package/dist/esm/utils/path-shim.js +0 -17
  120. package/dist/esm/utils/toPosixPath.d.ts +0 -4
  121. package/dist/esm/utils/toPosixPath.js +0 -16
  122. /package/dist/esm/node/plugin/{getOutDirs.d.ts → shared/getOutDirs.d.ts} +0 -0
  123. /package/dist/esm/node/plugin/{resolveClientEntriesDev.d.ts → shared/resolveClientEntriesDev.d.ts} +0 -0
  124. /package/dist/esm/{utils → node/plugin/shared}/viteIsSSR.d.ts +0 -0
@@ -4,8 +4,9 @@ export { reloadVikeConfig };
4
4
  export { vikeConfigDependencies };
5
5
  export { isVikeConfigFile };
6
6
  export { isV1Design };
7
- export { getConfigValueInterfaceFile };
8
- import { assertPosixPath, assert, isObject, assertUsage, assertWarning, objectEntries, hasProp, includes, assertIsNotProductionRuntime, getMostSimilar, joinEnglish, lowerFirst, assertKeys, objectKeys, objectFromEntries, makeFirst, isNpmPackageImport, reverse } from '../../../utils.js';
7
+ export { getConfVal };
8
+ export { getConfigDefinitionOptional };
9
+ import { assertPosixPath, assert, isObject, assertUsage, assertWarning, objectEntries, hasProp, includes, assertIsNotProductionRuntime, getMostSimilar, joinEnglish, lowerFirst, assertKeys, objectKeys, objectFromEntries, makeFirst, isNpmPackageImport, reverse, unique, isCallable } from '../../../utils.js';
9
10
  import path from 'path';
10
11
  import { configDefinitionsBuiltInAll } from './getVikeConfig/configDefinitionsBuiltIn.js';
11
12
  import { getLocationId, getFilesystemRouteString, getFilesystemRouteDefinedBy, isInherited, sortAfterInheritanceOrder, isGlobalLocation, applyFilesystemRoutingRootEffect } from './getVikeConfig/filesystemRouting.js';
@@ -18,15 +19,13 @@ import pc from '@brillout/picocolors';
18
19
  import { getConfigDefinedAt } from '../../../../../shared/page-configs/getConfigDefinedAt.js';
19
20
  import { crawlPlusFiles } from './getVikeConfig/crawlPlusFiles.js';
20
21
  import { getConfigFileExport } from './getConfigFileExport.js';
21
- import { loadConfigFile, loadImportedFile, loadValueFile } from './getVikeConfig/loadFileAtConfigTime.js';
22
- import { clearFilesEnvMap, resolveConfigEnvWithFileName, resolvePointerImportOfConfig } from './getVikeConfig/resolvePointerImport.js';
22
+ import { loadConfigFile, loadPointerImport, loadValueFile } from './getVikeConfig/loadFileAtConfigTime.js';
23
+ import { resolvePointerImport } from './getVikeConfig/resolvePointerImport.js';
23
24
  import { getFilePathResolved } from '../../../shared/getFilePath.js';
24
25
  import { getConfigValueBuildTime } from '../../../../../shared/page-configs/getConfigValueBuildTime.js';
25
26
  import { assertExtensionsRequire, assertExtensionsConventions } from './assertExtensions.js';
26
27
  import { getPageConfigUserFriendlyNew } from '../../../../../shared/page-configs/getPageConfigUserFriendly.js';
27
28
  import { getConfigValuesBase } from '../../../../../shared/page-configs/serialize/serializeConfigValues.js';
28
- const configDefinitionsBuiltIn = getConfigDefinitionsBuiltIn();
29
- const configDefinitionsBuiltInGlobal = getConfigDefinitionsBuiltInGlobal();
30
29
  assertIsNotProductionRuntime();
31
30
  let restartVite = false;
32
31
  let wasConfigInvalid = null;
@@ -37,7 +36,6 @@ function reloadVikeConfig(config) {
37
36
  const vikeVitePluginOptions = config._vikeVitePluginOptions;
38
37
  assert(vikeVitePluginOptions);
39
38
  vikeConfigDependencies.clear();
40
- clearFilesEnvMap();
41
39
  vikeConfigPromise = loadVikeConfig_withErrorHandling(userRootDir, true, vikeVitePluginOptions);
42
40
  handleReloadSideEffects();
43
41
  }
@@ -96,7 +94,7 @@ async function isV1Design(config) {
96
94
  const isV1Design = pageConfigs.length > 0;
97
95
  return isV1Design;
98
96
  }
99
- async function loadInterfaceFiles(userRootDir) {
97
+ async function loadInterfaceFiles(userRootDir, esbuildCache) {
100
98
  const plusFiles = await findPlusFiles(userRootDir, null);
101
99
  const configFiles = [];
102
100
  const valueFiles = [];
@@ -114,10 +112,10 @@ async function loadInterfaceFiles(userRootDir) {
114
112
  ...configFiles.map(async (filePath) => {
115
113
  const { filePathAbsoluteUserRootDir } = filePath;
116
114
  assert(filePathAbsoluteUserRootDir);
117
- const { configFile, extendsConfigs } = await loadConfigFile(filePath, userRootDir, [], false);
115
+ const { configFile, extendsConfigs } = await loadConfigFile(filePath, userRootDir, [], false, esbuildCache);
118
116
  assert(filePath.filePathAbsoluteUserRootDir);
119
117
  const locationId = getLocationId(filePathAbsoluteUserRootDir);
120
- const interfaceFile = getInterfaceFileFromConfigFile(configFile, false, locationId);
118
+ const interfaceFile = getInterfaceFileFromConfigFile(configFile, false, locationId, userRootDir);
121
119
  interfaceFilesAll[locationId] = interfaceFilesAll[locationId] ?? [];
122
120
  interfaceFilesAll[locationId].push(interfaceFile);
123
121
  extendsConfigs.forEach((extendsConfig) => {
@@ -137,7 +135,7 @@ async function loadInterfaceFiles(userRootDir) {
137
135
  export default { extends: [vikeReact] }
138
136
  ```
139
137
  */
140
- const interfaceFile = getInterfaceFileFromConfigFile(extendsConfig, true, locationId);
138
+ const interfaceFile = getInterfaceFileFromConfigFile(extendsConfig, true, locationId, userRootDir);
141
139
  assertExtensionsConventions(interfaceFile);
142
140
  interfaceFilesAll[locationId].push(interfaceFile);
143
141
  });
@@ -152,60 +150,50 @@ async function loadInterfaceFiles(userRootDir) {
152
150
  const interfaceFile = {
153
151
  locationId,
154
152
  filePath,
155
- fileExportsByConfigName: {
156
- [configName]: {}
157
- },
158
153
  isConfigFile: false,
159
154
  isValueFile: true,
155
+ isValueFileLoaded: false,
160
156
  configName
161
157
  };
162
- {
163
- // We don't have access to the custom config definitions defined by the user yet.
164
- // - If `configDef` is `undefined` => we load the file +{configName}.js later.
165
- // - We already need to load +meta.js here (to get the custom config definitions defined by the user)
166
- const configDef = getConfigDefinitionOptional(configDefinitionsBuiltIn, configName);
167
- if (configDef && shouldBeLoadableAtBuildTime(configDef)) {
168
- await loadValueFile(interfaceFile, configName, userRootDir);
169
- }
170
- }
171
- {
172
- interfaceFilesAll[locationId] = interfaceFilesAll[locationId] ?? [];
173
- interfaceFilesAll[locationId].push(interfaceFile);
174
- }
158
+ interfaceFilesAll[locationId] = interfaceFilesAll[locationId] ?? [];
159
+ interfaceFilesAll[locationId].push(interfaceFile);
160
+ // We don't have access to the custom config definitions defined by the user yet.
161
+ // - If `configDef` is `undefined` => we load the file +{configName}.js later.
162
+ // - We already need to load +meta.js here (to get the custom config definitions defined by the user)
163
+ await loadValueFile(interfaceFile, configDefinitionsBuiltInAll, userRootDir, esbuildCache);
175
164
  })
176
165
  ]);
177
- assertAllConfigsAreKnown(interfaceFilesAll);
166
+ assertKnownConfigs(interfaceFilesAll);
178
167
  return interfaceFilesAll;
179
168
  }
180
- function getInterfaceFileFromConfigFile(configFile, isConfigExtend, locationId) {
169
+ function getInterfaceFileFromConfigFile(configFile, isConfigExtension, locationId, userRootDir) {
181
170
  const { fileExports, filePath, extendsFilePaths } = configFile;
171
+ const fileExportsByConfigName = {};
172
+ const pointerImportsByConfigName = {};
173
+ const fileExport = getConfigFileExport(fileExports, filePath.filePathToShowToUser);
174
+ Object.entries(fileExport).forEach(([configName, configValue]) => {
175
+ fileExportsByConfigName[configName] = configValue;
176
+ const pointerImport = resolvePointerImport(configValue, configFile.filePath, userRootDir, configName);
177
+ if (pointerImport) {
178
+ pointerImportsByConfigName[configName] = {
179
+ ...pointerImport,
180
+ fileExportValueLoaded: false
181
+ };
182
+ }
183
+ });
182
184
  const interfaceFile = {
183
185
  locationId,
184
186
  filePath,
185
- fileExportsByConfigName: {},
187
+ fileExportsByConfigName,
188
+ pointerImportsByConfigName,
186
189
  isConfigFile: true,
187
190
  isValueFile: false,
188
- isConfigExtend,
191
+ isValueFileLoaded: true,
192
+ isConfigExtension,
189
193
  extendsFilePaths
190
194
  };
191
- const fileExport = getConfigFileExport(fileExports, filePath.filePathToShowToUser);
192
- Object.entries(fileExport).forEach(([configName, configValue]) => {
193
- interfaceFile.fileExportsByConfigName[configName] = { configValue };
194
- });
195
195
  return interfaceFile;
196
196
  }
197
- /** Show error message upon unknown config */
198
- function assertAllConfigsAreKnown(interfaceFilesAll) {
199
- objectEntries(interfaceFilesAll).forEach(([locationId, interfaceFiles]) => {
200
- const interfaceFilesRelevant = getInterfaceFilesRelevant(interfaceFilesAll, locationId);
201
- const configDefinitions = getConfigDefinitions(interfaceFilesRelevant);
202
- interfaceFiles.forEach((interfaceFile) => {
203
- Object.keys(interfaceFile.fileExportsByConfigName).forEach((configName) => {
204
- assertConfigExists(configName, Object.keys(configDefinitions), interfaceFile.filePath.filePathToShowToUser);
205
- });
206
- });
207
- });
208
- }
209
197
  async function loadVikeConfig_withErrorHandling(userRootDir, isDev, vikeVitePluginOptions, doNotRestartViteOnError) {
210
198
  let hasError = false;
211
199
  let ret;
@@ -240,7 +228,6 @@ async function loadVikeConfig_withErrorHandling(userRootDir, isDev, vikeVitePlug
240
228
  pageConfigs: [],
241
229
  pageConfigGlobal: {
242
230
  configDefinitions: {},
243
- interfaceFiles: {},
244
231
  configValueSources: {}
245
232
  },
246
233
  global: getPageConfigUserFriendlyNew({ configValues: {} })
@@ -250,9 +237,10 @@ async function loadVikeConfig_withErrorHandling(userRootDir, isDev, vikeVitePlug
250
237
  }
251
238
  }
252
239
  async function loadVikeConfig(userRootDir, vikeVitePluginOptions) {
253
- const interfaceFilesAll = await loadInterfaceFiles(userRootDir);
254
- const importedFilesLoaded = {};
255
- const { pageConfigGlobal, pageConfigs } = await getPageConfigs(interfaceFilesAll, userRootDir, importedFilesLoaded);
240
+ const esbuildCache = {};
241
+ const interfaceFilesAll = await loadInterfaceFiles(userRootDir, esbuildCache);
242
+ const configDefinitionsResolved = await resolveConfigDefinitions(interfaceFilesAll, userRootDir, esbuildCache);
243
+ const { pageConfigGlobal, pageConfigs } = getPageConfigs(configDefinitionsResolved, interfaceFilesAll, userRootDir);
256
244
  // interop vike(options) in vite.config.js
257
245
  temp_interopVikeVitePlugin(pageConfigGlobal, vikeVitePluginOptions, userRootDir);
258
246
  // global
@@ -260,189 +248,138 @@ async function loadVikeConfig(userRootDir, vikeVitePluginOptions) {
260
248
  const global = getPageConfigUserFriendlyNew({ configValues });
261
249
  return { pageConfigs, pageConfigGlobal, global };
262
250
  }
263
- async function getGlobalConfigs(interfaceFilesAll, userRootDir, importedFilesLoaded) {
264
- /* TODO/now: dedupe
265
- // Validate that global configs live in global interface files
266
- {
267
- const interfaceFilesGlobalPaths: string[] = []
268
- objectEntries(interfaceFilesGlobal).forEach(([locationId, interfaceFiles]) => {
269
- assert(isGlobalLocation(locationId, locationIds))
270
- interfaceFiles.forEach(({ filePath: { filePathAbsoluteUserRootDir } }) => {
271
- if (filePathAbsoluteUserRootDir) {
272
- interfaceFilesGlobalPaths.push(filePathAbsoluteUserRootDir)
273
- }
274
- })
275
- })
276
- const globalPaths = Array.from(new Set(interfaceFilesGlobalPaths.map((p) => path.posix.dirname(p))))
277
- objectEntries(interfaceFilesAll).forEach(([locationId, interfaceFiles]) => {
278
- interfaceFiles.forEach((interfaceFile) => {
279
- Object.keys(interfaceFile.fileExportsByConfigName).forEach((configName) => {
280
- if (!isGlobalLocation(locationId, locationIds) && isGlobalConfig(configName)) {
281
- assertUsage(
282
- false,
283
- [
284
- `${interfaceFile.filePath.filePathToShowToUser} defines the config ${pc.cyan(
285
- configName
286
- )} which is global:`,
287
- globalPaths.length
288
- ? `define ${pc.cyan(configName)} in ${joinEnglish(globalPaths, 'or')} instead`
289
- : `create a global config (e.g. /pages/+config.js) and define ${pc.cyan(configName)} there instead`
290
- ].join(' ')
291
- )
292
- }
293
- })
294
- })
295
- })
296
- }
297
- //*/
298
- }
299
- function temp_interopVikeVitePlugin(pageConfigGlobal, vikeVitePluginOptions, userRootDir) {
300
- assert(isObject(vikeVitePluginOptions));
301
- assertWarning(Object.keys(vikeVitePluginOptions).length === 0, `Define Vike settings in +config.js instead of vite.config.js ${pc.underline('https://vike.dev/migration/settings')}`, { onlyOnce: true });
302
- Object.entries(vikeVitePluginOptions).forEach(([configName, value]) => {
303
- var _a;
304
- assert(includes(objectKeys(configDefinitionsBuiltInGlobal), configName));
305
- const configDef = configDefinitionsBuiltInGlobal[configName];
306
- const sources = ((_a = pageConfigGlobal.configValueSources)[configName] ?? (_a[configName] = []));
307
- sources.push({
308
- value,
309
- configEnv: configDef.env,
310
- definedAtFilePath: {
311
- ...getFilePathResolved({
312
- userRootDir,
313
- filePathAbsoluteUserRootDir: '/vite.config.js'
314
- }),
315
- fileExportPathToShowToUser: null
316
- },
317
- locationId: '/',
318
- interfaceFile: null,
319
- isOverriden: configDef.cumulative ? false : sources.length > 0,
320
- valueIsImportedAtRuntime: false,
321
- valueIsDefinedByPlusFile: false
322
- });
323
- });
251
+ async function resolveConfigDefinitions(interfaceFilesAll, userRootDir, esbuildCache) {
252
+ const configDefinitionsGlobal = getConfigDefinitions(
253
+ // We use `interfaceFilesAll` in order to allow local Vike extensions to create global configs.
254
+ interfaceFilesAll, // TODO/now sort
255
+ (configDef) => !!configDef.global);
256
+ await loadCustomConfigBuildTimeFiles(interfaceFilesAll, configDefinitionsGlobal, userRootDir, esbuildCache);
257
+ const configDefinitionsLocal = {};
258
+ await Promise.all(objectEntries(interfaceFilesAll).map(async ([locationId, interfaceFiles]) => {
259
+ const interfaceFilesRelevant = getInterfaceFilesRelevant(interfaceFilesAll, locationId);
260
+ // configDefinitions = getConfigDefinitions(interfaceFilesRelevant, (configDef) => configDef.global !== true) // TODO/now
261
+ const configDefinitions = getConfigDefinitions(interfaceFilesRelevant);
262
+ await loadCustomConfigBuildTimeFiles(interfaceFiles, configDefinitions, userRootDir, esbuildCache);
263
+ configDefinitionsLocal[locationId] = { configDefinitions, interfaceFiles, interfaceFilesRelevant };
264
+ }));
265
+ const configDefinitionsResolved = {
266
+ configDefinitionsGlobal,
267
+ configDefinitionsLocal
268
+ };
269
+ return configDefinitionsResolved;
324
270
  }
325
- async function getPageConfigs(interfaceFilesAll, userRootDir, importedFilesLoaded) {
326
- const locationIds = objectKeys(interfaceFilesAll);
327
- const interfaceFilesGlobal = objectFromEntries(objectEntries(interfaceFilesAll).filter(([locationId]) => {
328
- return isGlobalLocation(locationId, locationIds);
271
+ // Load value files (with `env.config===true`) of *custom* configs.
272
+ // - The value files of *built-in* configs are already loaded at `loadInterfaceFiles()`.
273
+ async function loadCustomConfigBuildTimeFiles(interfaceFiles, configDefinitions, userRootDir, esbuildCache) {
274
+ const interfaceFileList = Object.values(interfaceFiles).flat(1);
275
+ await Promise.all(interfaceFileList.map(async (interfaceFile) => {
276
+ if (interfaceFile.isValueFile) {
277
+ await loadValueFile(interfaceFile, configDefinitions, userRootDir, esbuildCache);
278
+ }
279
+ else {
280
+ await Promise.all(Object.entries(interfaceFile.pointerImportsByConfigName).map(async ([configName, pointerImport]) => {
281
+ await loadPointerImport(pointerImport, userRootDir, configName, configDefinitions, esbuildCache);
282
+ }));
283
+ }
329
284
  }));
285
+ }
286
+ function getPageConfigs(configDefinitionsResolved, interfaceFilesAll, userRootDir) {
330
287
  const pageConfigGlobal = {
331
- configDefinitions: configDefinitionsBuiltInGlobal,
332
- interfaceFiles: interfaceFilesGlobal,
288
+ configDefinitions: configDefinitionsResolved.configDefinitionsGlobal,
333
289
  configValueSources: {}
334
290
  };
335
- await Promise.all(objectEntries(configDefinitionsBuiltInGlobal).map(async ([configName, configDef]) => {
336
- const sources = await resolveConfigValueSources(configName, configDef, interfaceFilesGlobal, userRootDir, importedFilesLoaded);
337
- const configValueSource = sources[0];
338
- if (!configValueSource)
291
+ objectEntries(configDefinitionsResolved.configDefinitionsGlobal).forEach(([configName, configDef]) => {
292
+ const sources = resolveConfigValueSources(configName, configDef,
293
+ // We use `interfaceFilesAll` in order to allow local Vike extensions to set the value of global configs (e.g. `vite`).
294
+ interfaceFilesAll, // TODO/now check sort order
295
+ userRootDir, true);
296
+ if (sources.length === 0)
339
297
  return;
340
298
  pageConfigGlobal.configValueSources[configName] = sources;
341
- }));
342
- const pageConfigs = [];
343
- await Promise.all(objectEntries(interfaceFilesAll)
344
- .filter(([_locationId, interfaceFiles]) => isDefiningPage(interfaceFiles))
345
- .map(async ([locationId]) => {
346
- const interfaceFilesRelevant = getInterfaceFilesRelevant(interfaceFilesAll, locationId);
347
- const interfaceFilesRelevantList = Object.values(interfaceFilesRelevant).flat(1);
348
- const configDefinitions = getConfigDefinitions(interfaceFilesRelevant);
349
- // Load value files of `env.config===true` custom configs
350
- await Promise.all(interfaceFilesRelevantList.map(async (interfaceFile) => {
351
- if (!interfaceFile.isValueFile)
352
- return;
353
- const { configName } = interfaceFile;
354
- if (isGlobalConfig(configName))
355
- return;
356
- const configDef = getConfigDefinition(configDefinitions, configName, interfaceFile.filePath.filePathToShowToUser);
357
- if (!shouldBeLoadableAtBuildTime(configDef))
358
- return;
359
- const isAlreadyLoaded = interfacefileIsAlreaydLoaded(interfaceFile);
360
- if (isAlreadyLoaded)
361
- return;
362
- // Value files of built-in configs should have already been loaded at loadInterfaceFiles()
363
- assert(!(configName in configDefinitionsBuiltIn));
364
- await loadValueFile(interfaceFile, configName, userRootDir);
365
- }));
299
+ });
300
+ assertPageConfigGlobal(pageConfigGlobal, interfaceFilesAll);
301
+ const pageConfigs = objectEntries(configDefinitionsResolved.configDefinitionsLocal)
302
+ .filter(([_locationId, { interfaceFiles }]) => isDefiningPage(interfaceFiles))
303
+ .map(([locationId, { configDefinitions, interfaceFilesRelevant }]) => {
304
+ const configDefinitionsLocal = configDefinitions;
366
305
  let configValueSources = {};
367
- await Promise.all(objectEntries(configDefinitions)
368
- .filter(([configName]) => !isGlobalConfig(configName))
369
- .map(async ([configName, configDef]) => {
370
- const sources = await resolveConfigValueSources(configName, configDef, interfaceFilesRelevant, userRootDir, importedFilesLoaded);
306
+ objectEntries(configDefinitionsLocal)
307
+ .filter(([_configName, configDef]) => configDef.global !== true)
308
+ .forEach(([configName, configDef]) => {
309
+ const sources = resolveConfigValueSources(configName, configDef, interfaceFilesRelevant, userRootDir, false);
371
310
  if (sources.length === 0)
372
311
  return;
312
+ // assertUsage(!isGlobalConfig(configName, configDefinitionsLocal, sources), 'TODO') // TODO/now
373
313
  configValueSources[configName] = sources;
374
- }));
314
+ });
375
315
  configValueSources = sortConfigValueSources(configValueSources, locationId);
376
316
  const { routeFilesystem, isErrorPage } = determineRouteFilesystem(locationId, configValueSources);
377
- applyEffectsAll(configValueSources, configDefinitions);
378
- const configValuesComputed = getComputed(configValueSources, configDefinitions);
317
+ applyEffectsAll(configValueSources, configDefinitionsLocal);
318
+ const configValuesComputed = getComputed(configValueSources, configDefinitionsLocal);
379
319
  const pageConfig = {
380
320
  pageId: locationId,
381
321
  isErrorPage,
382
322
  routeFilesystem,
383
- configDefinitions,
323
+ configDefinitions: configDefinitionsLocal,
384
324
  interfaceFiles: interfaceFilesRelevant,
385
325
  configValueSources,
386
326
  configValuesComputed
387
327
  };
388
- pageConfigs.push(pageConfig);
389
- }));
390
- assertPageConfigs(pageConfigs, interfaceFilesAll);
328
+ return pageConfig;
329
+ });
330
+ assertPageConfigs(pageConfigs);
391
331
  return { pageConfigs, pageConfigGlobal };
392
332
  }
393
- function assertPageConfigs(pageConfigs, interfaceFilesAll) {
394
- pageConfigs.forEach((pageConfig) => {
395
- assertGlobalConfigs(pageConfig, interfaceFilesAll);
396
- assertExtensionsRequire(pageConfig);
397
- assertOnBeforeRenderEnv(pageConfig);
333
+ function assertPageConfigGlobal(pageConfigGlobal, interfaceFilesAll) {
334
+ Object.entries(pageConfigGlobal.configValueSources).forEach(([configName, sources]) => {
335
+ assertGlobalConfigLocation(configName, sources, interfaceFilesAll, pageConfigGlobal.configDefinitions);
398
336
  });
399
337
  }
400
- // TODO/now: refactor
401
- // - Dedupe: most of the assertGlobalConfigs() code below is a copy-paste of the assertUsage() logic inside getGlobalConfigs()
402
- // - This assertUsage() message is slightly better: use this one for getGlobalConfigs()
403
- // Global configs should be defined at global locations
404
- function assertGlobalConfigs(pageConfig, interfaceFilesAll) {
405
- const interfaceFilesRelevantList = Object.values(pageConfig.interfaceFiles).flat(1);
406
- const { configDefinitions } = pageConfig;
407
- interfaceFilesRelevantList.forEach((interfaceFile) => {
408
- const configNames = [];
409
- if (interfaceFile.isValueFile) {
410
- configNames.push(interfaceFile.configName);
338
+ function assertGlobalConfigLocation(configName, sources, interfaceFilesAll, configDefinitionsGlobal) {
339
+ const locationIdsAll = objectKeys(interfaceFilesAll);
340
+ // Determine existing global +config.js files
341
+ const configFilePathsGlobal = [];
342
+ const interfaceFilesGlobal = Object.values(objectFromEntries(objectEntries(interfaceFilesAll).filter(([locationId]) => isGlobalLocation(locationId, locationIdsAll)))).flat();
343
+ interfaceFilesGlobal
344
+ .filter((i) => i.isConfigFile)
345
+ .forEach((interfaceFile) => {
346
+ const { filePathAbsoluteUserRootDir } = interfaceFile.filePath;
347
+ if (filePathAbsoluteUserRootDir) {
348
+ configFilePathsGlobal.push(filePathAbsoluteUserRootDir);
411
349
  }
412
- else {
413
- configNames.push(...Object.keys(interfaceFile.fileExportsByConfigName));
350
+ });
351
+ // Call assertWarning()
352
+ sources.forEach((source) => {
353
+ const { interfaceFile } = source;
354
+ // It's `null` when the config is defined by `vike(options)` in vite.config.js
355
+ assert(interfaceFile);
356
+ const { filePathAbsoluteUserRootDir } = interfaceFile.filePath;
357
+ // Allow local Vike extensions to set gloabl configs (`filePathAbsoluteUserRootDir===null` for Vike extension)
358
+ if (!filePathAbsoluteUserRootDir)
359
+ return;
360
+ assert(!interfaceFile.isConfigExtension);
361
+ if (!isGlobalLocation(source.locationId, locationIdsAll)) {
362
+ const configDef = configDefinitionsGlobal[configName];
363
+ assert(configDef);
364
+ const isConditionallyGlobal = isCallable(configDef.global);
365
+ const errBeg = `${filePathAbsoluteUserRootDir} (which is a local config file) sets the config ${pc.cyan(configName)}`;
366
+ const errMid = !isConditionallyGlobal
367
+ ? "but it's a global config"
368
+ : 'to a value that is global';
369
+ const what = isConditionallyGlobal ? 'global values' : pc.cyan(configName);
370
+ const errEnd = configFilePathsGlobal.length > 0
371
+ ? `define ${what} at a global config file such as ${joinEnglish(configFilePathsGlobal, 'or')} instead`
372
+ : `create a global config file (e.g. /pages/+config.js) and define ${what} there instead`;
373
+ // When updating this error message => also update error message at https://vike.dev/warning/global-config
374
+ const errMsg = `${errBeg} ${errMid}: ${errEnd} (https://vike.dev/warning/global-config).`;
375
+ assertWarning(false, errMsg, { onlyOnce: true });
414
376
  }
415
- configNames.forEach((configName) => {
416
- if (isGlobalConfig(configName))
417
- return;
418
- const configDef = getConfigDefinition(configDefinitions, configName, interfaceFile.filePath.filePathToShowToUser);
419
- if (configDef.global === true) {
420
- const locationIds = objectKeys(interfaceFilesAll);
421
- if (!isGlobalLocation(interfaceFile.locationId, locationIds)) {
422
- const interfaceFilesGlobal = objectFromEntries(objectEntries(interfaceFilesAll).filter(([locationId]) => {
423
- return isGlobalLocation(locationId, locationIds);
424
- }));
425
- const configFilesGlobal = [];
426
- objectEntries(interfaceFilesGlobal).forEach(([locationId, interfaceFiles]) => {
427
- assert(isGlobalLocation(locationId, locationIds));
428
- interfaceFiles.forEach((interfaceFile) => {
429
- if (!interfaceFile.isConfigFile)
430
- return;
431
- const { filePath: { filePathAbsoluteUserRootDir } } = interfaceFile;
432
- if (filePathAbsoluteUserRootDir) {
433
- configFilesGlobal.push(filePathAbsoluteUserRootDir);
434
- }
435
- });
436
- });
437
- assertUsage(false, [
438
- `${interfaceFile.filePath.filePathToShowToUser} sets the config ${pc.cyan(configName)} but it's a global config:`,
439
- configFilesGlobal.length > 0
440
- ? `define ${pc.cyan(configName)} at ${joinEnglish(configFilesGlobal, 'or')} instead.`
441
- : `create a global config (e.g. /pages/+config.js) and define ${pc.cyan(configName)} there instead.`
442
- ].join(' '));
443
- }
444
- }
445
- });
377
+ });
378
+ }
379
+ function assertPageConfigs(pageConfigs) {
380
+ pageConfigs.forEach((pageConfig) => {
381
+ assertExtensionsRequire(pageConfig);
382
+ assertOnBeforeRenderEnv(pageConfig);
446
383
  });
447
384
  }
448
385
  function assertOnBeforeRenderEnv(pageConfig) {
@@ -482,13 +419,31 @@ function getConfigValues(pageConfig) {
482
419
  });
483
420
  return configValues;
484
421
  }
485
- function interfacefileIsAlreaydLoaded(interfaceFile) {
486
- const configMapValues = Object.values(interfaceFile.fileExportsByConfigName);
487
- const isAlreadyLoaded = configMapValues.some((conf) => 'configValue' in conf);
488
- if (isAlreadyLoaded) {
489
- assert(configMapValues.every((conf) => 'configValue' in conf));
490
- }
491
- return isAlreadyLoaded;
422
+ function temp_interopVikeVitePlugin(pageConfigGlobal, vikeVitePluginOptions, userRootDir) {
423
+ assert(isObject(vikeVitePluginOptions));
424
+ assertWarning(Object.keys(vikeVitePluginOptions).length === 0, `Define Vike settings in +config.js instead of vite.config.js ${pc.underline('https://vike.dev/migration/settings')}`, { onlyOnce: true });
425
+ Object.entries(vikeVitePluginOptions).forEach(([configName, value]) => {
426
+ var _a;
427
+ assert(includes(objectKeys(configDefinitionsBuiltInAll), configName));
428
+ const configDef = configDefinitionsBuiltInAll[configName];
429
+ const sources = ((_a = pageConfigGlobal.configValueSources)[configName] ?? (_a[configName] = []));
430
+ sources.push({
431
+ value,
432
+ configEnv: configDef.env,
433
+ definedAtFilePath: {
434
+ ...getFilePathResolved({
435
+ userRootDir,
436
+ filePathAbsoluteUserRootDir: '/vite.config.js'
437
+ }),
438
+ fileExportPathToShowToUser: null
439
+ },
440
+ locationId: '/',
441
+ interfaceFile: null,
442
+ isOverriden: configDef.cumulative ? false : sources.length > 0,
443
+ valueIsImportedAtRuntime: false,
444
+ valueIsDefinedByPlusFile: false
445
+ });
446
+ });
492
447
  }
493
448
  function getInterfaceFilesRelevant(interfaceFilesAll, locationIdPage) {
494
449
  const interfaceFilesRelevant = Object.fromEntries(objectEntries(interfaceFilesAll)
@@ -498,26 +453,19 @@ function getInterfaceFilesRelevant(interfaceFilesAll, locationIdPage) {
498
453
  .sort(([locationId1], [locationId2]) => sortAfterInheritanceOrder(locationId1, locationId2, locationIdPage)));
499
454
  return interfaceFilesRelevant;
500
455
  }
501
- async function resolveConfigValueSources(configName, configDef, interfaceFilesRelevant, userRootDir, importedFilesLoaded) {
502
- const sourcesInfo = [];
456
+ function resolveConfigValueSources(configName, configDef, interfaceFilesRelevant, userRootDir, isGlobal) {
457
+ const interfaceFilesSource = [];
503
458
  // interfaceFilesRelevant is sorted by sortAfterInheritanceOrder()
504
459
  for (const interfaceFiles of Object.values(interfaceFilesRelevant)) {
505
- const interfaceFilesDefiningConfig = interfaceFiles.filter((interfaceFile) => interfaceFile.fileExportsByConfigName[configName]);
460
+ const interfaceFilesDefiningConfig = interfaceFiles.filter((interfaceFile) => getDefiningConfigNames(interfaceFile).includes(configName));
506
461
  if (interfaceFilesDefiningConfig.length === 0)
507
462
  continue;
508
463
  const visited = new WeakSet();
509
464
  const add = (interfaceFile) => {
510
465
  assert(!visited.has(interfaceFile));
511
466
  visited.add(interfaceFile);
512
- const isHighestInheritancePrecedence = sourcesInfo.length === 0;
513
- sourcesInfo.push([
514
- configName,
515
- interfaceFile,
516
- configDef,
517
- userRootDir,
518
- importedFilesLoaded,
519
- isHighestInheritancePrecedence
520
- ]);
467
+ const isHighestInheritancePrecedence = interfaceFilesSource.length === 0;
468
+ interfaceFilesSource.push({ interfaceFile, isHighestInheritancePrecedence });
521
469
  };
522
470
  // Main resolution logic
523
471
  {
@@ -528,8 +476,8 @@ async function resolveConfigValueSources(configName, configDef, interfaceFilesRe
528
476
  .sort(makeOrderDeterministic);
529
477
  const interfaceConfigFiles = interfaceFilesDefiningConfig
530
478
  .filter((interfaceFile) => interfaceFile.isConfigFile &&
531
- // We consider value from extended configs (e.g. vike-react) later (i.e. with less priority)
532
- !interfaceFile.isConfigExtend)
479
+ // We consider values from extensions (e.g. vike-react) later (i.e. with less priority)
480
+ !interfaceFile.isConfigExtension)
533
481
  .sort(makeOrderDeterministic);
534
482
  const interfaceValueFile = interfaceValueFiles[0];
535
483
  const interfaceConfigFile = interfaceConfigFiles[0];
@@ -557,8 +505,8 @@ async function resolveConfigValueSources(configName, configDef, interfaceFilesRe
557
505
  });
558
506
  // extends
559
507
  interfaceFilesDefiningConfig
560
- .filter((interfaceFile) => interfaceFile.isConfigFile && interfaceFile.isConfigExtend)
561
- // extended config files are already sorted by inheritance order
508
+ .filter((interfaceFile) => interfaceFile.isConfigFile && interfaceFile.isConfigExtension)
509
+ // Extension config files are already sorted by inheritance order
562
510
  .forEach((interfaceFile) => {
563
511
  add(interfaceFile);
564
512
  });
@@ -566,31 +514,26 @@ async function resolveConfigValueSources(configName, configDef, interfaceFilesRe
566
514
  assert(visited.has(interfaceFile));
567
515
  });
568
516
  }
569
- const sources = await Promise.all(sourcesInfo.map(async (args) => await getConfigValueSource(...args)));
570
- return sources;
571
- }
572
- function makeOrderDeterministic(interfaceFile1, interfaceFile2) {
573
- return lowerFirst((interfaceFile) => {
574
- const { filePathAbsoluteUserRootDir } = interfaceFile.filePath;
575
- assert(isInterfaceFileUserLand(interfaceFile));
576
- assert(filePathAbsoluteUserRootDir);
577
- return filePathAbsoluteUserRootDir.length;
578
- })(interfaceFile1, interfaceFile2);
579
- }
580
- function warnOverridenConfigValues(interfaceFileWinner, interfaceFilesOverriden, configName) {
581
- interfaceFilesOverriden.forEach((interfaceFileLoser) => {
582
- const loserFilePath = interfaceFileLoser.filePath.filePathToShowToUser;
583
- const winnerFilePath = interfaceFileWinner.filePath.filePathToShowToUser;
584
- const confName = pc.cyan(configName);
585
- assertWarning(false, `The value of the config ${confName} defined at ${loserFilePath} is always overwritten by the value defined at ${winnerFilePath}, remove the superfluous value defined at ${loserFilePath}`, { onlyOnce: true });
517
+ let sources = interfaceFilesSource.map(({ interfaceFile, isHighestInheritancePrecedence }) => {
518
+ const configValueSource = getConfigValueSource(configName, interfaceFile, configDef, userRootDir, isHighestInheritancePrecedence);
519
+ return configValueSource;
586
520
  });
521
+ if (isCallable(configDef.global)) {
522
+ const isGlobalValue = configDef.global;
523
+ assert(configDef.env.config);
524
+ sources = sources.filter((source) => {
525
+ assert(source.configEnv.config);
526
+ // TODO/now: source.valueIsDefined
527
+ assert('value' in source);
528
+ const valueIsGlobal = isGlobalValue(source.value);
529
+ return isGlobal ? valueIsGlobal : !valueIsGlobal;
530
+ });
531
+ }
532
+ return sources;
587
533
  }
588
- function isInterfaceFileUserLand(interfaceFile) {
589
- return (interfaceFile.isConfigFile && !interfaceFile.isConfigExtend) || interfaceFile.isValueFile;
590
- }
591
- async function getConfigValueSource(configName, interfaceFile, configDef, userRootDir, importedFilesLoaded, isHighestInheritancePrecedence) {
592
- const conf = interfaceFile.fileExportsByConfigName[configName];
593
- assert(conf);
534
+ function getConfigValueSource(configName, interfaceFile, configDef, userRootDir, isHighestInheritancePrecedence) {
535
+ const confVal = getConfVal(interfaceFile, configName);
536
+ assert(confVal);
594
537
  const configValueSourceCommon = {
595
538
  locationId: interfaceFile.locationId,
596
539
  interfaceFile
@@ -606,11 +549,12 @@ async function getConfigValueSource(configName, interfaceFile, configDef, userRo
606
549
  let valueFilePath;
607
550
  if (interfaceFile.isConfigFile) {
608
551
  // Defined over pointer import
609
- const resolved = resolvePointerImportOfConfig(conf.configValue, interfaceFile.filePath, userRootDir, configDef.env, configName);
552
+ assert(confVal.configValueLoaded);
553
+ const pointerImport = resolvePointerImport(confVal.configValue, interfaceFile.filePath, userRootDir, configName);
610
554
  const configDefinedAt = getConfigDefinedAt('Config', configName, definedAtFilePath_);
611
- assertUsage(resolved, `${configDefinedAt} should be an import`);
612
- valueFilePath = resolved.pointerImport.filePathAbsoluteVite;
613
- definedAtFilePath = resolved.pointerImport;
555
+ assertUsage(pointerImport, `${configDefinedAt} should be an import`);
556
+ valueFilePath = pointerImport.fileExportPath.filePathAbsoluteVite;
557
+ definedAtFilePath = pointerImport.fileExportPath;
614
558
  }
615
559
  else {
616
560
  // Defined by value file, i.e. +{configName}.js
@@ -635,31 +579,22 @@ async function getConfigValueSource(configName, interfaceFile, configDef, userRo
635
579
  }
636
580
  // +config.js
637
581
  if (interfaceFile.isConfigFile) {
638
- assert('configValue' in conf);
639
- const { configValue } = conf;
582
+ assert(confVal.configValueLoaded);
583
+ const { configValue } = confVal;
640
584
  // Defined over pointer import
641
- const resolved = resolvePointerImportOfConfig(configValue, interfaceFile.filePath, userRootDir, configDef.env, configName);
642
- if (resolved) {
585
+ const pointerImport = interfaceFile.pointerImportsByConfigName[configName];
586
+ if (pointerImport) {
643
587
  const configValueSource = {
644
588
  ...configValueSourceCommon,
645
- configEnv: resolved.configEnvResolved,
589
+ configEnv: resolveConfigEnv(configDef.env, pointerImport.fileExportPath),
646
590
  valueIsImportedAtRuntime: true,
647
591
  valueIsDefinedByPlusFile: false,
648
592
  isOverriden,
649
- definedAtFilePath: resolved.pointerImport
593
+ definedAtFilePath: pointerImport.fileExportPath
650
594
  };
651
- // Load pointer import
652
- if (shouldBeLoadableAtBuildTime(configDef) &&
653
- // The value of `extends` was already loaded and already used: we don't need the value of `extends` anymore
654
- configName !== 'extends') {
655
- if (resolved.pointerImport.filePathAbsoluteFilesystem) {
656
- const fileExport = await loadImportedFile(resolved.pointerImport, userRootDir, importedFilesLoaded);
657
- configValueSource.value = fileExport;
658
- }
659
- else {
660
- const configDefinedAt = getConfigDefinedAt('Config', configName, configValueSource.definedAtFilePath);
661
- assertUsage(!configDef.cumulative, `${configDefinedAt} cannot be defined over an aliased import`);
662
- }
595
+ if (pointerImport.fileExportValueLoaded) {
596
+ configValueSource.value = pointerImport.fileExportValue;
597
+ assert('fileExportValue' in pointerImport);
663
598
  }
664
599
  return configValueSource;
665
600
  }
@@ -677,8 +612,8 @@ async function getConfigValueSource(configName, interfaceFile, configDef, userRo
677
612
  }
678
613
  // Defined by value file, i.e. +{configName}.js
679
614
  if (interfaceFile.isValueFile) {
680
- const configEnvResolved = resolveConfigEnvWithFileName(configDef.env, interfaceFile.filePath);
681
- const valueAlreadyLoaded = 'configValue' in conf;
615
+ const configEnvResolved = resolveConfigEnv(configDef.env, interfaceFile.filePath);
616
+ const valueAlreadyLoaded = confVal.configValueLoaded;
682
617
  assert(valueAlreadyLoaded === !!configEnvResolved.config);
683
618
  const configValueSource = {
684
619
  ...configValueSourceCommon,
@@ -695,15 +630,34 @@ async function getConfigValueSource(configName, interfaceFile, configDef, userRo
695
630
  }
696
631
  };
697
632
  if (valueAlreadyLoaded) {
698
- configValueSource.value = conf.configValue;
633
+ configValueSource.value = confVal.configValue;
699
634
  }
700
635
  return configValueSource;
701
636
  }
702
637
  assert(false);
703
638
  }
639
+ function makeOrderDeterministic(interfaceFile1, interfaceFile2) {
640
+ return lowerFirst((interfaceFile) => {
641
+ const { filePathAbsoluteUserRootDir } = interfaceFile.filePath;
642
+ assert(isInterfaceFileUserLand(interfaceFile));
643
+ assert(filePathAbsoluteUserRootDir);
644
+ return filePathAbsoluteUserRootDir.length;
645
+ })(interfaceFile1, interfaceFile2);
646
+ }
647
+ function warnOverridenConfigValues(interfaceFileWinner, interfaceFilesOverriden, configName) {
648
+ interfaceFilesOverriden.forEach((interfaceFileLoser) => {
649
+ const loserFilePath = interfaceFileLoser.filePath.filePathToShowToUser;
650
+ const winnerFilePath = interfaceFileWinner.filePath.filePathToShowToUser;
651
+ const confName = pc.cyan(configName);
652
+ assertWarning(false, `The value of the config ${confName} defined at ${loserFilePath} is always overwritten by the value defined at ${winnerFilePath}, remove the superfluous value defined at ${loserFilePath}`, { onlyOnce: true });
653
+ });
654
+ }
655
+ function isInterfaceFileUserLand(interfaceFile) {
656
+ return (interfaceFile.isConfigFile && !interfaceFile.isConfigExtension) || interfaceFile.isValueFile;
657
+ }
704
658
  function isDefiningPage(interfaceFiles) {
705
659
  for (const interfaceFile of interfaceFiles) {
706
- const configNames = Object.keys(interfaceFile.fileExportsByConfigName);
660
+ const configNames = getDefiningConfigNames(interfaceFile);
707
661
  if (configNames.some((configName) => isDefiningPageConfig(configName))) {
708
662
  return true;
709
663
  }
@@ -713,16 +667,29 @@ function isDefiningPage(interfaceFiles) {
713
667
  function isDefiningPageConfig(configName) {
714
668
  return ['Page', 'route'].includes(configName);
715
669
  }
716
- function getConfigDefinitions(interfaceFilesRelevant) {
717
- const configDefinitionsMerged = { ...configDefinitionsBuiltIn };
670
+ function getDefiningConfigNames(interfaceFile) {
671
+ let configNames = [];
672
+ if (interfaceFile.isValueFile) {
673
+ configNames.push(interfaceFile.configName);
674
+ }
675
+ if (interfaceFile.isValueFileLoaded) {
676
+ configNames.push(...Object.keys(interfaceFile.fileExportsByConfigName));
677
+ }
678
+ configNames = unique(configNames);
679
+ return configNames;
680
+ }
681
+ function getConfigDefinitions(interfaceFilesRelevant, filter) {
682
+ let configDefinitions = { ...configDefinitionsBuiltInAll };
683
+ // Add user-land meta configs
718
684
  Object.entries(interfaceFilesRelevant)
719
685
  .reverse()
720
686
  .forEach(([_locationId, interfaceFiles]) => {
721
687
  interfaceFiles.forEach((interfaceFile) => {
722
- const configMeta = interfaceFile.fileExportsByConfigName['meta'];
723
- if (!configMeta)
688
+ const confVal = getConfVal(interfaceFile, 'meta');
689
+ if (!confVal)
724
690
  return;
725
- const meta = configMeta.configValue;
691
+ assert(confVal.configValueLoaded);
692
+ const meta = confVal.configValue;
726
693
  assertMetaUsage(meta, `Config ${pc.cyan('meta')} defined at ${interfaceFile.filePath.filePathToShowToUser}`);
727
694
  // Set configDef._userEffectDefinedAtFilePath
728
695
  Object.entries(meta).forEach(([configName, configDef]) => {
@@ -734,16 +701,18 @@ function getConfigDefinitions(interfaceFilesRelevant) {
734
701
  fileExportPathToShowToUser: ['default', 'meta', configName, 'effect']
735
702
  };
736
703
  });
737
- objectEntries(meta).forEach(([configName, configDefinition]) => {
704
+ objectEntries(meta).forEach(([configName, configDefinitionUserLand]) => {
738
705
  // User can override an existing config definition
739
- configDefinitionsMerged[configName] = {
740
- ...configDefinitionsMerged[configName],
741
- ...configDefinition
706
+ configDefinitions[configName] = {
707
+ ...configDefinitions[configName],
708
+ ...configDefinitionUserLand
742
709
  };
743
710
  });
744
711
  });
745
712
  });
746
- const configDefinitions = configDefinitionsMerged;
713
+ if (filter) {
714
+ configDefinitions = Object.fromEntries(Object.entries(configDefinitions).filter(([_configName, configDef]) => filter(configDef)));
715
+ }
747
716
  return configDefinitions;
748
717
  }
749
718
  function assertMetaUsage(metaVal, metaConfigDefinedAt) {
@@ -897,10 +866,35 @@ function assertNoUnexpectedPlusSign(filePath: string, fileName: string) {
897
866
  )
898
867
  }
899
868
  */
900
- function handleUnknownConfig(configName, configNames, filePathToShowToUser) {
869
+ // Show error message upon unknown config
870
+ function assertKnownConfigs(interfaceFilesAll) {
871
+ const configDefinitionsAll = getConfigDefinitions(interfaceFilesAll);
872
+ const configNamesKnownAll = Object.keys(configDefinitionsAll);
873
+ objectEntries(interfaceFilesAll).forEach(([locationId, interfaceFiles]) => {
874
+ const interfaceFilesRelevant = getInterfaceFilesRelevant(interfaceFilesAll, locationId);
875
+ const configDefinitionsLocal = getConfigDefinitions(interfaceFilesRelevant);
876
+ const configNamesKnownLocal = Object.keys(configDefinitionsLocal);
877
+ interfaceFiles.forEach((interfaceFile) => {
878
+ const configNames = getDefiningConfigNames(interfaceFile);
879
+ configNames.forEach((configName) => {
880
+ assertKnownConfig(configName, configNamesKnownAll, configNamesKnownLocal, interfaceFile);
881
+ assert(configNamesKnownLocal.includes(configName));
882
+ assert(configNamesKnownAll.includes(configName));
883
+ });
884
+ });
885
+ });
886
+ }
887
+ function assertKnownConfig(configName, configNamesKnownAll, configNamesKnownLocal, interfaceFile) {
888
+ if (configNamesKnownLocal.includes(configName))
889
+ return;
901
890
  const configNameColored = pc.cyan(configName);
902
- let errMsg = `${filePathToShowToUser} sets an unknown config ${configNameColored}.`;
903
- // vike-{react,vue,solid} hint
891
+ const { locationId, filePath: { filePathToShowToUser } } = interfaceFile;
892
+ const errMsg = `${filePathToShowToUser} sets an unknown config ${configNameColored}`;
893
+ // Inheritance issue: config is known but isn't defined at `locationId`
894
+ if (configNamesKnownAll.includes(configName)) {
895
+ assertUsage(false, `${filePathToShowToUser} sets the value of the config ${configNameColored} which is a custom config that is defined with ${pc.underline('https://vike.dev/meta')} at a path that doesn't apply to ${locationId} — see ${pc.underline('https://vike.dev/config#inheritance')}`);
896
+ }
897
+ // Missing vike-{react,vue,solid} installation
904
898
  {
905
899
  const ui = ['vike-react', 'vike-vue', 'vike-solid'];
906
900
  const knownVikeExntensionConfigs = {
@@ -915,15 +909,11 @@ function handleUnknownConfig(configName, configNames, filePathToShowToUser) {
915
909
  Wrapper: ui
916
910
  };
917
911
  if (configName in knownVikeExntensionConfigs) {
918
- const requiredVikeExtension = knownVikeExntensionConfigs[configName];
919
- assertUsage(false, [
920
- errMsg,
921
- `If you want to use the configuration documented at https://vike.dev/${configName} then make sure to install the Vike extension ${requiredVikeExtension
922
- .map((e) => pc.bold(e))
923
- .join('/')}.`,
924
- `Also make sure it applies to ${filePathToShowToUser} (see https://vike.dev/extends#inheritance).`,
925
- `Alternatively, if you don't want to use the aforementioned Vike extension, define it yourself by using ${pc.cyan('meta')} (https://vike.dev/meta).`
926
- ].join(' '));
912
+ const requiredVikeExtension = knownVikeExntensionConfigs[configName]
913
+ .map((e) => pc.bold(e))
914
+ .join('/');
915
+ const errMsgEnhanced = `${errMsg}. If you want to use the configuration ${configNameColored} documented at ${pc.underline(`https://vike.dev/${configName}`)} then make sure to install ${requiredVikeExtension}. (Alternatively, you can define ${configNameColored} yourself by using ${pc.cyan('meta')}, see ${pc.underline('https://vike.dev/meta')} for more information.)`;
916
+ assertUsage(false, errMsgEnhanced);
927
917
  }
928
918
  }
929
919
  // Similarity hint
@@ -932,18 +922,15 @@ function handleUnknownConfig(configName, configNames, filePathToShowToUser) {
932
922
  configNameSimilar = 'Page';
933
923
  }
934
924
  else {
935
- configNameSimilar = getMostSimilar(configName, configNames);
925
+ configNameSimilar = getMostSimilar(configName, configNamesKnownAll);
936
926
  }
937
927
  if (configNameSimilar) {
938
928
  assert(configNameSimilar !== configName);
939
- errMsg += ` Did you mean to set ${pc.cyan(configNameSimilar)} instead?`;
929
+ let errMsgEnhanced = `${errMsg}. Did you mean ${pc.cyan(configNameSimilar)} instead?`;
940
930
  if (configName === 'page') {
941
- errMsg += ` (The name of the config ${pc.cyan('Page')} starts with a capital letter ${pc.cyan('P')} because it defines a UI component: a ubiquitous JavaScript convention is that the name of UI components start with a capital letter.)`;
931
+ errMsgEnhanced += ` (The name of the config ${pc.cyan('Page')} starts with a capital letter ${pc.cyan('P')} because it defines a UI component: a ubiquitous JavaScript convention is that the name of UI components start with a capital letter.)`;
942
932
  }
943
- }
944
- // `meta` hint
945
- if (!configNameSimilar) {
946
- errMsg += ` Make sure to define ${configNameColored} by using ${pc.cyan('meta')} (https://vike.dev/meta), and also make sure the meta configuration applies to ${filePathToShowToUser} (see https://vike.dev/config#inheritance).`;
933
+ assertUsage(false, errMsgEnhanced);
947
934
  }
948
935
  assertUsage(false, errMsg);
949
936
  }
@@ -1030,52 +1017,9 @@ function getConfigEnvValue(val, errMsgIntro) {
1030
1017
  */
1031
1018
  return val;
1032
1019
  }
1033
- function getConfigDefinition(configDefinitions, configName, filePathToShowToUser) {
1034
- const configDef = configDefinitions[configName];
1035
- assertConfigExists(configName, Object.keys(configDefinitions), filePathToShowToUser);
1036
- assert(configDef);
1037
- return configDef;
1038
- }
1039
1020
  function getConfigDefinitionOptional(configDefinitions, configName) {
1040
1021
  return configDefinitions[configName] ?? null;
1041
1022
  }
1042
- function shouldBeLoadableAtBuildTime(configDef) {
1043
- return !!configDef.env.config && !configDef._valueIsFilePath;
1044
- }
1045
- function isGlobalConfig(configName) {
1046
- // TODO/now
1047
- if (configName === 'prerender')
1048
- return false;
1049
- const configNamesGlobal = getConfigNamesGlobal();
1050
- return includes(configNamesGlobal, configName);
1051
- }
1052
- /*
1053
- // TODO/now
1054
- function isGlobalConfig(configName: string, configDefinitions: ConfigDefinitions): configName is ConfigNameGlobal {
1055
- const configSpec = configDefinitions[configName]
1056
- assert(configSpec)
1057
- const globalValue = configSpec.global
1058
- if (!globalValue) return false
1059
- if (globalValue === true ) return true
1060
- return globalValue(value)
1061
- }
1062
- */
1063
- function getConfigNamesGlobal() {
1064
- return Object.keys(configDefinitionsBuiltInGlobal);
1065
- }
1066
- function getConfigDefinitionsBuiltInGlobal() {
1067
- return objectFromEntries(objectEntries(configDefinitionsBuiltInAll).filter(([_configName, configDef]) => configDef.global !== undefined));
1068
- }
1069
- function getConfigDefinitionsBuiltIn() {
1070
- return objectFromEntries(objectEntries(configDefinitionsBuiltInAll).filter(([_configName, configDef]) => configDef.global !== true));
1071
- }
1072
- function assertConfigExists(configName, configNamesRelevant, filePathToShowToUser) {
1073
- const configNames = [...configNamesRelevant, ...getConfigNamesGlobal()];
1074
- if (configNames.includes(configName))
1075
- return;
1076
- handleUnknownConfig(configName, configNames, filePathToShowToUser);
1077
- assert(false);
1078
- }
1079
1023
  function sortConfigValueSources(configValueSources, locationIdPage) {
1080
1024
  return Object.fromEntries(Object.entries(configValueSources)
1081
1025
  // Make order deterministic (no other purpose)
@@ -1092,6 +1036,31 @@ function sortConfigValueSources(configValueSources, locationIdPage) {
1092
1036
  // Sort after the filesystem inheritance of the config value
1093
1037
  .sort(([, [source1]], [, [source2]]) => reverse(sortAfterInheritanceOrder(source1.locationId, source2.locationId, locationIdPage))));
1094
1038
  }
1095
- function getConfigValueInterfaceFile(interfaceFile, configName) {
1096
- return interfaceFile.fileExportsByConfigName[configName]?.configValue;
1039
+ function getConfVal(interfaceFile, configName) {
1040
+ const configNames = getDefiningConfigNames(interfaceFile);
1041
+ if (!configNames.includes(configName))
1042
+ return null;
1043
+ if (!interfaceFile.isValueFileLoaded)
1044
+ return { configValueLoaded: false };
1045
+ const confVal = { configValue: interfaceFile.fileExportsByConfigName[configName], configValueLoaded: true };
1046
+ return confVal;
1047
+ }
1048
+ function resolveConfigEnv(configEnv, filePath) {
1049
+ const configEnvResolved = { ...configEnv };
1050
+ if (filePath.filePathAbsoluteFilesystem) {
1051
+ const { fileName } = filePath;
1052
+ if (fileName.includes('.server.')) {
1053
+ configEnvResolved.server = true;
1054
+ configEnvResolved.client = false;
1055
+ }
1056
+ else if (fileName.includes('.client.')) {
1057
+ configEnvResolved.client = true;
1058
+ configEnvResolved.server = false;
1059
+ }
1060
+ else if (fileName.includes('.shared.')) {
1061
+ configEnvResolved.server = true;
1062
+ configEnvResolved.client = true;
1063
+ }
1064
+ }
1065
+ return configEnvResolved;
1097
1066
  }