vike 0.4.223 → 0.4.224-commit-00ed9fe

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 (183) hide show
  1. package/dist/cjs/node/api/build.js +4 -37
  2. package/dist/cjs/node/api/prepareViteApiCall.js +9 -3
  3. package/dist/cjs/node/plugin/index.js +8 -20
  4. package/dist/cjs/node/plugin/plugins/baseUrls.js +3 -1
  5. package/dist/cjs/node/plugin/plugins/{buildConfig/fixServerAssets.js → build/handleAssetsManifest.js} +130 -52
  6. package/dist/cjs/node/plugin/plugins/build/pluginAutoFullBuild.js +145 -0
  7. package/dist/cjs/node/plugin/plugins/build/pluginBuildApp.js +52 -0
  8. package/dist/cjs/node/plugin/plugins/{buildConfig.js → build/pluginBuildConfig.js} +22 -84
  9. package/dist/cjs/node/plugin/plugins/{buildEntry/index.js → build/pluginBuildEntry.js} +9 -9
  10. package/dist/cjs/node/plugin/plugins/{distFileNames.js → build/pluginDistFileNames.js} +7 -7
  11. package/dist/cjs/node/plugin/plugins/{packageJsonFile.js → build/pluginDistPackageJsonFile.js} +6 -6
  12. package/dist/cjs/node/plugin/plugins/{suppressRollupWarning.js → build/pluginSuppressRollupWarning.js} +3 -3
  13. package/dist/cjs/node/plugin/plugins/build.js +21 -0
  14. package/dist/cjs/node/plugin/plugins/commonConfig.js +22 -4
  15. package/dist/cjs/node/plugin/plugins/devConfig/determineFsAllowList.js +1 -1
  16. package/dist/cjs/node/plugin/plugins/devConfig/determineOptimizeDeps.js +5 -5
  17. package/dist/cjs/node/plugin/plugins/devConfig/index.js +1 -1
  18. package/dist/cjs/node/plugin/plugins/envVars.js +2 -2
  19. package/dist/cjs/node/plugin/plugins/extractAssetsPlugin.js +9 -9
  20. package/dist/cjs/node/plugin/plugins/extractExportNamesPlugin.js +2 -2
  21. package/dist/cjs/node/plugin/plugins/fileEnv.js +5 -2
  22. package/dist/cjs/node/plugin/plugins/importUserCode/getVirtualFileImportUserCode.js +3 -3
  23. package/dist/cjs/node/plugin/plugins/importUserCode/index.js +2 -5
  24. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/assertExtensions.js +5 -5
  25. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/configDefinitionsBuiltIn.js +7 -2
  26. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles/ignorePatternsBuiltIn.js +16 -0
  27. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.js +50 -64
  28. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/filesystemRouting.js +2 -1
  29. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/getPlusFilesAll.js +3 -3
  30. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/transpileAndExecuteFile.js +19 -7
  31. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +277 -212
  32. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/virtual-files/getVirtualFilePageConfigValuesAll.js +4 -4
  33. package/dist/cjs/node/plugin/plugins/previewConfig.js +12 -7
  34. package/dist/cjs/node/plugin/shared/addSsrMiddleware.js +5 -1
  35. package/dist/cjs/node/plugin/shared/findPageFiles.js +3 -3
  36. package/dist/cjs/node/plugin/shared/getOutDirs.js +8 -7
  37. package/dist/cjs/node/plugin/shared/isViteServerBuild.js +47 -0
  38. package/dist/cjs/node/plugin/shared/resolveClientEntriesDev.js +1 -1
  39. package/dist/cjs/node/plugin/utils.js +1 -0
  40. package/dist/cjs/node/prerender/context.js +3 -8
  41. package/dist/cjs/node/prerender/resolvePrerenderConfig.js +30 -21
  42. package/dist/cjs/node/prerender/runPrerender.js +28 -30
  43. package/dist/cjs/node/prerender/utils.js +1 -0
  44. package/dist/cjs/node/runtime/html/stream.js +7 -0
  45. package/dist/cjs/node/runtime/renderPage/createHttpResponse/assertNoInfiniteHttpRedirect.js +13 -5
  46. package/dist/cjs/node/runtime/renderPage/createHttpResponse.js +2 -4
  47. package/dist/cjs/node/runtime/renderPage/logErrorHint.js +13 -2
  48. package/dist/cjs/node/runtime/renderPage.js +6 -10
  49. package/dist/cjs/shared/getPageContextUrlComputed.js +1 -1
  50. package/dist/cjs/shared/page-configs/getConfigValueBuildTime.js +2 -5
  51. package/dist/cjs/shared/page-configs/serialize/parsePageConfigs.js +3 -1
  52. package/dist/cjs/shared/page-configs/serialize/serializeConfigValues.js +20 -9
  53. package/dist/cjs/utils/PROJECT_VERSION.js +1 -1
  54. package/dist/cjs/utils/debug.js +2 -1
  55. package/dist/cjs/utils/findFile.js +1 -1
  56. package/dist/cjs/utils/findPackageJson.js +1 -1
  57. package/dist/cjs/utils/isFilePathAbsoluteFilesystem.js +10 -4
  58. package/dist/cjs/utils/parseUrl-extras.js +1 -0
  59. package/dist/cjs/utils/path.js +1 -0
  60. package/dist/cjs/utils/requireResolve.js +11 -4
  61. package/dist/cjs/utils/sorter.js +0 -3
  62. package/dist/esm/client/client-routing-runtime/index.d.ts +1 -0
  63. package/dist/esm/client/client-routing-runtime/index.js +1 -0
  64. package/dist/esm/client/client-routing-runtime/renderPageClientSide.d.ts +8 -0
  65. package/dist/esm/client/client-routing-runtime/renderPageClientSide.js +10 -1
  66. package/dist/esm/node/api/build.js +4 -4
  67. package/dist/esm/node/api/prepareViteApiCall.js +9 -3
  68. package/dist/esm/node/plugin/index.d.ts +2 -1
  69. package/dist/esm/node/plugin/index.js +4 -17
  70. package/dist/esm/node/plugin/plugins/baseUrls.js +3 -1
  71. package/dist/esm/node/plugin/plugins/build/handleAssetsManifest.d.ts +18 -0
  72. package/dist/esm/node/plugin/plugins/{buildConfig/fixServerAssets.js → build/handleAssetsManifest.js} +131 -53
  73. package/dist/esm/node/plugin/plugins/build/pluginAutoFullBuild.d.ts +5 -0
  74. package/dist/esm/node/plugin/plugins/build/pluginAutoFullBuild.js +140 -0
  75. package/dist/esm/node/plugin/plugins/build/pluginBuildApp.d.ts +3 -0
  76. package/dist/esm/node/plugin/plugins/build/pluginBuildApp.js +50 -0
  77. package/dist/esm/node/plugin/plugins/{buildConfig.d.ts → build/pluginBuildConfig.d.ts} +3 -3
  78. package/dist/esm/node/plugin/plugins/{buildConfig.js → build/pluginBuildConfig.js} +22 -81
  79. package/dist/esm/node/plugin/plugins/build/pluginBuildEntry.d.ts +7 -0
  80. package/dist/esm/node/plugin/plugins/{buildEntry/index.js → build/pluginBuildEntry.js} +9 -9
  81. package/dist/esm/node/plugin/plugins/build/pluginDistFileNames.d.ts +3 -0
  82. package/dist/esm/node/plugin/plugins/{distFileNames.js → build/pluginDistFileNames.js} +7 -7
  83. package/dist/esm/node/plugin/plugins/build/pluginDistPackageJsonFile.d.ts +3 -0
  84. package/dist/esm/node/plugin/plugins/{packageJsonFile.js → build/pluginDistPackageJsonFile.js} +7 -6
  85. package/dist/esm/node/plugin/plugins/build/pluginSuppressRollupWarning.d.ts +3 -0
  86. package/dist/esm/node/plugin/plugins/{suppressRollupWarning.js → build/pluginSuppressRollupWarning.js} +3 -3
  87. package/dist/esm/node/plugin/plugins/build.d.ts +3 -0
  88. package/dist/esm/node/plugin/plugins/build.js +19 -0
  89. package/dist/esm/node/plugin/plugins/commonConfig.d.ts +16 -6
  90. package/dist/esm/node/plugin/plugins/commonConfig.js +22 -4
  91. package/dist/esm/node/plugin/plugins/devConfig/determineFsAllowList.js +1 -1
  92. package/dist/esm/node/plugin/plugins/devConfig/determineOptimizeDeps.js +5 -5
  93. package/dist/esm/node/plugin/plugins/devConfig/index.js +1 -1
  94. package/dist/esm/node/plugin/plugins/envVars.js +2 -2
  95. package/dist/esm/node/plugin/plugins/extractAssetsPlugin.js +10 -10
  96. package/dist/esm/node/plugin/plugins/extractExportNamesPlugin.js +2 -2
  97. package/dist/esm/node/plugin/plugins/fileEnv.js +5 -2
  98. package/dist/esm/node/plugin/plugins/importUserCode/getVirtualFileImportUserCode.js +3 -3
  99. package/dist/esm/node/plugin/plugins/importUserCode/index.js +2 -5
  100. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/assertExtensions.js +5 -5
  101. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/configDefinitionsBuiltIn.js +7 -2
  102. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles/ignorePatternsBuiltIn.d.ts +1 -0
  103. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles/ignorePatternsBuiltIn.js +13 -0
  104. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.d.ts +1 -1
  105. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.js +50 -64
  106. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/filesystemRouting.js +2 -1
  107. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/getPlusFilesAll.js +3 -3
  108. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/transpileAndExecuteFile.d.ts +0 -1
  109. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/transpileAndExecuteFile.js +20 -8
  110. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.d.ts +8 -6
  111. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +279 -214
  112. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/virtual-files/getVirtualFilePageConfigValuesAll.js +4 -4
  113. package/dist/esm/node/plugin/plugins/previewConfig.js +12 -7
  114. package/dist/esm/node/plugin/shared/addSsrMiddleware.d.ts +1 -1
  115. package/dist/esm/node/plugin/shared/addSsrMiddleware.js +5 -1
  116. package/dist/esm/node/plugin/shared/findPageFiles.js +3 -3
  117. package/dist/esm/node/plugin/shared/getHttpRequestAsyncStore.js +1 -3
  118. package/dist/esm/node/plugin/shared/getOutDirs.d.ts +2 -2
  119. package/dist/esm/node/plugin/shared/getOutDirs.js +8 -7
  120. package/dist/esm/node/plugin/shared/isViteServerBuild.d.ts +15 -0
  121. package/dist/esm/node/plugin/shared/isViteServerBuild.js +45 -0
  122. package/dist/esm/node/plugin/shared/resolveClientEntriesDev.js +1 -1
  123. package/dist/esm/node/plugin/utils.d.ts +1 -0
  124. package/dist/esm/node/plugin/utils.js +1 -0
  125. package/dist/esm/node/prerender/context.d.ts +0 -2
  126. package/dist/esm/node/prerender/context.js +4 -9
  127. package/dist/esm/node/prerender/resolvePrerenderConfig.d.ts +11 -6
  128. package/dist/esm/node/prerender/resolvePrerenderConfig.js +31 -22
  129. package/dist/esm/node/prerender/runPrerender.d.ts +7 -25
  130. package/dist/esm/node/prerender/runPrerender.js +29 -31
  131. package/dist/esm/node/prerender/utils.d.ts +1 -0
  132. package/dist/esm/node/prerender/utils.js +1 -0
  133. package/dist/esm/node/runtime/globalContext.d.ts +3 -2
  134. package/dist/esm/node/runtime/html/stream.js +7 -0
  135. package/dist/esm/node/runtime/renderPage/createHttpResponse/assertNoInfiniteHttpRedirect.d.ts +3 -1
  136. package/dist/esm/node/runtime/renderPage/createHttpResponse/assertNoInfiniteHttpRedirect.js +14 -6
  137. package/dist/esm/node/runtime/renderPage/createHttpResponse.d.ts +3 -1
  138. package/dist/esm/node/runtime/renderPage/createHttpResponse.js +2 -4
  139. package/dist/esm/node/runtime/renderPage/logErrorHint.js +13 -2
  140. package/dist/esm/node/runtime/renderPage/renderPageAlreadyRouted.d.ts +165 -5
  141. package/dist/esm/node/runtime/renderPage.js +7 -11
  142. package/dist/esm/shared/getPageContextUrlComputed.js +1 -1
  143. package/dist/esm/shared/page-configs/Config.d.ts +12 -2
  144. package/dist/esm/shared/page-configs/PageConfig.d.ts +5 -5
  145. package/dist/esm/shared/page-configs/getConfigValueBuildTime.js +2 -5
  146. package/dist/esm/shared/page-configs/serialize/parsePageConfigs.js +3 -1
  147. package/dist/esm/shared/page-configs/serialize/serializeConfigValues.d.ts +2 -0
  148. package/dist/esm/shared/page-configs/serialize/serializeConfigValues.js +20 -9
  149. package/dist/esm/types/index.d.ts +2 -0
  150. package/dist/esm/utils/PROJECT_VERSION.d.ts +1 -1
  151. package/dist/esm/utils/PROJECT_VERSION.js +1 -1
  152. package/dist/esm/utils/debug.js +2 -1
  153. package/dist/esm/utils/findFile.js +1 -1
  154. package/dist/esm/utils/findPackageJson.js +1 -1
  155. package/dist/esm/utils/isFilePathAbsoluteFilesystem.js +8 -2
  156. package/dist/esm/utils/parseUrl-extras.js +1 -0
  157. package/dist/esm/utils/path.js +1 -0
  158. package/dist/esm/utils/projectInfo.d.ts +1 -1
  159. package/dist/esm/utils/requireResolve.js +11 -4
  160. package/dist/esm/utils/sorter.d.ts +18 -5
  161. package/dist/esm/utils/sorter.js +0 -3
  162. package/package.json +9 -16
  163. package/dist/cjs/node/plugin/plugins/autoFullBuild.js +0 -119
  164. package/dist/cjs/node/plugin/plugins/buildApp.js +0 -76
  165. package/dist/cjs/node/plugin/plugins/removeRequireHookPlugin.js +0 -17
  166. package/dist/cjs/node/plugin/shared/getFullBuildInlineConfig.js +0 -20
  167. package/dist/cjs/node/plugin/shared/viteIsSSR.js +0 -31
  168. package/dist/esm/node/plugin/plugins/autoFullBuild.d.ts +0 -3
  169. package/dist/esm/node/plugin/plugins/autoFullBuild.js +0 -114
  170. package/dist/esm/node/plugin/plugins/buildApp.d.ts +0 -3
  171. package/dist/esm/node/plugin/plugins/buildApp.js +0 -74
  172. package/dist/esm/node/plugin/plugins/buildConfig/fixServerAssets.d.ts +0 -20
  173. package/dist/esm/node/plugin/plugins/buildEntry/index.d.ts +0 -8
  174. package/dist/esm/node/plugin/plugins/distFileNames.d.ts +0 -3
  175. package/dist/esm/node/plugin/plugins/packageJsonFile.d.ts +0 -3
  176. package/dist/esm/node/plugin/plugins/removeRequireHookPlugin.d.ts +0 -3
  177. package/dist/esm/node/plugin/plugins/removeRequireHookPlugin.js +0 -15
  178. package/dist/esm/node/plugin/plugins/suppressRollupWarning.d.ts +0 -3
  179. package/dist/esm/node/plugin/shared/getFullBuildInlineConfig.d.ts +0 -2
  180. package/dist/esm/node/plugin/shared/getFullBuildInlineConfig.js +0 -17
  181. package/dist/esm/node/plugin/shared/viteIsSSR.d.ts +0 -11
  182. package/dist/esm/node/plugin/shared/viteIsSSR.js +0 -29
  183. package/dist-cjs-fixup.mjs +0 -41
@@ -5,7 +5,8 @@ export { vikeConfigDependencies };
5
5
  export { isV1Design };
6
6
  export { getConfVal };
7
7
  export { getConfigDefinitionOptional };
8
- import { assertPosixPath, assert, isObject, assertUsage, assertWarning, objectEntries, hasProp, includes, assertIsNotProductionRuntime, getMostSimilar, joinEnglish, assertKeys, objectKeys, objectFromEntries, unique, isCallable, makeFirst, lowerFirst } from '../../../utils.js';
8
+ export { isOverriden };
9
+ import { assertPosixPath, assert, isObject, assertUsage, assertWarning, objectEntries, hasProp, includes, assertIsNotProductionRuntime, getMostSimilar, joinEnglish, assertKeys, objectKeys, objectFromEntries, unique, isCallable, makeFirst, lowerFirst, makeLast } from '../../../utils.js';
9
10
  import { configDefinitionsBuiltIn } from './getVikeConfig/configDefinitionsBuiltIn.js';
10
11
  import { getLocationId, getFilesystemRouteString, getFilesystemRouteDefinedBy, isInherited, sortAfterInheritanceOrder, applyFilesystemRoutingRootEffect } from './getVikeConfig/filesystemRouting.js';
11
12
  import { isVikeConfigInvalid, isVikeConfigInvalid_set } from '../../../../runtime/renderPage/isVikeConfigInvalid.js';
@@ -20,7 +21,7 @@ import { getFilePathResolved } from '../../../shared/getFilePath.js';
20
21
  import { getConfigValueBuildTime } from '../../../../../shared/page-configs/getConfigValueBuildTime.js';
21
22
  import { assertExtensionsRequire } from './getVikeConfig/assertExtensions.js';
22
23
  import { getPageConfigGlobalUserFriendly, getPageConfigUserFriendly } from '../../../../../shared/page-configs/getPageConfigUserFriendly.js';
23
- import { getConfigValuesBase } from '../../../../../shared/page-configs/serialize/serializeConfigValues.js';
24
+ import { getConfigValuesBase, isJsonValue } from '../../../../../shared/page-configs/serialize/serializeConfigValues.js';
24
25
  import { getPlusFilesAll } from './getVikeConfig/getPlusFilesAll.js';
25
26
  assertIsNotProductionRuntime();
26
27
  let restartVite = false;
@@ -67,6 +68,7 @@ async function handleReloadSideEffects() {
67
68
  }
68
69
  }
69
70
  }
71
+ // TODO/soon: predominantly use getVikeConfigPublic() instead of getVikeConfig() then maybe refector?
70
72
  async function getVikeConfig(config, { doNotRestartViteOnError } = {}) {
71
73
  const userRootDir = config.root;
72
74
  const vikeVitePluginOptions = config._vikeVitePluginOptions;
@@ -85,8 +87,9 @@ async function getVikeConfigEntry(userRootDir, isDev, vikeVitePluginOptions, doN
85
87
  }
86
88
  return await vikeConfigPromise;
87
89
  }
88
- async function isV1Design(config) {
89
- const vikeConfig = await getVikeConfig(config);
90
+ function isV1Design(config) {
91
+ const vikeConfig = config._vikeConfigObject;
92
+ assert(vikeConfig);
90
93
  const { pageConfigs } = vikeConfig;
91
94
  const isV1Design = pageConfigs.length > 0;
92
95
  return isV1Design;
@@ -140,7 +143,7 @@ async function loadVikeConfig(userRootDir, vikeVitePluginOptions) {
140
143
  const configDefinitionsResolved = await resolveConfigDefinitions(plusFilesAll, userRootDir, esbuildCache);
141
144
  assertKnownConfigs(configDefinitionsResolved, plusFilesAll);
142
145
  const { pageConfigGlobal, pageConfigs } = getPageConfigsBuildTime(configDefinitionsResolved, plusFilesAll, userRootDir);
143
- // interop vike(options) in vite.config.js
146
+ // Backwards compatibility for vike(options) in vite.config.js
144
147
  temp_interopVikeVitePlugin(pageConfigGlobal, vikeVitePluginOptions, userRootDir);
145
148
  // global
146
149
  const pageConfigGlobalValues = getConfigValues(pageConfigGlobal);
@@ -153,16 +156,23 @@ async function loadVikeConfig(userRootDir, vikeVitePluginOptions) {
153
156
  return { pageConfigs, pageConfigGlobal, global, pages };
154
157
  }
155
158
  async function resolveConfigDefinitions(plusFilesAll, userRootDir, esbuildCache) {
159
+ const plusFilesAllOrdered = Object.values(plusFilesAll)
160
+ .flat()
161
+ .sort((plusFile1, plusFile2) => sortAfterInheritanceOrderGlobal(plusFile1, plusFile2, plusFilesAll, null));
156
162
  const configDefinitionsGlobal = getConfigDefinitions(
157
- // We use `plusFilesAll` in order to allow local Vike extensions to create global configs.
158
- sortForGlobal(plusFilesAll), (configDef) => !!configDef.global);
163
+ // We use `plusFilesAll` in order to allow local Vike extensions to create global configs, and to set the value of global configs such as `+vite` (enabling Vike extensions to add Vite plugins).
164
+ plusFilesAllOrdered, (configDef) => !!configDef.global);
159
165
  await loadCustomConfigBuildTimeFiles(plusFilesAll, configDefinitionsGlobal, userRootDir, esbuildCache);
160
166
  const configDefinitionsLocal = {};
161
- await Promise.all(objectEntries(plusFilesAll).map(async ([locationId, plusFiles]) => {
162
- const plusFilesRelevant = getPlusFilesRelevant(plusFilesAll, locationId);
167
+ await Promise.all(objectEntries(plusFilesAll).map(async ([locationIdPage, plusFiles]) => {
168
+ const plusFilesRelevant = objectEntries(plusFilesAll)
169
+ .filter(([locationId]) => isInherited(locationId, locationIdPage))
170
+ .map(([, plusFiles]) => plusFiles)
171
+ .flat()
172
+ .sort((plusFile1, plusFile2) => sortAfterInheritanceOrderPage(plusFile1, plusFile2, locationIdPage, null));
163
173
  const configDefinitions = getConfigDefinitions(plusFilesRelevant, (configDef) => configDef.global !== true);
164
174
  await loadCustomConfigBuildTimeFiles(plusFiles, configDefinitions, userRootDir, esbuildCache);
165
- configDefinitionsLocal[locationId] = { configDefinitions, plusFiles, plusFilesRelevant };
175
+ configDefinitionsLocal[locationIdPage] = { configDefinitions, plusFiles, plusFilesRelevant };
166
176
  }));
167
177
  const configDefinitionsResolved = {
168
178
  configDefinitionsGlobal,
@@ -192,12 +202,15 @@ function getPageConfigsBuildTime(configDefinitionsResolved, plusFilesAll, userRo
192
202
  };
193
203
  objectEntries(configDefinitionsResolved.configDefinitionsGlobal).forEach(([configName, configDef]) => {
194
204
  const sources = resolveConfigValueSources(configName, configDef,
195
- // We use `plusFilesAll` in order to allow local Vike extensions to set the value of global configs (e.g. `vite`).
196
- sortForGlobal(plusFilesAll), userRootDir, true);
205
+ // We use `plusFilesAll` in order to allow local Vike extensions to create global configs, and to set the value of global configs such as `+vite` (enabling Vike extensions to add Vite plugins).
206
+ Object.values(plusFilesAll).flat(), userRootDir, true);
197
207
  if (sources.length === 0)
198
208
  return;
199
209
  pageConfigGlobal.configValueSources[configName] = sources;
200
210
  });
211
+ applyEffectsMetaEnv(pageConfigGlobal.configValueSources, configDefinitionsResolved.configDefinitionsGlobal);
212
+ applyEffectsConfVal(pageConfigGlobal.configValueSources, configDefinitionsResolved.configDefinitionsGlobal);
213
+ sortConfigValueSources(pageConfigGlobal.configValueSources, null);
201
214
  assertPageConfigGlobal(pageConfigGlobal, plusFilesAll);
202
215
  const pageConfigs = objectEntries(configDefinitionsResolved.configDefinitionsLocal)
203
216
  .filter(([_locationId, { plusFiles }]) => isDefiningPage(plusFiles))
@@ -208,13 +221,14 @@ function getPageConfigsBuildTime(configDefinitionsResolved, plusFilesAll, userRo
208
221
  .filter(([_configName, configDef]) => configDef.global !== true)
209
222
  .forEach(([configName, configDef]) => {
210
223
  const sources = resolveConfigValueSources(configName, configDef, plusFilesRelevant, userRootDir, false);
211
- // sortConfigValueSources(sources, locationId)
212
224
  if (sources.length === 0)
213
225
  return;
214
226
  configValueSources[configName] = sources;
215
227
  });
216
228
  const pageConfigRoute = determineRouteFilesystem(locationId, configValueSources);
217
- applyEffectsAll(configValueSources, configDefinitionsLocal);
229
+ applyEffectsMetaEnv(configValueSources, configDefinitionsLocal);
230
+ applyEffectsConfVal(configValueSources, configDefinitionsLocal);
231
+ sortConfigValueSources(configValueSources, locationId);
218
232
  const configValuesComputed = getComputed(configValueSources, configDefinitionsLocal);
219
233
  const pageConfig = {
220
234
  pageId: locationId,
@@ -351,110 +365,122 @@ function temp_interopVikeVitePlugin(pageConfigGlobal, vikeVitePluginOptions, use
351
365
  },
352
366
  locationId: '/',
353
367
  plusFile: null,
354
- isOverriden: configDef.cumulative ? false : sources.length > 0,
355
- valueIsImportedAtRuntime: false,
356
- valueIsDefinedByPlusFile: false
368
+ valueIsLoadedWithImport: false,
369
+ valueIsDefinedByPlusValueFile: false
357
370
  });
358
371
  });
359
372
  }
360
- function getPlusFilesRelevant(plusFilesAll, locationIdPage) {
361
- const plusFilesRelevant = Object.fromEntries(objectEntries(plusFilesAll)
362
- .filter(([locationId]) => {
363
- return isInherited(locationId, locationIdPage);
364
- })
365
- // Sort after config inheritance.
366
- // - Together with getPlusFilesOrdered() this implements the whole order of config inheritance.
367
- // - See sortForGlobal() for global configs order.
368
- .sort(([locationId1], [locationId2]) => sortAfterInheritanceOrder(locationId1, locationId2, locationIdPage)));
369
- return plusFilesRelevant;
370
- }
371
- function sortForGlobal(plusFilesAll) {
372
- const plusFilesAllSorted = Object.fromEntries(objectEntries(plusFilesAll)
373
- .sort(lowerFirst(([locationId]) => locationId.split('/').length))
374
- .sort(makeFirst(([locationId]) => isGlobalLocation(locationId, plusFilesAll))));
375
- return plusFilesAllSorted;
373
+ function sortConfigValueSources(configValueSources, locationIdPage) {
374
+ Object.entries(configValueSources).forEach(([configName, sources]) => {
375
+ sources
376
+ .sort((source1, source2) => {
377
+ if (!source1.plusFile || !source2.plusFile)
378
+ return 0;
379
+ const isGlobal = !locationIdPage;
380
+ if (isGlobal) {
381
+ return sortAfterInheritanceOrderGlobal(source1.plusFile, source2.plusFile, null, configName);
382
+ }
383
+ else {
384
+ return sortAfterInheritanceOrderPage(source1.plusFile, source2.plusFile, locationIdPage, configName);
385
+ }
386
+ })
387
+ // TODO/next-major: remove
388
+ // Interop with vike(options) in vite.config.js — make it least precedence.
389
+ .sort(makeLast((source) => !source.plusFile));
390
+ });
391
+ }
392
+ function sortAfterInheritanceOrderPage(plusFile1, plusFile2, locationIdPage, configName) {
393
+ {
394
+ const ret = sortAfterInheritanceOrder(plusFile1.locationId, plusFile2.locationId, locationIdPage);
395
+ if (ret !== 0)
396
+ return ret;
397
+ assert(plusFile1.locationId === plusFile2.locationId);
398
+ }
399
+ if (configName) {
400
+ const ret = sortPlusFilesSameLocationId(plusFile1, plusFile2, configName);
401
+ if (ret !== 0)
402
+ return ret;
403
+ }
404
+ return 0;
405
+ }
406
+ function sortAfterInheritanceOrderGlobal(plusFile1, plusFile2, plusFilesAll, configName) {
407
+ if (plusFilesAll) {
408
+ const ret = makeFirst((plusFile) => isGlobalLocation(plusFile.locationId, plusFilesAll))(plusFile1, plusFile2);
409
+ if (ret !== 0)
410
+ return ret;
411
+ }
412
+ {
413
+ const ret = lowerFirst((plusFile) => plusFile.locationId.split('/').length)(plusFile1, plusFile2);
414
+ if (ret !== 0)
415
+ return ret;
416
+ }
417
+ if (plusFile1.locationId !== plusFile2.locationId) {
418
+ // Same as `sort()` in `['some', 'string', 'array'].sort()`
419
+ return plusFile1.locationId > plusFile2.locationId ? 1 : -1;
420
+ }
421
+ if (configName) {
422
+ assert(plusFile1.locationId === plusFile2.locationId);
423
+ const ret = sortPlusFilesSameLocationId(plusFile1, plusFile2, configName);
424
+ if (ret !== 0)
425
+ return ret;
426
+ }
427
+ return 0;
428
+ }
429
+ function sortPlusFilesSameLocationId(plusFile1, plusFile2, configName) {
430
+ assert(plusFile1.locationId === plusFile2.locationId);
431
+ assert(isDefiningConfig(plusFile1, configName));
432
+ assert(isDefiningConfig(plusFile2, configName));
433
+ // Config set by extensions (lowest precedence)
434
+ {
435
+ const ret = makeLast((plusFile) => !!plusFile.isExtensionConfig)(plusFile1, plusFile2);
436
+ if (ret !== 0)
437
+ return ret;
438
+ }
439
+ // Config set by side-export (lower precedence)
440
+ {
441
+ // - For example `export { frontmatter }` of `.mdx` files.
442
+ // - This only considers side-export configs that are already loaded at build-time. (E.g. it actually doesn't consider `export { frontmatter }` of .mdx files since .mdx files are loaded only at runtime.)
443
+ const ret = makeLast((plusFile) => !plusFile.isConfigFile &&
444
+ // Is side-export
445
+ plusFile.configName !== configName)(plusFile1, plusFile2);
446
+ if (ret !== 0)
447
+ return ret;
448
+ }
449
+ // Config set by +config.js
450
+ {
451
+ const ret = makeLast((plusFile) => plusFile.isConfigFile)(plusFile1, plusFile2);
452
+ if (ret !== 0)
453
+ return ret;
454
+ }
455
+ // Config set by +{configName}.js (highest precedence)
456
+ // No need to make it deterministic: the overall order is arleady deterministic, see sortMakeDeterministic() at getPlusFilesAll()
457
+ return 0;
376
458
  }
377
459
  function resolveConfigValueSources(configName, configDef, plusFilesRelevant, userRootDir, isGlobal) {
378
- const plusFilesOrdered = getPlusFilesOrdered(configName, plusFilesRelevant);
379
- let sources = plusFilesOrdered.map((plusFile, i) => {
380
- const isHighestInheritancePrecedence = i === 0;
381
- const configValueSource = getConfigValueSource(configName, plusFile, configDef, userRootDir, isHighestInheritancePrecedence);
382
- return configValueSource;
383
- });
384
- if (isCallable(configDef.global)) {
385
- const isGlobalValue = configDef.global;
460
+ let sources = plusFilesRelevant
461
+ .filter((plusFile) => isDefiningConfig(plusFile, configName))
462
+ .map((plusFile) => getConfigValueSource(configName, plusFile, configDef, userRootDir));
463
+ // Filter hydrid global-local configs
464
+ if (!isCallable(configDef.global)) {
465
+ // Already filtered
466
+ assert((configDef.global ?? false) === isGlobal);
467
+ }
468
+ else {
469
+ // We cannot filter earlier
386
470
  assert(configDef.env.config);
387
471
  sources = sources.filter((source) => {
388
472
  assert(source.configEnv.config);
389
473
  assert(source.valueIsLoaded);
390
- const valueIsGlobal = isGlobalValue(source.value);
474
+ const valueIsGlobal = resolveIsGlobalValue(configDef.global, source.value);
391
475
  return isGlobal ? valueIsGlobal : !valueIsGlobal;
392
476
  });
393
477
  }
394
478
  return sources;
395
479
  }
396
- // Together with sortAfterInheritanceOrder() this implements the whole order of config inheritance.
397
- function getPlusFilesOrdered(configName, plusFilesRelevant) {
398
- const plusFilesOrdered = [];
399
- // `plusFilesRelevant` is already sorted by sortAfterInheritanceOrder() at getPlusFilesRelevant()
400
- // `plusFilesAtLocationId` is already sorted by sortMakeDeterministic() at getPlusFilesAll()
401
- for (const plusFilesAtLocationId of Object.values(plusFilesRelevant)) {
402
- const plusFilesForConfigName = plusFilesAtLocationId.filter((plusFile) => getDefiningConfigNames(plusFile).includes(configName));
403
- // We populate `plusFilesOrdered` with inheritance order.
404
- const populate = (plusFile) => {
405
- assert(!visited.has(plusFile));
406
- visited.add(plusFile);
407
- plusFilesOrdered.push(plusFile);
408
- };
409
- const visited = new WeakSet();
410
- // ========================
411
- // User-land config (first)
412
- // ========================
413
- {
414
- const plusFilesValue = plusFilesForConfigName.filter((plusFile) => !plusFile.isConfigFile &&
415
- // We consider side-effect configs (e.g. `export { frontmatter }` of .mdx files) later (i.e. with less priority)
416
- plusFile.configName === configName);
417
- const plusFilesConfig = plusFilesForConfigName.filter((plusFile) => plusFile.isConfigFile &&
418
- // We consider extensions (e.g. vike-react) later (i.e. with less priority)
419
- !plusFile.isExtensionConfig);
420
- [...plusFilesValue, ...plusFilesConfig].forEach((plusFile) => {
421
- assert(plusFile.filePath.filePathAbsoluteUserRootDir); // ensure it's a user-land plus file
422
- populate(plusFile);
423
- });
424
- }
425
- // ==========================
426
- // Side-effect configs (next)
427
- // ==========================
428
- // - For example `export { frontmatter }` of `.mdx` files.
429
- // - This only considers side-effect configs that are already loaded at build-time. (E.g. it actually doesn't consider `export { frontmatter }` of .mdx files since .mdx files are loaded only at runtime.)
430
- plusFilesForConfigName
431
- .filter((plusFile) => !plusFile.isConfigFile &&
432
- // Is side-effect config
433
- plusFile.configName !== configName)
434
- .forEach((plusFile) => {
435
- assert(plusFile.filePath.filePathAbsoluteUserRootDir); // ensure it's a user-land plus file
436
- populate(plusFile);
437
- });
438
- // ========================
439
- // Extensions config (last)
440
- // ========================
441
- plusFilesForConfigName
442
- .filter((plusFile) => plusFile.isConfigFile && plusFile.isExtensionConfig)
443
- // Extension config files are already sorted by inheritance order
444
- .forEach((plusFile) => {
445
- assert(!plusFile.filePath.filePathAbsoluteUserRootDir); // ensure it isn't a user-land plus file
446
- populate(plusFile);
447
- });
448
- // ======
449
- // Assert we didn't miss any config.
450
- // ======
451
- plusFilesForConfigName.forEach((plusFile) => {
452
- assert(visited.has(plusFile));
453
- });
454
- }
455
- return plusFilesOrdered;
480
+ function isDefiningConfig(plusFile, configName) {
481
+ return getDefiningConfigNames(plusFile).includes(configName);
456
482
  }
457
- function getConfigValueSource(configName, plusFile, configDef, userRootDir, isHighestInheritancePrecedence) {
483
+ function getConfigValueSource(configName, plusFile, configDef, userRootDir) {
458
484
  const confVal = getConfVal(plusFile, configName);
459
485
  assert(confVal);
460
486
  const configValueSourceCommon = {
@@ -465,15 +491,14 @@ function getConfigValueSource(configName, plusFile, configDef, userRootDir, isHi
465
491
  ...plusFile.filePath,
466
492
  fileExportPathToShowToUser: ['default', configName]
467
493
  };
468
- const isOverriden = configDef.cumulative ? false : !isHighestInheritancePrecedence;
469
494
  // +client.js
470
495
  if (configDef._valueIsFilePath) {
471
496
  let definedAtFilePath;
472
497
  let valueFilePath;
473
498
  if (plusFile.isConfigFile) {
474
499
  // Defined over pointer import
475
- assert(confVal.configValueLoaded);
476
- const pointerImport = resolvePointerImport(confVal.configValue, plusFile.filePath, userRootDir, configName);
500
+ assert(confVal.valueIsLoaded);
501
+ const pointerImport = resolvePointerImport(confVal.value, plusFile.filePath, userRootDir, configName);
477
502
  const configDefinedAt = getConfigDefinedAt('Config', configName, definedAtFilePath_);
478
503
  assertUsage(pointerImport, `${configDefinedAt} should be an import`);
479
504
  valueFilePath = pointerImport.fileExportPath.filePathAbsoluteVite;
@@ -494,17 +519,15 @@ function getConfigValueSource(configName, plusFile, configDef, userRootDir, isHi
494
519
  value: valueFilePath,
495
520
  valueIsFilePath: true,
496
521
  configEnv: configDef.env,
497
- valueIsImportedAtRuntime: true,
498
- valueIsDefinedByPlusFile: false,
499
- isOverriden,
522
+ valueIsLoadedWithImport: false,
523
+ valueIsDefinedByPlusValueFile: false,
500
524
  definedAtFilePath
501
525
  };
502
526
  return configValueSource;
503
527
  }
504
528
  // +config.js
505
529
  if (plusFile.isConfigFile) {
506
- assert(confVal.configValueLoaded);
507
- const { configValue } = confVal;
530
+ assert(confVal.valueIsLoaded);
508
531
  // Defined over pointer import
509
532
  const pointerImport = plusFile.pointerImportsByConfigName[configName];
510
533
  if (pointerImport) {
@@ -520,9 +543,8 @@ function getConfigValueSource(configName, plusFile, configDef, userRootDir, isHi
520
543
  ...configValueSourceCommon,
521
544
  ...value,
522
545
  configEnv: resolveConfigEnv(configDef.env, pointerImport.fileExportPath),
523
- valueIsImportedAtRuntime: true,
524
- valueIsDefinedByPlusFile: false,
525
- isOverriden,
546
+ valueIsLoadedWithImport: true,
547
+ valueIsDefinedByPlusValueFile: false,
526
548
  definedAtFilePath: pointerImport.fileExportPath
527
549
  };
528
550
  return configValueSource;
@@ -531,11 +553,10 @@ function getConfigValueSource(configName, plusFile, configDef, userRootDir, isHi
531
553
  const configValueSource = {
532
554
  ...configValueSourceCommon,
533
555
  valueIsLoaded: true,
534
- value: configValue,
556
+ value: confVal.value,
535
557
  configEnv: configDef.env,
536
- valueIsImportedAtRuntime: false,
537
- valueIsDefinedByPlusFile: false,
538
- isOverriden,
558
+ valueIsLoadedWithImport: false,
559
+ valueIsDefinedByPlusValueFile: false,
539
560
  definedAtFilePath: definedAtFilePath_
540
561
  };
541
562
  return configValueSource;
@@ -543,23 +564,13 @@ function getConfigValueSource(configName, plusFile, configDef, userRootDir, isHi
543
564
  // Defined by value file, i.e. +{configName}.js
544
565
  if (!plusFile.isConfigFile) {
545
566
  const configEnvResolved = resolveConfigEnv(configDef.env, plusFile.filePath);
546
- const valueAlreadyLoaded = confVal.configValueLoaded;
547
- assert(valueAlreadyLoaded === !!configEnvResolved.config);
548
- const value = valueAlreadyLoaded
549
- ? {
550
- valueIsLoaded: true,
551
- value: confVal.configValue
552
- }
553
- : {
554
- valueIsLoaded: false
555
- };
567
+ assert(confVal.valueIsLoaded === !!configEnvResolved.config);
556
568
  const configValueSource = {
557
569
  ...configValueSourceCommon,
558
- ...value,
570
+ ...confVal,
559
571
  configEnv: configEnvResolved,
560
- valueIsImportedAtRuntime: !valueAlreadyLoaded,
561
- valueIsDefinedByPlusFile: true,
562
- isOverriden,
572
+ valueIsLoadedWithImport: !confVal.valueIsLoaded || !isJsonValue(confVal.value),
573
+ valueIsDefinedByPlusValueFile: true,
563
574
  definedAtFilePath: {
564
575
  ...plusFile.filePath,
565
576
  fileExportPathToShowToUser: configName === plusFile.configName
@@ -584,6 +595,15 @@ function isDefiningPage(plusFiles) {
584
595
  function isDefiningPageConfig(configName) {
585
596
  return ['Page', 'route'].includes(configName);
586
597
  }
598
+ function resolveIsGlobalValue(configDefGlobal, configValue) {
599
+ let isGlobal;
600
+ if (isCallable(configDefGlobal))
601
+ isGlobal = configDefGlobal(configValue);
602
+ else
603
+ isGlobal = configDefGlobal ?? false;
604
+ assert(typeof isGlobal === 'boolean');
605
+ return isGlobal;
606
+ }
587
607
  function getDefiningConfigNames(plusFile) {
588
608
  let configNames = [];
589
609
  if (!plusFile.isConfigFile) {
@@ -598,33 +618,32 @@ function getDefiningConfigNames(plusFile) {
598
618
  function getConfigDefinitions(plusFilesRelevant, filter) {
599
619
  let configDefinitions = { ...configDefinitionsBuiltIn };
600
620
  // Add user-land meta configs
601
- Object.entries(plusFilesRelevant)
621
+ plusFilesRelevant
622
+ .slice()
602
623
  .reverse()
603
- .forEach(([_locationId, plusFiles]) => {
604
- plusFiles.forEach((plusFile) => {
605
- const confVal = getConfVal(plusFile, 'meta');
606
- if (!confVal)
624
+ .forEach((plusFile) => {
625
+ const confVal = getConfVal(plusFile, 'meta');
626
+ if (!confVal)
627
+ return;
628
+ assert(confVal.valueIsLoaded);
629
+ const meta = confVal.value;
630
+ assertMetaUsage(meta, `Config ${pc.cyan('meta')} defined at ${plusFile.filePath.filePathToShowToUser}`);
631
+ // Set configDef._userEffectDefinedAtFilePath
632
+ Object.entries(meta).forEach(([configName, configDef]) => {
633
+ if (!configDef.effect)
607
634
  return;
608
- assert(confVal.configValueLoaded);
609
- const meta = confVal.configValue;
610
- assertMetaUsage(meta, `Config ${pc.cyan('meta')} defined at ${plusFile.filePath.filePathToShowToUser}`);
611
- // Set configDef._userEffectDefinedAtFilePath
612
- Object.entries(meta).forEach(([configName, configDef]) => {
613
- if (!configDef.effect)
614
- return;
615
- assert(plusFile.isConfigFile);
616
- configDef._userEffectDefinedAtFilePath = {
617
- ...plusFile.filePath,
618
- fileExportPathToShowToUser: ['default', 'meta', configName, 'effect']
619
- };
620
- });
621
- objectEntries(meta).forEach(([configName, configDefinitionUserLand]) => {
622
- // User can override an existing config definition
623
- configDefinitions[configName] = {
624
- ...configDefinitions[configName],
625
- ...configDefinitionUserLand
626
- };
627
- });
635
+ assert(plusFile.isConfigFile);
636
+ configDef._userEffectDefinedAtFilePath = {
637
+ ...plusFile.filePath,
638
+ fileExportPathToShowToUser: ['default', 'meta', configName, 'effect']
639
+ };
640
+ });
641
+ objectEntries(meta).forEach(([configName, configDefinitionUserLand]) => {
642
+ // User can override an existing config definition
643
+ configDefinitions[configName] = {
644
+ ...configDefinitions[configName],
645
+ ...configDefinitionUserLand
646
+ };
628
647
  });
629
648
  });
630
649
  if (filter) {
@@ -668,67 +687,102 @@ function assertMetaUsage(metaVal, metaConfigDefinedAt) {
668
687
  }
669
688
  });
670
689
  }
671
- function applyEffectsAll(configValueSources, configDefinitions) {
672
- objectEntries(configDefinitions).forEach(([configName, configDef]) => {
673
- if (!configDef.effect)
690
+ // Test: https://github.com/vikejs/vike/blob/441a37c4c1a3b07bb8f6efb1d1f7be297a53974a/test/playground/vite.config.ts#L39
691
+ function applyEffectsConfVal(configValueSources, configDefinitions) {
692
+ objectEntries(configDefinitions).forEach(([configNameEffect, configDefEffect]) => {
693
+ const sourceEffect = configValueSources[configNameEffect]?.[0];
694
+ if (!sourceEffect)
674
695
  return;
675
- // The value needs to be loaded at config time, that's why we only support effect for configs that are config-only for now.
676
- // (We could support effect for non config-only by always loading its value at config time, regardless of the config's `env` value.)
677
- assertUsage(configDef.env.config, [
678
- `Cannot add effect to ${pc.cyan(configName)} because its ${pc.cyan('env')} is ${pc.cyan(JSON.stringify(configDef.env))}: effects can only be added to configs with an ${pc.cyan('env')} with ${pc.cyan('{ config: true }')}.`
679
- ].join(' '));
680
- const source = configValueSources[configName]?.[0];
681
- if (!source)
696
+ const effect = runEffect(configNameEffect, configDefEffect, sourceEffect);
697
+ if (!effect)
682
698
  return;
683
- // The config value is eagerly loaded since `configDef.env === 'config-only``
684
- assert('value' in source);
685
- // Call effect
686
- const configModFromEffect = configDef.effect({
687
- configValue: source.value,
688
- configDefinedAt: getConfigDefinedAt('Config', configName, source.definedAtFilePath)
689
- });
690
- if (!configModFromEffect)
699
+ const { configModFromEffect, configValueEffectSource } = effect;
700
+ applyEffectConfVal(configModFromEffect, sourceEffect, configValueSources, configNameEffect, configDefEffect, configDefinitions, configValueEffectSource);
701
+ });
702
+ }
703
+ // Test: https://github.com/vikejs/vike/blob/441a37c4c1a3b07bb8f6efb1d1f7be297a53974a/test/playground/pages/config-meta/effect/e2e-test.ts#L16
704
+ function applyEffectsMetaEnv(configValueSources, configDefinitions) {
705
+ objectEntries(configDefinitions).forEach(([configNameEffect, configDefEffect]) => {
706
+ const sourceEffect = configValueSources[configNameEffect]?.[0];
707
+ if (!sourceEffect)
708
+ return;
709
+ const effect = runEffect(configNameEffect, configDefEffect, sourceEffect);
710
+ if (!effect)
691
711
  return;
692
- assert(hasProp(source, 'value')); // We need to assume that the config value is loaded at build-time
693
- applyEffect(configModFromEffect, configValueSources, configDef);
712
+ const { configModFromEffect } = effect;
713
+ applyEffectMetaEnv(configModFromEffect, configValueSources, configDefEffect);
694
714
  });
695
715
  }
696
- function applyEffect(configModFromEffect, configValueSources, configDefEffect) {
697
- const notSupported = `Effects currently only supports modifying the the ${pc.cyan('env')} of a config.`;
698
- objectEntries(configModFromEffect).forEach(([configName, configValue]) => {
699
- if (configName === 'meta') {
700
- let configDefinedAt;
701
- if (configDefEffect._userEffectDefinedAtFilePath) {
702
- configDefinedAt = getConfigDefinedAt('Config', configName, configDefEffect._userEffectDefinedAtFilePath);
703
- }
704
- else {
705
- configDefinedAt = null;
706
- }
707
- assertMetaUsage(configValue, configDefinedAt);
708
- objectEntries(configValue).forEach(([configTargetName, configTargetDef]) => {
709
- {
710
- const keys = Object.keys(configTargetDef);
711
- assertUsage(keys.includes('env'), notSupported);
712
- assertUsage(keys.length === 1, notSupported);
713
- }
714
- const envOverriden = configTargetDef.env;
715
- const sources = configValueSources[configTargetName];
716
- sources?.forEach((configValueSource) => {
717
- // Apply effect
718
- configValueSource.configEnv = envOverriden;
719
- });
720
- });
716
+ function runEffect(configName, configDef, source) {
717
+ if (!configDef.effect)
718
+ return null;
719
+ // The value needs to be loaded at config time, that's why we only support effect for configs that are config-only for now.
720
+ assertUsage(configDef.env.config, [
721
+ `Cannot add meta.effect to ${pc.cyan(configName)} because its meta.env is ${pc.cyan(JSON.stringify(configDef.env))} but an effect can only be added to a config that has a meta.env with ${pc.cyan('{ config: true }')}.`
722
+ ].join(' '));
723
+ assert(source.valueIsLoaded);
724
+ const configValueEffectSource = source.value;
725
+ // Call effect
726
+ const configModFromEffect = configDef.effect({
727
+ configValue: configValueEffectSource,
728
+ configDefinedAt: getConfigDefinedAt('Config', configName, source.definedAtFilePath)
729
+ });
730
+ if (!configModFromEffect)
731
+ return null;
732
+ return { configModFromEffect, configValueEffectSource };
733
+ }
734
+ function applyEffectConfVal(configModFromEffect, sourceEffect, configValueSources, configNameEffect, configDefEffect, configDefinitions, configValueEffectSource) {
735
+ objectEntries(configModFromEffect).forEach(([configNameTarget, configValue]) => {
736
+ if (configNameTarget === 'meta')
737
+ return;
738
+ const configDef = configDefinitions[configNameTarget];
739
+ assert(configDef);
740
+ assert(configDefEffect._userEffectDefinedAtFilePath);
741
+ const configValueSource = {
742
+ definedAtFilePath: configDefEffect._userEffectDefinedAtFilePath,
743
+ plusFile: sourceEffect.plusFile,
744
+ locationId: sourceEffect.locationId,
745
+ configEnv: configDef.env,
746
+ valueIsLoadedWithImport: false,
747
+ valueIsDefinedByPlusValueFile: false,
748
+ valueIsLoaded: true,
749
+ value: configValue
750
+ };
751
+ const isValueGlobalSource = resolveIsGlobalValue(configDefEffect.global, configValueEffectSource);
752
+ const isValueGlobalTarget = resolveIsGlobalValue(configDef.global, configValue);
753
+ const isGlobalHumanReadable = (isGlobal) => `${isGlobal ? 'non-' : ''}global`;
754
+ // The error message make it sound like it's an inherent limitation, it actually isn't (both ways can make senses).
755
+ assertUsage(isValueGlobalSource === isValueGlobalTarget, `The configuration ${pc.cyan(configNameEffect)} is set to ${pc.cyan(JSON.stringify(configValueEffectSource))} which is considered ${isGlobalHumanReadable(isValueGlobalSource)}. However, it has a meta.effect that sets the configuration ${pc.cyan(configNameTarget)} to ${pc.cyan(JSON.stringify(configValue))} which is considered ${isGlobalHumanReadable(isValueGlobalTarget)}. This is contradictory: make sure the values are either both non-global or both global.`);
756
+ configValueSources[configNameTarget] ?? (configValueSources[configNameTarget] = []);
757
+ configValueSources[configNameTarget].push(configValueSource);
758
+ });
759
+ }
760
+ function applyEffectMetaEnv(configModFromEffect, configValueSources, configDefEffect) {
761
+ const notSupported = `${pc.cyan('meta.effect')} currently only supports setting the value of a config, or modifying the ${pc.cyan('meta.env')} of a config.`;
762
+ objectEntries(configModFromEffect).forEach(([configNameTarget, configValue]) => {
763
+ if (configNameTarget !== 'meta')
764
+ return;
765
+ let configDefinedAt;
766
+ if (configDefEffect._userEffectDefinedAtFilePath) {
767
+ configDefinedAt = getConfigDefinedAt('Config', configNameTarget, configDefEffect._userEffectDefinedAtFilePath);
721
768
  }
722
769
  else {
723
- assertUsage(false, notSupported);
724
- /* To implement being able to set a config value in an effect:
725
- * - Copy and append definedAtFile.fileExportPathToShowToUser with ['meta', configName, 'effect']
726
- * - Copying the definedAtFile of the config that defines the effect
727
- * - Same precedence as the config that sets the value triggering the effect (not the config defining the effect)
728
- * - Apply sortConfigValueSources() again?
729
- configValueSources.push()
730
- */
770
+ configDefinedAt = null;
731
771
  }
772
+ assertMetaUsage(configValue, configDefinedAt);
773
+ objectEntries(configValue).forEach(([configTargetName, configTargetDef]) => {
774
+ {
775
+ const keys = Object.keys(configTargetDef);
776
+ assertUsage(keys.includes('env'), notSupported);
777
+ assertUsage(keys.length === 1, notSupported);
778
+ }
779
+ const envOverriden = configTargetDef.env;
780
+ const sources = configValueSources[configTargetName];
781
+ sources?.forEach((configValueSource) => {
782
+ // Apply effect
783
+ configValueSource.configEnv = envOverriden;
784
+ });
785
+ });
732
786
  });
733
787
  }
734
788
  function getComputed(configValueSources, configDefinitions) {
@@ -748,7 +802,7 @@ function getComputed(configValueSources, configDefinitions) {
748
802
  }
749
803
  // Show error message upon unknown config
750
804
  function assertKnownConfigs(configDefinitionsResolved, plusFilesAll) {
751
- const configDefinitionsAll = getConfigDefinitions(plusFilesAll);
805
+ const configDefinitionsAll = getConfigDefinitions(Object.values(plusFilesAll).flat());
752
806
  const configNamesKnownAll = Object.keys(configDefinitionsAll);
753
807
  const configNamesGlobal = Object.keys(configDefinitionsResolved.configDefinitionsGlobal);
754
808
  objectEntries(configDefinitionsResolved.configDefinitionsLocal).forEach(([_locationId, { configDefinitions, plusFiles }]) => {
@@ -842,7 +896,7 @@ function determineRouteFilesystem(locationId, configValueSources) {
842
896
  function getFilesystemRoutingRootEffect(configFilesystemRoutingRoot, configName) {
843
897
  assert(configFilesystemRoutingRoot.configEnv.config);
844
898
  // Eagerly loaded since it's config-only
845
- assert('value' in configFilesystemRoutingRoot);
899
+ assert(configFilesystemRoutingRoot.valueIsLoaded);
846
900
  const { value } = configFilesystemRoutingRoot;
847
901
  const configDefinedAt = getConfigDefinedAt('Config', configName, configFilesystemRoutingRoot.definedAtFilePath);
848
902
  assertUsage(typeof value === 'string', `${configDefinedAt} should be a string`);
@@ -902,8 +956,8 @@ function getConfVal(plusFile, configName) {
902
956
  if (!configNames.includes(configName))
903
957
  return null;
904
958
  if (plusFile.isNotLoaded)
905
- return { configValueLoaded: false };
906
- const confVal = { configValue: plusFile.fileExportsByConfigName[configName], configValueLoaded: true };
959
+ return { valueIsLoaded: false };
960
+ const confVal = { value: plusFile.fileExportsByConfigName[configName], valueIsLoaded: true };
907
961
  return confVal;
908
962
  }
909
963
  function resolveConfigEnv(configEnv, filePath) {
@@ -932,3 +986,14 @@ function isGlobalLocation(locationId, plusFilesAll) {
932
986
  .map(([locationId]) => locationId);
933
987
  return locationIdsPage.every((locId) => isInherited(locationId, locId));
934
988
  }
989
+ function isOverriden(source, configName, pageConfig) {
990
+ const configDef = pageConfig.configDefinitions[configName];
991
+ assert(configDef);
992
+ if (configDef.cumulative)
993
+ return false;
994
+ const sources = pageConfig.configValueSources[configName];
995
+ assert(sources);
996
+ const idx = sources.indexOf(source);
997
+ assert(idx >= 0);
998
+ return idx > 0;
999
+ }