vike 0.4.159 → 0.4.160-commit-30d535e

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 (125) hide show
  1. package/dist/cjs/node/plugin/index.js +20 -1
  2. package/dist/cjs/node/plugin/plugins/autoFullBuild.js +2 -2
  3. package/dist/cjs/node/plugin/plugins/buildConfig.js +9 -0
  4. package/dist/cjs/node/plugin/plugins/commonConfig.js +1 -1
  5. package/dist/cjs/node/plugin/plugins/config/stemUtils.js +1 -1
  6. package/dist/cjs/node/plugin/plugins/devConfig/index.js +1 -1
  7. package/dist/cjs/node/plugin/plugins/importBuild/index.js +1 -1
  8. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getConfigFileExport.js +18 -0
  9. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.js +1 -5
  10. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/filesystemRouting.js +28 -46
  11. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/loadFileAtConfigTime.js +129 -0
  12. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/resolveFilePath.js +33 -0
  13. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/resolveImportPath.js +139 -0
  14. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/{replaceImportStatements.js → getVikeConfig/transformFileImports.js} +44 -13
  15. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/{transpileAndExecuteFile.js → getVikeConfig/transpileAndExecuteFile.js} +105 -78
  16. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +201 -382
  17. package/dist/cjs/node/plugin/plugins/previewConfig.js +1 -1
  18. package/dist/cjs/node/plugin/shared/getHttpRequestAsyncStore.js +1 -1
  19. package/dist/cjs/node/plugin/shared/loggerNotProd/log.js +3 -3
  20. package/dist/cjs/node/plugin/shared/loggerNotProd.js +1 -1
  21. package/dist/cjs/node/plugin/utils.js +1 -2
  22. package/dist/cjs/node/prerender/runPrerender.js +12 -5
  23. package/dist/cjs/node/runtime/globalContext.js +7 -3
  24. package/dist/cjs/node/runtime/html/injectAssets/getHtmlTags.js +2 -2
  25. package/dist/cjs/node/runtime/html/renderHtml.js +1 -1
  26. package/dist/cjs/node/runtime/html/stream.js +2 -2
  27. package/dist/cjs/node/runtime/renderPage/executeOnRenderHtmlHook.js +2 -2
  28. package/dist/cjs/node/runtime/renderPage/getHttpResponseBody.js +1 -1
  29. package/dist/cjs/node/runtime/renderPage/loadUserFilesServerSide.js +1 -1
  30. package/dist/cjs/node/runtime/renderPage/{logHintForCjsEsmError.js → logErrorHint.js} +81 -43
  31. package/dist/cjs/node/runtime/renderPage/loggerProd.js +3 -3
  32. package/dist/cjs/node/runtime/utils.js +1 -1
  33. package/dist/cjs/shared/page-configs/assertPlusFileExport.js +44 -0
  34. package/dist/cjs/shared/page-configs/serialize/parseConfigValuesImported.js +54 -27
  35. package/dist/cjs/shared/route/abort.js +1 -1
  36. package/dist/cjs/shared/route/executeGuardHook.js +3 -2
  37. package/dist/cjs/shared/utils.js +0 -1
  38. package/dist/cjs/utils/assert.js +5 -6
  39. package/dist/cjs/utils/assertIsNotProductionRuntime.js +35 -17
  40. package/dist/cjs/utils/{findUserPackageJsonPath.js → findFile.js} +11 -8
  41. package/dist/cjs/utils/nodeEnv.js +33 -1
  42. package/dist/cjs/utils/objectKeys.js +19 -3
  43. package/dist/cjs/utils/projectInfo.js +2 -4
  44. package/dist/cjs/utils/sorter.js +62 -1
  45. package/dist/esm/node/plugin/index.js +21 -2
  46. package/dist/esm/node/plugin/plugins/autoFullBuild.js +2 -2
  47. package/dist/esm/node/plugin/plugins/buildConfig.js +10 -1
  48. package/dist/esm/node/plugin/plugins/commonConfig.js +2 -2
  49. package/dist/esm/node/plugin/plugins/config/stemUtils.js +2 -2
  50. package/dist/esm/node/plugin/plugins/devConfig/index.js +2 -2
  51. package/dist/esm/node/plugin/plugins/importBuild/index.js +2 -2
  52. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getConfigFileExport.d.ts +2 -0
  53. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getConfigFileExport.js +12 -0
  54. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/configDefinitionsBuiltIn.d.ts +8 -1
  55. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.d.ts +0 -1
  56. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.js +1 -5
  57. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/filesystemRouting.d.ts +39 -12
  58. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/filesystemRouting.js +29 -47
  59. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/loadFileAtConfigTime.d.ts +21 -0
  60. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/loadFileAtConfigTime.js +123 -0
  61. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/resolveFilePath.d.ts +5 -0
  62. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/resolveFilePath.js +27 -0
  63. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/resolveImportPath.d.ts +12 -0
  64. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/resolveImportPath.js +133 -0
  65. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/{replaceImportStatements.d.ts → getVikeConfig/transformFileImports.d.ts} +5 -5
  66. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/{replaceImportStatements.js → getVikeConfig/transformFileImports.js} +43 -12
  67. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/{transpileAndExecuteFile.d.ts → getVikeConfig/transpileAndExecuteFile.d.ts} +3 -3
  68. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/{transpileAndExecuteFile.js → getVikeConfig/transpileAndExecuteFile.js} +105 -78
  69. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.d.ts +16 -1
  70. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +199 -380
  71. package/dist/esm/node/plugin/plugins/previewConfig.js +2 -2
  72. package/dist/esm/node/plugin/shared/getHttpRequestAsyncStore.js +1 -1
  73. package/dist/esm/node/plugin/shared/loggerNotProd/log.js +3 -3
  74. package/dist/esm/node/plugin/shared/loggerNotProd.js +1 -1
  75. package/dist/esm/node/plugin/utils.d.ts +1 -2
  76. package/dist/esm/node/plugin/utils.js +1 -2
  77. package/dist/esm/node/prerender/runPrerender.js +13 -6
  78. package/dist/esm/node/runtime/globalContext.js +8 -4
  79. package/dist/esm/node/runtime/html/injectAssets/getHtmlTags.js +2 -2
  80. package/dist/esm/node/runtime/html/renderHtml.js +1 -1
  81. package/dist/esm/node/runtime/html/stream.js +2 -2
  82. package/dist/esm/node/runtime/renderPage/executeOnRenderHtmlHook.js +2 -2
  83. package/dist/esm/node/runtime/renderPage/getHttpResponseBody.js +1 -1
  84. package/dist/esm/node/runtime/renderPage/loadUserFilesServerSide.js +1 -1
  85. package/dist/esm/node/runtime/renderPage/logErrorHint.d.ts +8 -0
  86. package/dist/esm/node/runtime/renderPage/{logHintForCjsEsmError.js → logErrorHint.js} +80 -42
  87. package/dist/esm/node/runtime/renderPage/loggerProd.js +3 -3
  88. package/dist/esm/node/runtime/utils.d.ts +1 -1
  89. package/dist/esm/node/runtime/utils.js +1 -1
  90. package/dist/esm/shared/page-configs/Config.d.ts +1 -1
  91. package/dist/esm/shared/page-configs/PageConfig.d.ts +6 -0
  92. package/dist/esm/shared/page-configs/assertPlusFileExport.d.ts +2 -0
  93. package/dist/esm/shared/page-configs/assertPlusFileExport.js +38 -0
  94. package/dist/esm/shared/page-configs/serialize/parseConfigValuesImported.js +54 -27
  95. package/dist/esm/shared/route/abort.js +2 -2
  96. package/dist/esm/shared/route/executeGuardHook.js +3 -2
  97. package/dist/esm/shared/utils.d.ts +0 -1
  98. package/dist/esm/shared/utils.js +0 -1
  99. package/dist/esm/utils/assert.js +5 -6
  100. package/dist/esm/utils/assertIsNotProductionRuntime.d.ts +8 -6
  101. package/dist/esm/utils/assertIsNotProductionRuntime.js +35 -17
  102. package/dist/esm/utils/debug.d.ts +1 -1
  103. package/dist/esm/utils/findFile.d.ts +3 -0
  104. package/dist/esm/utils/findFile.js +21 -0
  105. package/dist/esm/utils/nodeEnv.d.ts +6 -0
  106. package/dist/esm/utils/nodeEnv.js +29 -0
  107. package/dist/esm/utils/objectKeys.d.ts +10 -1
  108. package/dist/esm/utils/objectKeys.js +20 -3
  109. package/dist/esm/utils/projectInfo.d.ts +2 -8
  110. package/dist/esm/utils/projectInfo.js +2 -4
  111. package/dist/esm/utils/sorter.d.ts +59 -0
  112. package/dist/esm/utils/sorter.js +61 -0
  113. package/package.json +1 -1
  114. package/dist/cjs/shared/page-configs/assertExports.js +0 -67
  115. package/dist/cjs/utils/objectEntries.js +0 -8
  116. package/dist/esm/node/runtime/renderPage/logHintForCjsEsmError.d.ts +0 -13
  117. package/dist/esm/shared/page-configs/assertExports.d.ts +0 -6
  118. package/dist/esm/shared/page-configs/assertExports.js +0 -61
  119. package/dist/esm/utils/findUserPackageJsonPath.d.ts +0 -2
  120. package/dist/esm/utils/findUserPackageJsonPath.js +0 -18
  121. package/dist/esm/utils/objectEntries.d.ts +0 -4
  122. package/dist/esm/utils/objectEntries.js +0 -5
  123. /package/dist/cjs/node/runtime/renderPage/{logHintForCjsEsmError → logErrorHint}/errors.js +0 -0
  124. /package/dist/esm/node/runtime/renderPage/{logHintForCjsEsmError → logErrorHint}/errors.d.ts +0 -0
  125. /package/dist/esm/node/runtime/renderPage/{logHintForCjsEsmError → logErrorHint}/errors.js +0 -0
@@ -2,31 +2,32 @@ export { getVikeConfig };
2
2
  export { reloadVikeConfig };
3
3
  export { vikeConfigDependencies };
4
4
  export { isVikeConfigFile };
5
- import { assertPosixPath, assert, isObject, assertUsage, assertWarning, objectEntries, hasProp, arrayIncludes, assertIsNotProductionRuntime, getMostSimilar, isNpmPackageImport, joinEnglish, lowerFirst, mergeCumulativeValues, requireResolve, getOutDirs, deepEqual, assertKeys } from '../../../utils.js';
5
+ import { assertPosixPath, assert, isObject, assertUsage, assertWarning, objectEntries, hasProp, arrayIncludes, assertIsNotProductionRuntime, getMostSimilar, joinEnglish, lowerFirst, mergeCumulativeValues, getOutDirs, assertKeys, objectKeys, objectFromEntries, makeFirst, isNpmPackageImport, reverse } from '../../../utils.js';
6
6
  import path from 'path';
7
7
  import { configDefinitionsBuiltIn, configDefinitionsBuiltInGlobal } from './getVikeConfig/configDefinitionsBuiltIn.js';
8
8
  import { getLocationId, getFilesystemRouteString, getFilesystemRouteDefinedBy, isInherited, sortAfterInheritanceOrder, isGlobalLocation, applyFilesystemRoutingRootEffect } from './getVikeConfig/filesystemRouting.js';
9
- import { isTmpFile, transpileAndExecuteFile } from './transpileAndExecuteFile.js';
10
- import { parseImportData } from './replaceImportStatements.js';
9
+ import { isTmpFile } from './getVikeConfig/transpileAndExecuteFile.js';
11
10
  import { isConfigInvalid, isConfigInvalid_set } from '../../../../runtime/renderPage/isConfigInvalid.js';
12
11
  import { getViteDevServer } from '../../../../runtime/globalContext.js';
13
12
  import { logConfigError, logConfigErrorRecover } from '../../../shared/loggerNotProd.js';
14
13
  import { removeSuperfluousViteLog_enable, removeSuperfluousViteLog_disable } from '../../../shared/loggerVite/removeSuperfluousViteLog.js';
15
14
  import pc from '@brillout/picocolors';
16
15
  import { getConfigDefinedAtString } from '../../../../../shared/page-configs/helpers.js';
17
- import { assertExportsOfConfigFile, assertExportsOfValueFile } from '../../../../../shared/page-configs/assertExports.js';
18
16
  import { getConfigVike } from '../../../../shared/getConfigVike.js';
19
17
  import { assertConfigValueIsSerializable } from './getConfigValuesSerialized.js';
20
18
  import { crawlPlusFiles } from './getVikeConfig/crawlPlusFiles.js';
19
+ import { getConfigFileExport } from './getConfigFileExport.js';
20
+ import { loadConfigFile, loadImportedFile, loadValueFile } from './getVikeConfig/loadFileAtConfigTime.js';
21
+ import { clearFilesEnvMap, resolveImport } from './getVikeConfig/resolveImportPath.js';
22
+ import { resolveFilePathRelativeToUserRootDir } from './getVikeConfig/resolveFilePath.js';
21
23
  assertIsNotProductionRuntime();
22
24
  let devServerIsCorrupt = false;
23
25
  let wasConfigInvalid = null;
24
26
  let vikeConfigPromise = null;
25
27
  const vikeConfigDependencies = new Set();
26
- const filesEnv = new Map();
27
28
  function reloadVikeConfig(userRootDir, outDirRoot, extensions) {
28
29
  vikeConfigDependencies.clear();
29
- filesEnv.clear();
30
+ clearFilesEnvMap();
30
31
  vikeConfigPromise = loadVikeConfig_withErrorHandling(userRootDir, outDirRoot, true, extensions, true);
31
32
  handleReloadSideEffects();
32
33
  }
@@ -82,108 +83,98 @@ async function loadInterfaceFiles(userRootDir, outDirRoot, isDev, extensions) {
82
83
  }
83
84
  });
84
85
  let interfaceFilesByLocationId = {};
85
- // Config files
86
- await Promise.all(configFiles.map(async (filePath) => {
87
- const { configFile, extendsConfigs } = await loadConfigFile(filePath, userRootDir, []);
88
- const interfaceFile = getInterfaceFileFromConfigFile(configFile, false);
89
- const locationId = getLocationId(filePath.filePathAbsoluteVite);
90
- interfaceFilesByLocationId[locationId] = interfaceFilesByLocationId[locationId] ?? [];
91
- interfaceFilesByLocationId[locationId].push(interfaceFile);
92
- extendsConfigs.forEach((extendsConfig) => {
93
- const interfaceFile = getInterfaceFileFromConfigFile(extendsConfig, true);
94
- interfaceFilesByLocationId[locationId].push(interfaceFile);
95
- });
96
- }));
97
- // Value files
98
- await Promise.all(valueFiles.map(async (filePath) => {
99
- const configName = getConfigName(filePath.filePathAbsoluteVite);
100
- assert(configName);
101
- const interfaceFile = {
102
- filePath,
103
- configMap: {
104
- [configName]: {}
105
- },
106
- isConfigFile: false,
107
- isValueFile: true,
108
- configName
109
- };
110
- {
111
- // We don't have access to the custom config definitions defined by the user yet.
112
- // - If `configDef` is `undefined` => we load the file +{configName}.js later.
113
- // - We already need to load +meta.js here (to get the custom config definitions defined by the user)
114
- const configDef = getConfigDefinitionOptional(configDefinitionsBuiltIn, configName);
115
- if (configDef && isConfigEnv(configDef, configName)) {
116
- await loadValueFile(interfaceFile, configName, userRootDir);
117
- }
118
- }
119
- {
120
- const locationId = getLocationId(filePath.filePathAbsoluteVite);
86
+ await Promise.all([
87
+ // Config files
88
+ ...configFiles.map(async (filePath) => {
89
+ const { filePathRelativeToUserRootDir } = filePath;
90
+ assert(filePathRelativeToUserRootDir);
91
+ const { configFile, extendsConfigs } = await loadConfigFile(filePath, userRootDir, [], false);
92
+ assert(filePath.filePathRelativeToUserRootDir);
93
+ const locationId = getLocationId(filePathRelativeToUserRootDir);
94
+ const interfaceFile = getInterfaceFileFromConfigFile(configFile, false, locationId);
121
95
  interfaceFilesByLocationId[locationId] = interfaceFilesByLocationId[locationId] ?? [];
122
96
  interfaceFilesByLocationId[locationId].push(interfaceFile);
123
- }
124
- }));
97
+ extendsConfigs.forEach((extendsConfig) => {
98
+ /* We purposely use the same locationId because the Vike extension's config should only apply to where it's being extended from, for example:
99
+ ```js
100
+ // /pages/admin/+config.h.js
101
+
102
+ import vikeVue from 'vike-vue/config'
103
+ // Should only apply to /pages/admin/**
104
+ export default { extends: [vikeVue] }
105
+ ```
106
+ ```js
107
+ // /pages/marketing/+config.h.js
108
+
109
+ import vikeReact from 'vike-react/config'
110
+ // Should only apply to /pages/marketing/**
111
+ export default { extends: [vikeReact] }
112
+ ```
113
+ */
114
+ const interfaceFile = getInterfaceFileFromConfigFile(extendsConfig, true, locationId);
115
+ interfaceFilesByLocationId[locationId].push(interfaceFile);
116
+ });
117
+ }),
118
+ // Value files
119
+ ...valueFiles.map(async (filePath) => {
120
+ const { filePathRelativeToUserRootDir } = filePath;
121
+ assert(filePathRelativeToUserRootDir);
122
+ const configName = getConfigName(filePathRelativeToUserRootDir);
123
+ assert(configName);
124
+ const locationId = getLocationId(filePathRelativeToUserRootDir);
125
+ const interfaceFile = {
126
+ locationId,
127
+ filePath,
128
+ fileExportsByConfigName: {
129
+ [configName]: {}
130
+ },
131
+ isConfigFile: false,
132
+ isValueFile: true,
133
+ configName
134
+ };
135
+ {
136
+ // We don't have access to the custom config definitions defined by the user yet.
137
+ // - If `configDef` is `undefined` => we load the file +{configName}.js later.
138
+ // - We already need to load +meta.js here (to get the custom config definitions defined by the user)
139
+ const configDef = getConfigDefinitionOptional(configDefinitionsBuiltIn, configName);
140
+ if (configDef && isConfigEnv(configDef, configName)) {
141
+ await loadValueFile(interfaceFile, configName, userRootDir);
142
+ }
143
+ }
144
+ {
145
+ interfaceFilesByLocationId[locationId] = interfaceFilesByLocationId[locationId] ?? [];
146
+ interfaceFilesByLocationId[locationId].push(interfaceFile);
147
+ }
148
+ })
149
+ ]);
125
150
  assertAllConfigsAreKnown(interfaceFilesByLocationId);
126
151
  return interfaceFilesByLocationId;
127
152
  }
128
- function getConfigDefinition(configDefinitionsRelevant, configName, filePathToShowToUser) {
129
- const configDef = configDefinitionsRelevant[configName];
130
- assertConfigExists(configName, Object.keys(configDefinitionsRelevant), filePathToShowToUser);
131
- assert(configDef);
132
- return configDef;
133
- }
134
- function getConfigDefinitionOptional(configDefinitions, configName) {
135
- return configDefinitions[configName] ?? null;
136
- }
137
- async function loadValueFile(interfaceValueFile, configName, userRootDir) {
138
- const { fileExports } = await transpileAndExecuteFile(interfaceValueFile.filePath, true, userRootDir);
139
- const { filePathToShowToUser } = interfaceValueFile.filePath;
140
- assertExportsOfValueFile(fileExports, filePathToShowToUser, configName);
141
- Object.entries(fileExports).forEach(([exportName, configValue]) => {
142
- const configName_ = exportName === 'default' ? configName : exportName;
143
- interfaceValueFile.configMap[configName_] = { configValue };
144
- });
145
- }
146
- async function loadImportedFile(filePath, userRootDir, importedFilesLoaded) {
147
- const f = filePath.filePathAbsoluteFilesystem;
148
- if (!importedFilesLoaded[f]) {
149
- importedFilesLoaded[f] = transpileAndExecuteFile(filePath, true, userRootDir).then((r) => r.fileExports);
150
- }
151
- const fileExports = await importedFilesLoaded[f];
152
- return fileExports;
153
- }
154
- function isConfigEnv(configDef, configName) {
155
- const configEnv = configDef.env;
156
- if (configDef.cumulative) {
157
- // In principle we could lift that requirement (but it requires non-trivial modifications)
158
- assertUsage(configEnv.config, `Config ${pc.cyan(configName)} needs its ${pc.cyan('env')} to have ${pc.cyan('{ config: true }')} (because ${pc.cyan(configName)} is a ${pc.cyan('cumulative')} config)`);
159
- }
160
- return !!configEnv.config;
161
- }
162
- function getInterfaceFileFromConfigFile(configFile, isConfigExtend) {
153
+ function getInterfaceFileFromConfigFile(configFile, isConfigExtend, locationId) {
163
154
  const { fileExports, filePath, extendsFilePaths } = configFile;
164
155
  const interfaceFile = {
156
+ locationId,
165
157
  filePath,
166
- configMap: {},
158
+ fileExportsByConfigName: {},
167
159
  isConfigFile: true,
168
160
  isValueFile: false,
169
161
  isConfigExtend,
170
162
  extendsFilePaths
171
163
  };
172
- const { filePathToShowToUser } = filePath;
173
- assertExportsOfConfigFile(fileExports, filePathToShowToUser);
174
- Object.entries(fileExports.default).forEach(([configName, configValue]) => {
175
- interfaceFile.configMap[configName] = { configValue };
164
+ const fileExport = getConfigFileExport(fileExports, filePath.filePathToShowToUser);
165
+ Object.entries(fileExport).forEach(([configName, configValue]) => {
166
+ interfaceFile.fileExportsByConfigName[configName] = { configValue };
176
167
  });
177
168
  return interfaceFile;
178
169
  }
179
170
  /** Show error message upon unknown config */
180
171
  function assertAllConfigsAreKnown(interfaceFilesByLocationId) {
181
- Object.entries(interfaceFilesByLocationId).forEach(([locationId, interfaceFiles]) => {
172
+ objectEntries(interfaceFilesByLocationId).forEach(([locationId, interfaceFiles]) => {
182
173
  const interfaceFilesRelevant = getInterfaceFilesRelevant(interfaceFilesByLocationId, locationId);
183
- const configDefinitionsRelevant = getConfigDefinitions(interfaceFilesRelevant);
174
+ const configDefinitions = getConfigDefinitions(interfaceFilesRelevant);
184
175
  interfaceFiles.forEach((interfaceFile) => {
185
- Object.keys(interfaceFile.configMap).forEach((configName) => {
186
- assertConfigExists(configName, Object.keys(configDefinitionsRelevant), interfaceFile.filePath.filePathToShowToUser);
176
+ Object.keys(interfaceFile.fileExportsByConfigName).forEach((configName) => {
177
+ assertConfigExists(configName, Object.keys(configDefinitions), interfaceFile.filePath.filePathToShowToUser);
187
178
  });
188
179
  });
189
180
  });
@@ -233,11 +224,11 @@ async function loadVikeConfig(userRootDir, outDirRoot, isDev, extensions) {
233
224
  const interfaceFilesByLocationId = await loadInterfaceFiles(userRootDir, outDirRoot, isDev, extensions);
234
225
  const importedFilesLoaded = {};
235
226
  const { globalVikeConfig, pageConfigGlobal } = await getGlobalConfigs(interfaceFilesByLocationId, userRootDir, importedFilesLoaded);
236
- const pageConfigs = await Promise.all(Object.entries(interfaceFilesByLocationId)
227
+ const pageConfigs = await Promise.all(objectEntries(interfaceFilesByLocationId)
237
228
  .filter(([_pageId, interfaceFiles]) => isDefiningPage(interfaceFiles))
238
229
  .map(async ([locationId]) => {
239
230
  const interfaceFilesRelevant = getInterfaceFilesRelevant(interfaceFilesByLocationId, locationId);
240
- const configDefinitionsRelevant = getConfigDefinitions(interfaceFilesRelevant);
231
+ const configDefinitions = getConfigDefinitions(interfaceFilesRelevant);
241
232
  // Load value files of custom config-only configs
242
233
  await Promise.all(getInterfaceFileList(interfaceFilesRelevant).map(async (interfaceFile) => {
243
234
  if (!interfaceFile.isValueFile)
@@ -245,7 +236,7 @@ async function loadVikeConfig(userRootDir, outDirRoot, isDev, extensions) {
245
236
  const { configName } = interfaceFile;
246
237
  if (isGlobalConfig(configName))
247
238
  return;
248
- const configDef = getConfigDefinition(configDefinitionsRelevant, configName, interfaceFile.filePath.filePathToShowToUser);
239
+ const configDef = getConfigDefinition(configDefinitions, configName, interfaceFile.filePath.filePathToShowToUser);
249
240
  if (!isConfigEnv(configDef, configName))
250
241
  return;
251
242
  const isAlreadyLoaded = interfacefileIsAlreaydLoaded(interfaceFile);
@@ -255,8 +246,8 @@ async function loadVikeConfig(userRootDir, outDirRoot, isDev, extensions) {
255
246
  assert(!(configName in configDefinitionsBuiltIn));
256
247
  await loadValueFile(interfaceFile, configName, userRootDir);
257
248
  }));
258
- const configValueSources = {};
259
- await Promise.all(objectEntries(configDefinitionsRelevant)
249
+ let configValueSources = {};
250
+ await Promise.all(objectEntries(configDefinitions)
260
251
  .filter(([configName]) => !isGlobalConfig(configName))
261
252
  .map(async ([configName, configDef]) => {
262
253
  const sources = await resolveConfigValueSources(configName, configDef, interfaceFilesRelevant, userRootDir, importedFilesLoaded);
@@ -264,10 +255,12 @@ async function loadVikeConfig(userRootDir, outDirRoot, isDev, extensions) {
264
255
  return;
265
256
  configValueSources[configName] = sources;
266
257
  }));
258
+ configValueSources = sortConfigValueSources(configValueSources, locationId);
259
+ console.log(JSON.stringify(configValueSources, null, 2));
267
260
  const { routeFilesystem, isErrorPage } = determineRouteFilesystem(locationId, configValueSources);
268
- applyEffectsAll(configValueSources, configDefinitionsRelevant);
269
- const configValuesComputed = getComputed(configValueSources, configDefinitionsRelevant);
270
- const configValues = getConfigValues(configValueSources, configValuesComputed, configDefinitionsRelevant);
261
+ applyEffectsAll(configValueSources, configDefinitions);
262
+ const configValuesComputed = getComputed(configValueSources, configDefinitions);
263
+ const configValues = getConfigValues(configValueSources, configValuesComputed, configDefinitions);
271
264
  const pageConfig = {
272
265
  pageId: locationId,
273
266
  isErrorPage,
@@ -296,7 +289,7 @@ function assertOnBeforeRenderEnv(pageConfig) {
296
289
  assertUsage(!(onBeforeRenderEnv.client && !isClientRouting), `Page ${pageConfig.pageId} has an onBeforeRender() hook with env ${pc.cyan(JSON.stringify(onBeforeRenderEnv))} which doesn't make sense because the page is using Server Routing: onBeforeRender() can be run in the client only when using Client Routing.`);
297
290
  }
298
291
  function interfacefileIsAlreaydLoaded(interfaceFile) {
299
- const configMapValues = Object.values(interfaceFile.configMap);
292
+ const configMapValues = Object.values(interfaceFile.fileExportsByConfigName);
300
293
  const isAlreadyLoaded = configMapValues.some((conf) => 'configValue' in conf);
301
294
  if (isAlreadyLoaded) {
302
295
  assert(configMapValues.every((conf) => 'configValue' in conf));
@@ -304,7 +297,7 @@ function interfacefileIsAlreaydLoaded(interfaceFile) {
304
297
  return isAlreadyLoaded;
305
298
  }
306
299
  function getInterfaceFilesRelevant(interfaceFilesByLocationId, locationIdPage) {
307
- const interfaceFilesRelevant = Object.fromEntries(Object.entries(interfaceFilesByLocationId)
300
+ const interfaceFilesRelevant = Object.fromEntries(objectEntries(interfaceFilesByLocationId)
308
301
  .filter(([locationId]) => {
309
302
  return isInherited(locationId, locationIdPage);
310
303
  })
@@ -319,14 +312,14 @@ function getInterfaceFileList(interfaceFilesByLocationId) {
319
312
  return interfaceFiles;
320
313
  }
321
314
  async function getGlobalConfigs(interfaceFilesByLocationId, userRootDir, importedFilesLoaded) {
322
- const locationIds = Object.keys(interfaceFilesByLocationId);
323
- const interfaceFilesGlobal = Object.fromEntries(Object.entries(interfaceFilesByLocationId).filter(([locationId]) => {
315
+ const locationIds = objectKeys(interfaceFilesByLocationId);
316
+ const interfaceFilesGlobal = objectFromEntries(objectEntries(interfaceFilesByLocationId).filter(([locationId]) => {
324
317
  return isGlobalLocation(locationId, locationIds);
325
318
  }));
326
319
  // Validate that global configs live in global interface files
327
320
  {
328
321
  const interfaceFilesGlobalPaths = [];
329
- Object.entries(interfaceFilesGlobal).forEach(([locationId, interfaceFiles]) => {
322
+ objectEntries(interfaceFilesGlobal).forEach(([locationId, interfaceFiles]) => {
330
323
  assert(isGlobalLocation(locationId, locationIds));
331
324
  interfaceFiles.forEach(({ filePath: { filePathRelativeToUserRootDir } }) => {
332
325
  if (filePathRelativeToUserRootDir) {
@@ -335,9 +328,9 @@ async function getGlobalConfigs(interfaceFilesByLocationId, userRootDir, importe
335
328
  });
336
329
  });
337
330
  const globalPaths = Array.from(new Set(interfaceFilesGlobalPaths.map((p) => path.posix.dirname(p))));
338
- Object.entries(interfaceFilesByLocationId).forEach(([locationId, interfaceFiles]) => {
331
+ objectEntries(interfaceFilesByLocationId).forEach(([locationId, interfaceFiles]) => {
339
332
  interfaceFiles.forEach((interfaceFile) => {
340
- Object.keys(interfaceFile.configMap).forEach((configName) => {
333
+ Object.keys(interfaceFile.fileExportsByConfigName).forEach((configName) => {
341
334
  if (!isGlobalLocation(locationId, locationIds) && isGlobalConfig(configName)) {
342
335
  assertUsage(false, [
343
336
  `${interfaceFile.filePath.filePathToShowToUser} defines the config ${pc.cyan(configName)} which is global:`,
@@ -378,7 +371,7 @@ async function resolveConfigValueSources(configName, configDef, interfaceFilesRe
378
371
  const sourcesInfo = [];
379
372
  // interfaceFilesRelevant is sorted by sortAfterInheritanceOrder()
380
373
  for (const interfaceFiles of Object.values(interfaceFilesRelevant)) {
381
- const interfaceFilesDefiningConfig = interfaceFiles.filter((interfaceFile) => interfaceFile.configMap[configName]);
374
+ const interfaceFilesDefiningConfig = interfaceFiles.filter((interfaceFile) => interfaceFile.fileExportsByConfigName[configName]);
382
375
  if (interfaceFilesDefiningConfig.length === 0)
383
376
  continue;
384
377
  const visited = new WeakSet();
@@ -456,13 +449,15 @@ function isInterfaceFileUserLand(interfaceFile) {
456
449
  return (interfaceFile.isConfigFile && !interfaceFile.isConfigExtend) || interfaceFile.isValueFile;
457
450
  }
458
451
  async function getConfigValueSource(configName, interfaceFile, configDef, userRootDir, importedFilesLoaded) {
459
- const conf = interfaceFile.configMap[configName];
452
+ const conf = interfaceFile.fileExportsByConfigName[configName];
460
453
  assert(conf);
461
454
  const configEnv = configDef.env;
455
+ const { locationId } = interfaceFile;
462
456
  const definedAtConfigFile = {
463
457
  ...interfaceFile.filePath,
464
458
  fileExportPathToShowToUser: ['default', configName]
465
459
  };
460
+ // +client.js
466
461
  if (configDef._valueIsFilePath) {
467
462
  let definedAt;
468
463
  let valueFilePath;
@@ -483,6 +478,7 @@ async function getConfigValueSource(configName, interfaceFile, configDef, userRo
483
478
  };
484
479
  }
485
480
  const configValueSource = {
481
+ locationId,
486
482
  value: valueFilePath,
487
483
  valueIsFilePath: true,
488
484
  configEnv,
@@ -491,22 +487,27 @@ async function getConfigValueSource(configName, interfaceFile, configDef, userRo
491
487
  };
492
488
  return configValueSource;
493
489
  }
490
+ // +config.js
494
491
  if (interfaceFile.isConfigFile) {
495
492
  assert('configValue' in conf);
496
493
  const { configValue } = conf;
494
+ // fake import
497
495
  const import_ = resolveImport(configValue, interfaceFile.filePath, userRootDir, configEnv, configName);
498
496
  if (import_) {
499
497
  const configValueSource = {
498
+ locationId,
500
499
  configEnv,
501
500
  valueIsImportedAtRuntime: true,
502
501
  definedAt: import_
503
502
  };
504
- // Load config value
505
- if (isConfigEnv(configDef, configName)) {
503
+ // Load fake import
504
+ if (isConfigEnv(configDef, configName) &&
505
+ // The value of `extends` was already loaded and already used: we don't need the value of `extends` anymore
506
+ configName !== 'extends') {
506
507
  if (import_.filePathAbsoluteFilesystem) {
507
508
  assert(hasProp(import_, 'filePathAbsoluteFilesystem', 'string')); // Help TS
508
- const fileExports = await loadImportedFile(import_, userRootDir, importedFilesLoaded);
509
- configValueSource.value = fileExports[import_.fileExportName];
509
+ const fileExport = await loadImportedFile(import_, userRootDir, importedFilesLoaded);
510
+ configValueSource.value = fileExport;
510
511
  }
511
512
  else {
512
513
  const configDefinedAt = getConfigDefinedAtString('Config', configName, configValueSource);
@@ -515,20 +516,22 @@ async function getConfigValueSource(configName, interfaceFile, configDef, userRo
515
516
  }
516
517
  return configValueSource;
517
518
  }
518
- else {
519
- const configValueSource = {
520
- value: configValue,
521
- configEnv,
522
- valueIsImportedAtRuntime: false,
523
- definedAt: definedAtConfigFile
524
- };
525
- return configValueSource;
526
- }
519
+ // Defined by config file, i.e. +config.js file
520
+ const configValueSource = {
521
+ locationId,
522
+ value: configValue,
523
+ configEnv,
524
+ valueIsImportedAtRuntime: false,
525
+ definedAt: definedAtConfigFile
526
+ };
527
+ return configValueSource;
527
528
  }
528
- else if (interfaceFile.isValueFile) {
529
+ // Defined by value file, i.e. +{configName}.js
530
+ if (interfaceFile.isValueFile) {
529
531
  const valueAlreadyLoaded = 'configValue' in conf;
530
532
  assert(valueAlreadyLoaded === !!configEnv.config);
531
533
  const configValueSource = {
534
+ locationId,
532
535
  configEnv,
533
536
  valueIsImportedAtRuntime: !valueAlreadyLoaded,
534
537
  definedAt: {
@@ -546,25 +549,9 @@ async function getConfigValueSource(configName, interfaceFile, configDef, userRo
546
549
  }
547
550
  assert(false);
548
551
  }
549
- function assertFileEnv(filePathForEnvCheck, configEnv, configName) {
550
- assertPosixPath(filePathForEnvCheck);
551
- if (!filesEnv.has(filePathForEnvCheck)) {
552
- filesEnv.set(filePathForEnvCheck, []);
553
- }
554
- const fileEnv = filesEnv.get(filePathForEnvCheck);
555
- fileEnv.push({ configEnv, configName });
556
- const configDifferentEnv = fileEnv.filter((c) => !deepEqual(c.configEnv, configEnv))[0];
557
- if (configDifferentEnv) {
558
- assertUsage(false, [
559
- `${filePathForEnvCheck} defines the value of configs living in different environments:`,
560
- ...[configDifferentEnv, { configName, configEnv }].map((c) => ` - config ${pc.cyan(c.configName)} which value lives in environment ${pc.cyan(JSON.stringify(c.configEnv))}`),
561
- 'Defining config values in the same file is allowed only if they live in the same environment, see https://vike.dev/header-file'
562
- ].join('\n'));
563
- }
564
- }
565
552
  function isDefiningPage(interfaceFiles) {
566
553
  for (const interfaceFile of interfaceFiles) {
567
- const configNames = Object.keys(interfaceFile.configMap);
554
+ const configNames = Object.keys(interfaceFile.fileExportsByConfigName);
568
555
  if (configNames.some((configName) => isDefiningPageConfig(configName))) {
569
556
  return true;
570
557
  }
@@ -574,90 +561,13 @@ function isDefiningPage(interfaceFiles) {
574
561
  function isDefiningPageConfig(configName) {
575
562
  return ['Page', 'route'].includes(configName);
576
563
  }
577
- function resolveImport(configValue, importerFilePath, userRootDir, configEnv, configName) {
578
- if (typeof configValue !== 'string')
579
- return null;
580
- const importData = parseImportData(configValue);
581
- if (!importData)
582
- return null;
583
- const { importPath, exportName } = importData;
584
- const filePathAbsoluteFilesystem = resolveImportPath(importData, importerFilePath);
585
- assertFileEnv(filePathAbsoluteFilesystem ?? importPath, configEnv, configName);
586
- const fileExportPathToShowToUser = exportName === 'default' || exportName === configName ? [] : [exportName];
587
- if (importPath.startsWith('.')) {
588
- // We need to resolve relative paths into absolute paths. Because the import paths are included in virtual files:
589
- // ```
590
- // [vite] Internal server error: Failed to resolve import "./onPageTransitionHooks" from "virtual:vike:pageConfigValuesAll:client:/pages/index". Does the file exist?
591
- // ```
592
- assertImportPath(filePathAbsoluteFilesystem, importData, importerFilePath);
593
- const filePathRelativeToUserRootDir = resolveImportPath_relativeToUserRootDir(filePathAbsoluteFilesystem, importData, importerFilePath, userRootDir);
594
- const filePath = {
595
- filePathAbsoluteFilesystem,
596
- filePathRelativeToUserRootDir,
597
- filePathAbsoluteVite: filePathRelativeToUserRootDir,
598
- filePathToShowToUser: filePathRelativeToUserRootDir,
599
- importPathAbsolute: null
600
- };
601
- return {
602
- ...filePath,
603
- fileExportName: exportName,
604
- fileExportPathToShowToUser
605
- };
606
- }
607
- else {
608
- // importPath can be:
609
- // - an npm package import
610
- // - a path alias
611
- const filePath = {
612
- filePathAbsoluteFilesystem,
613
- filePathRelativeToUserRootDir: null,
614
- filePathAbsoluteVite: importPath,
615
- filePathToShowToUser: importPath,
616
- importPathAbsolute: importPath
617
- };
618
- return {
619
- ...filePath,
620
- fileExportName: exportName,
621
- fileExportPathToShowToUser
622
- };
623
- }
624
- }
625
- function resolveImportPath_relativeToUserRootDir(filePathAbsoluteFilesystem, importData, configFilePath, userRootDir) {
626
- assertPosixPath(userRootDir);
627
- let filePathRelativeToUserRootDir;
628
- if (filePathAbsoluteFilesystem.startsWith(userRootDir)) {
629
- filePathRelativeToUserRootDir = getVitePathFromAbsolutePath(filePathAbsoluteFilesystem, userRootDir);
630
- }
631
- else {
632
- assertUsage(false, `${configFilePath.filePathToShowToUser} imports from a relative path ${pc.cyan(importData.importPath)} outside of ${userRootDir} which is forbidden: import from a relative path inside ${userRootDir}, or import from a dependency's package.json#exports entry instead`);
633
- // None of the following works. Seems to be a Vite bug?
634
- // /*
635
- // assert(filePathAbsoluteFilesystem.startsWith('/'))
636
- // filePath = `/@fs${filePathAbsoluteFilesystem}`
637
- // /*/
638
- // filePathRelativeToUserRootDir = path.posix.relative(userRootDir, filePathAbsoluteFilesystem)
639
- // assert(filePathRelativeToUserRootDir.startsWith('../'))
640
- // filePathRelativeToUserRootDir = '/' + filePathRelativeToUserRootDir
641
- // //*/
642
- }
643
- assertPosixPath(filePathRelativeToUserRootDir);
644
- assert(filePathRelativeToUserRootDir.startsWith('/'));
645
- return filePathRelativeToUserRootDir;
646
- }
647
- function getVitePathFromAbsolutePath(filePathAbsoluteFilesystem, root) {
648
- assertPosixPath(filePathAbsoluteFilesystem);
649
- assertPosixPath(root);
650
- assert(filePathAbsoluteFilesystem.startsWith(root));
651
- let vitePath = path.posix.relative(root, filePathAbsoluteFilesystem);
652
- assert(!vitePath.startsWith('/') && !vitePath.startsWith('.'));
653
- vitePath = '/' + vitePath;
654
- return vitePath;
655
- }
656
564
  function getConfigDefinitions(interfaceFilesRelevant) {
657
- const configDefinitions = { ...configDefinitionsBuiltIn };
658
- Object.entries(interfaceFilesRelevant).forEach(([_locationId, interfaceFiles]) => {
565
+ const configDefinitionsMerged = { ...configDefinitionsBuiltIn };
566
+ Object.entries(interfaceFilesRelevant)
567
+ .reverse()
568
+ .forEach(([_locationId, interfaceFiles]) => {
659
569
  interfaceFiles.forEach((interfaceFile) => {
660
- const configMeta = interfaceFile.configMap['meta'];
570
+ const configMeta = interfaceFile.fileExportsByConfigName['meta'];
661
571
  if (!configMeta)
662
572
  return;
663
573
  const meta = configMeta.configValue;
@@ -674,13 +584,14 @@ function getConfigDefinitions(interfaceFilesRelevant) {
674
584
  });
675
585
  objectEntries(meta).forEach(([configName, configDefinition]) => {
676
586
  // User can override an existing config definition
677
- configDefinitions[configName] = {
678
- ...configDefinitions[configName],
587
+ configDefinitionsMerged[configName] = {
588
+ ...configDefinitionsMerged[configName],
679
589
  ...configDefinition
680
590
  };
681
591
  });
682
592
  });
683
593
  });
594
+ const configDefinitions = configDefinitionsMerged;
684
595
  return configDefinitions;
685
596
  }
686
597
  function assertMetaValue(metaVal, configMetaDefinedAt) {
@@ -719,8 +630,8 @@ function assertMetaValue(metaVal, configMetaDefinedAt) {
719
630
  }
720
631
  });
721
632
  }
722
- function applyEffectsAll(configValueSources, configDefinitionsRelevant) {
723
- objectEntries(configDefinitionsRelevant).forEach(([configName, configDef]) => {
633
+ function applyEffectsAll(configValueSources, configDefinitions) {
634
+ objectEntries(configDefinitions).forEach(([configName, configDef]) => {
724
635
  if (!configDef.effect)
725
636
  return;
726
637
  // The value needs to be loaded at config time, that's why we only support effect for configs that are config-only for now.
@@ -779,9 +690,9 @@ function applyEffect(configModFromEffect, configValueSources, configDefEffect) {
779
690
  }
780
691
  });
781
692
  }
782
- function getComputed(configValueSources, configDefinitionsRelevant) {
693
+ function getComputed(configValueSources, configDefinitions) {
783
694
  const configValuesComputed = {};
784
- objectEntries(configDefinitionsRelevant).forEach(([configName, configDef]) => {
695
+ objectEntries(configDefinitions).forEach(([configName, configDef]) => {
785
696
  if (!configDef._computed)
786
697
  return;
787
698
  const value = configDef._computed(configValueSources);
@@ -796,15 +707,7 @@ function getComputed(configValueSources, configDefinitionsRelevant) {
796
707
  }
797
708
  async function findPlusFiles(userRootDir, outDirRoot, isDev, extensions) {
798
709
  const files = await crawlPlusFiles(userRootDir, outDirRoot, isDev);
799
- const plusFiles = files.map(({ filePathRelativeToUserRootDir, filePathAbsoluteFilesystem }) => {
800
- return {
801
- filePathRelativeToUserRootDir,
802
- filePathAbsoluteVite: filePathRelativeToUserRootDir,
803
- filePathAbsoluteFilesystem,
804
- filePathToShowToUser: filePathRelativeToUserRootDir,
805
- importPathAbsolute: null
806
- };
807
- });
710
+ const plusFiles = files.map(({ filePathRelativeToUserRootDir }) => resolveFilePathRelativeToUserRootDir(filePathRelativeToUserRootDir, userRootDir));
808
711
  // TODO/v1-release: remove
809
712
  extensions.forEach((extension) => {
810
713
  extension.pageConfigsDistFiles?.forEach((pageConfigDistFile) => {
@@ -840,125 +743,22 @@ function getConfigName(filePath) {
840
743
  return configName;
841
744
  }
842
745
  }
843
- async function loadConfigFile(configFilePath, userRootDir, visited) {
844
- const { filePathAbsoluteFilesystem } = configFilePath;
845
- assertNoInfiniteLoop(visited, filePathAbsoluteFilesystem);
846
- const { fileExports } = await transpileAndExecuteFile(configFilePath, false, userRootDir);
847
- const { extendsConfigs, extendsFilePaths } = await loadExtendsConfigs(fileExports, configFilePath, userRootDir, [
848
- ...visited,
849
- filePathAbsoluteFilesystem
850
- ]);
851
- const configFile = {
852
- fileExports,
853
- filePath: configFilePath,
854
- extendsFilePaths
855
- };
856
- return { configFile, extendsConfigs };
857
- }
858
- function assertNoInfiniteLoop(visited, filePathAbsoluteFilesystem) {
859
- const idx = visited.indexOf(filePathAbsoluteFilesystem);
860
- if (idx === -1)
861
- return;
862
- const loop = visited.slice(idx);
863
- assert(loop[0] === filePathAbsoluteFilesystem);
864
- assertUsage(idx === -1, `Infinite extends loop ${[...loop, filePathAbsoluteFilesystem].join('>')}`);
865
- }
866
- async function loadExtendsConfigs(configFileExports, configFilePath, userRootDir, visited) {
867
- const extendsImportData = getExtendsImportData(configFileExports, configFilePath);
868
- const extendsConfigFiles = [];
869
- extendsImportData.map((importData) => {
870
- const { importPath: importPath } = importData;
871
- const filePathAbsoluteFilesystem = resolveImportPath(importData, configFilePath);
872
- assertImportPath(filePathAbsoluteFilesystem, importData, configFilePath);
873
- assertExtendsImportPath(importPath, filePathAbsoluteFilesystem, configFilePath);
874
- // - filePathRelativeToUserRootDir has no functionality beyond nicer error messages for user
875
- // - Using importPath would be visually nicer but it's ambigous => we rather pick filePathAbsoluteFilesystem for added clarity
876
- const filePathRelativeToUserRootDir = determineFilePathRelativeToUserDir(filePathAbsoluteFilesystem, userRootDir);
877
- const filePathAbsoluteVite = filePathRelativeToUserRootDir ?? importPath;
878
- extendsConfigFiles.push({
879
- filePathAbsoluteFilesystem,
880
- filePathAbsoluteVite,
881
- filePathRelativeToUserRootDir,
882
- filePathToShowToUser: filePathAbsoluteVite,
883
- importPathAbsolute: importPath
884
- });
885
- });
886
- const extendsConfigs = [];
887
- await Promise.all(extendsConfigFiles.map(async (configFilePath) => {
888
- const result = await loadConfigFile(configFilePath, userRootDir, visited);
889
- extendsConfigs.push(result.configFile);
890
- extendsConfigs.push(...result.extendsConfigs);
891
- }));
892
- const extendsFilePaths = extendsConfigFiles.map((f) => f.filePathAbsoluteFilesystem);
893
- return { extendsConfigs, extendsFilePaths };
894
- }
895
- function determineFilePathRelativeToUserDir(filePathAbsoluteFilesystem, userRootDir) {
896
- assertPosixPath(filePathAbsoluteFilesystem);
897
- assertPosixPath(userRootDir);
898
- if (!filePathAbsoluteFilesystem.startsWith(userRootDir)) {
899
- return null;
900
- }
901
- let filePathRelativeToUserRootDir = filePathAbsoluteFilesystem.slice(userRootDir.length);
902
- if (!filePathRelativeToUserRootDir.startsWith('/'))
903
- filePathRelativeToUserRootDir = '/' + filePathRelativeToUserRootDir;
904
- return filePathRelativeToUserRootDir;
905
- }
906
- function assertExtendsImportPath(importPath, filePath, configFilePath) {
907
- if (isNpmPackageImport(importPath)) {
908
- const fileDir = path.posix.dirname(filePath) + '/';
909
- const fileName = path.posix.basename(filePath);
910
- const fileNameBaseCorrect = '+config';
911
- const [fileNameBase, ...fileNameRest] = fileName.split('.');
912
- const fileNameCorrect = [fileNameBaseCorrect, ...fileNameRest].join('.');
913
- assertWarning(fileNameBase === fileNameBaseCorrect, `Rename ${fileName} to ${fileNameCorrect} in ${fileDir}`, {
914
- onlyOnce: true
915
- });
916
- }
917
- else {
918
- assertWarning(false, `${configFilePath.filePathToShowToUser} uses ${pc.cyan('extends')} to inherit from ${pc.cyan(importPath)} which is a user-land file: this is experimental and may be remove at any time. Reach out to a maintainer if you need this feature.`, { onlyOnce: true });
919
- }
920
- }
921
- function getExtendsImportData(configFileExports, configFilePath) {
922
- const { filePathToShowToUser } = configFilePath;
923
- assertExportsOfConfigFile(configFileExports, filePathToShowToUser);
924
- const defaultExports = configFileExports.default;
925
- const wrongUsage = `${filePathToShowToUser} sets the config ${pc.cyan('extends')} to an invalid value, see https://vike.dev/extends`;
926
- let extendList;
927
- if (!('extends' in defaultExports)) {
928
- return [];
929
- }
930
- else if (hasProp(defaultExports, 'extends', 'string')) {
931
- extendList = [defaultExports.extends];
932
- }
933
- else if (hasProp(defaultExports, 'extends', 'string[]')) {
934
- extendList = defaultExports.extends;
935
- }
936
- else {
937
- assertUsage(false, wrongUsage);
938
- }
939
- const extendsImportData = extendList.map((importDataSerialized) => {
940
- const importData = parseImportData(importDataSerialized);
941
- assertUsage(importData, wrongUsage);
942
- return importData;
943
- });
944
- return extendsImportData;
945
- }
946
- function isGlobalConfig(configName) {
947
- if (configName === 'prerender')
948
- return false;
949
- const configNamesGlobal = getConfigNamesGlobal();
950
- return arrayIncludes(configNamesGlobal, configName);
951
- }
952
- function getConfigNamesGlobal() {
953
- return Object.keys(configDefinitionsBuiltInGlobal);
954
- }
955
- function assertConfigExists(configName, configNamesRelevant, filePathToShowToUser) {
956
- const configNames = [...configNamesRelevant, ...getConfigNamesGlobal()];
957
- if (configNames.includes(configName))
958
- return;
959
- handleUnknownConfig(configName, configNames, filePathToShowToUser);
960
- assert(false);
961
- }
746
+ /* https://github.com/vikejs/vike/issues/1407
747
+ function assertNoUnexpectedPlusSign(filePath: string, fileName: string) {
748
+ const dirs = path.posix.dirname(filePath).split('/')
749
+ dirs.forEach((dir, i) => {
750
+ const dirPath = dirs.slice(0, i + 1).join('/')
751
+ assertUsage(
752
+ !dir.includes('+'),
753
+ `Character '+' is a reserved character: remove '+' from the directory name ${dirPath}/`
754
+ )
755
+ })
756
+ assertUsage(
757
+ !fileName.slice(1).includes('+'),
758
+ `Character '+' is only allowed at the beginning of filenames: make sure ${filePath} doesn't contain any '+' in its filename other than its first letter`
759
+ )
760
+ }
761
+ */
962
762
  function handleUnknownConfig(configName, configNames, filePathToShowToUser) {
963
763
  let errMsg = `${filePathToShowToUser} defines an unknown config ${pc.cyan(configName)}`;
964
764
  let configNameSimilar = null;
@@ -1025,36 +825,10 @@ function determineIsErrorPage(routeFilesystem) {
1025
825
  assertPosixPath(routeFilesystem);
1026
826
  return routeFilesystem.split('/').includes('_error');
1027
827
  }
1028
- function resolveImportPath(importData, importerFilePath) {
1029
- const importerFilePathAbsolute = importerFilePath.filePathAbsoluteFilesystem;
1030
- assertPosixPath(importerFilePathAbsolute);
1031
- const cwd = path.posix.dirname(importerFilePathAbsolute);
1032
- // We can't use import.meta.resolve() as of Junary 2023 (and probably for a lot longer): https://stackoverflow.com/questions/54977743/do-require-resolve-for-es-modules#comment137174954_62272600:~:text=But%20the%20argument%20parent%20(aka%20cwd)%20still%20requires%20a%20flag
1033
- // filePathAbsoluteFilesystem is expected to be null when importData.importPath is a Vite path alias
1034
- const filePathAbsoluteFilesystem = requireResolve(importData.importPath, cwd);
1035
- return filePathAbsoluteFilesystem;
1036
- }
1037
- function assertImportPath(filePathAbsoluteFilesystem, importData, importerFilePath) {
1038
- const { importPath: importPath, importStringWasGenerated, importString } = importData;
1039
- const { filePathToShowToUser } = importerFilePath;
1040
- if (!filePathAbsoluteFilesystem) {
1041
- const importPathString = pc.cyan(`'${importPath}'`);
1042
- const errIntro = importStringWasGenerated
1043
- ? `The import path ${importPathString} in ${filePathToShowToUser}`
1044
- : `The import ${pc.cyan(importString)} defined in ${filePathToShowToUser}`;
1045
- const errIntro2 = `${errIntro} couldn't be resolved: does ${importPathString}`;
1046
- if (importPath.startsWith('.')) {
1047
- assertUsage(false, `${errIntro2} point to an existing file?`);
1048
- }
1049
- else {
1050
- assertUsage(false, `${errIntro2} exist?`);
1051
- }
1052
- }
1053
- }
1054
828
  function isVikeConfigFile(filePath) {
1055
829
  return !!getConfigName(filePath);
1056
830
  }
1057
- function getConfigValues(configValueSources, configValuesComputed, configDefinitionsRelevant) {
831
+ function getConfigValues(configValueSources, configValuesComputed, configDefinitions) {
1058
832
  const configValues = {};
1059
833
  Object.entries(configValuesComputed).forEach(([configName, configValueComputed]) => {
1060
834
  configValues[configName] = {
@@ -1063,7 +837,7 @@ function getConfigValues(configValueSources, configValuesComputed, configDefinit
1063
837
  };
1064
838
  });
1065
839
  Object.entries(configValueSources).forEach(([configName, sources]) => {
1066
- const configDef = configDefinitionsRelevant[configName];
840
+ const configDef = configDefinitions[configName];
1067
841
  assert(configDef);
1068
842
  if (!configDef.cumulative) {
1069
843
  const configValueSource = sources[0];
@@ -1177,3 +951,48 @@ function getConfigEnvValue(val, errMsgIntro) {
1177
951
  */
1178
952
  return val;
1179
953
  }
954
+ function getConfigDefinition(configDefinitions, configName, filePathToShowToUser) {
955
+ const configDef = configDefinitions[configName];
956
+ assertConfigExists(configName, Object.keys(configDefinitions), filePathToShowToUser);
957
+ assert(configDef);
958
+ return configDef;
959
+ }
960
+ function getConfigDefinitionOptional(configDefinitions, configName) {
961
+ return configDefinitions[configName] ?? null;
962
+ }
963
+ function isConfigEnv(configDef, configName) {
964
+ const configEnv = configDef.env;
965
+ if (configDef.cumulative) {
966
+ // In principle we could lift that requirement (but it requires non-trivial modifications)
967
+ assertUsage(configEnv.config, `Config ${pc.cyan(configName)} needs its ${pc.cyan('env')} to have ${pc.cyan('{ config: true }')} (because ${pc.cyan(configName)} is a ${pc.cyan('cumulative')} config)`);
968
+ }
969
+ return !!configEnv.config;
970
+ }
971
+ function isGlobalConfig(configName) {
972
+ if (configName === 'prerender')
973
+ return false;
974
+ const configNamesGlobal = getConfigNamesGlobal();
975
+ return arrayIncludes(configNamesGlobal, configName);
976
+ }
977
+ function getConfigNamesGlobal() {
978
+ return Object.keys(configDefinitionsBuiltInGlobal);
979
+ }
980
+ function assertConfigExists(configName, configNamesRelevant, filePathToShowToUser) {
981
+ const configNames = [...configNamesRelevant, ...getConfigNamesGlobal()];
982
+ if (configNames.includes(configName))
983
+ return;
984
+ handleUnknownConfig(configName, configNames, filePathToShowToUser);
985
+ assert(false);
986
+ }
987
+ function sortConfigValueSources(configValueSources, locationIdPage) {
988
+ return Object.fromEntries(Object.entries(configValueSources)
989
+ // Make order deterministic (no other purpose)
990
+ .sort(([, [source1]], [, [source2]]) => source1.definedAt.filePathAbsoluteVite < source2.definedAt.filePathAbsoluteVite ? -1 : 1)
991
+ // Sort after whether the config value was defined by an npm package
992
+ .sort(makeFirst(([, [source]]) => {
993
+ const { importPathAbsolute } = source.definedAt;
994
+ return !!importPathAbsolute && isNpmPackageImport(importPathAbsolute);
995
+ }))
996
+ // Sort after the filesystem inheritance of the config value
997
+ .sort(([, [source1]], [, [source2]]) => reverse(sortAfterInheritanceOrder(source1.locationId, source2.locationId, locationIdPage))));
998
+ }