vike 0.4.143-commit-f03b42d → 0.4.143-commit-fa295e1

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 (49) hide show
  1. package/dist/cjs/node/plugin/plugins/devConfig/determineOptimizeDeps.js +30 -27
  2. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getFilePathToShowToUser.js +6 -0
  3. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +119 -64
  4. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigValuesAll.js +11 -10
  5. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigs.js +11 -11
  6. package/dist/cjs/node/prerender/runPrerender.js +9 -8
  7. package/dist/cjs/node/runtime/html/injectAssets/getHtmlTags.js +1 -1
  8. package/dist/cjs/node/runtime/renderPage/log404/index.js +10 -5
  9. package/dist/cjs/node/runtime/renderPage/renderPageAlreadyRouted.js +3 -2
  10. package/dist/cjs/node/shared/getClientEntryFilePath.js +1 -7
  11. package/dist/cjs/shared/getPageFiles/getExports.js +2 -5
  12. package/dist/cjs/shared/getPageFiles/parsePageConfigsSerialized.js +9 -6
  13. package/dist/cjs/shared/hooks/getHook.js +3 -1
  14. package/dist/cjs/shared/page-configs/getExportPath.js +2 -2
  15. package/dist/cjs/shared/page-configs/parseConfigValuesImported.js +8 -5
  16. package/dist/cjs/shared/page-configs/utils.js +66 -42
  17. package/dist/cjs/shared/route/loadPageRoutes.js +5 -6
  18. package/dist/cjs/utils/projectInfo.js +1 -1
  19. package/dist/esm/node/plugin/plugins/devConfig/determineOptimizeDeps.js +30 -27
  20. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getFilePathToShowToUser.d.ts +11 -2
  21. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getFilePathToShowToUser.js +6 -0
  22. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/configDefinitionsBuiltIn.d.ts +3 -2
  23. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +119 -64
  24. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigValuesAll.js +11 -10
  25. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigs.d.ts +2 -2
  26. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigs.js +11 -11
  27. package/dist/esm/node/prerender/runPrerender.js +10 -9
  28. package/dist/esm/node/runtime/html/injectAssets/getHtmlTags.js +1 -1
  29. package/dist/esm/node/runtime/renderPage/log404/index.js +10 -5
  30. package/dist/esm/node/runtime/renderPage/renderPageAlreadyRouted.js +3 -2
  31. package/dist/esm/node/shared/getClientEntryFilePath.js +2 -8
  32. package/dist/esm/shared/addUrlComputedProps.d.ts +4 -2
  33. package/dist/esm/shared/getPageFiles/getExports.d.ts +1 -2
  34. package/dist/esm/shared/getPageFiles/getExports.js +3 -6
  35. package/dist/esm/shared/getPageFiles/parsePageConfigsSerialized.js +9 -6
  36. package/dist/esm/shared/hooks/getHook.js +3 -1
  37. package/dist/esm/shared/page-configs/Config.d.ts +1 -3
  38. package/dist/esm/shared/page-configs/PageConfig.d.ts +35 -10
  39. package/dist/esm/shared/page-configs/getExportPath.d.ts +1 -1
  40. package/dist/esm/shared/page-configs/getExportPath.js +2 -2
  41. package/dist/esm/shared/page-configs/parseConfigValuesImported.js +8 -5
  42. package/dist/esm/shared/page-configs/utils.d.ts +19 -13
  43. package/dist/esm/shared/page-configs/utils.js +65 -41
  44. package/dist/esm/shared/route/loadPageRoutes.js +6 -7
  45. package/dist/esm/shared/types.d.ts +1 -0
  46. package/dist/esm/types/index.d.ts +1 -0
  47. package/dist/esm/utils/projectInfo.d.ts +1 -1
  48. package/dist/esm/utils/projectInfo.js +1 -1
  49. package/package.json +1 -1
@@ -84,7 +84,8 @@ async function loadInterfaceFiles(userRootDir, isDev, extensions) {
84
84
  await Promise.all(configFiles.map(async ({ filePathAbsolute, filePathRelativeToUserRootDir }) => {
85
85
  const configFilePath = {
86
86
  filePathAbsolute: filePathAbsolute,
87
- filePathRelativeToUserRootDir: filePathRelativeToUserRootDir
87
+ filePathRelativeToUserRootDir: filePathRelativeToUserRootDir,
88
+ importPathAbsolute: null
88
89
  };
89
90
  const { configFile, extendsConfigs } = await loadConfigFile(configFilePath, userRootDir, []);
90
91
  const interfaceFile = getInterfaceFileFromConfigFile(configFile, false);
@@ -103,7 +104,8 @@ async function loadInterfaceFiles(userRootDir, isDev, extensions) {
103
104
  const interfaceFile = {
104
105
  filePath: {
105
106
  filePathRelativeToUserRootDir,
106
- filePathAbsolute
107
+ filePathAbsolute,
108
+ importPathAbsolute: null
107
109
  },
108
110
  configMap: {
109
111
  [configName]: {}
@@ -338,7 +340,9 @@ function getGlobalConfigs(interfaceFilesByLocationId, userRootDir) {
338
340
  if (configName === 'prerender' && typeof configValueSource.value === 'boolean')
339
341
  return;
340
342
  assert(!configValueSource.isComputed);
341
- assertWarning(false, `Being able to define config ${pc.cyan(configName)} in ${configValueSource.definedAtInfo.filePath} is experimental and will likely be removed. Define the config ${pc.cyan(configName)} in vike's Vite plugin options instead.`, { onlyOnce: true });
343
+ const sourceFilePath = getFilePathToShowToUser2(configValueSource.definedAtInfo);
344
+ assert(sourceFilePath);
345
+ assertWarning(false, `Being able to define config ${pc.cyan(configName)} in ${sourceFilePath} is experimental and will likely be removed. Define the config ${pc.cyan(configName)} in vike's Vite plugin options instead.`, { onlyOnce: true });
342
346
  globalVikeConfig[configName] = configValueSource.value;
343
347
  }
344
348
  });
@@ -421,48 +425,48 @@ function warnOverridenConfigValues(interfaceFileWinner, interfaceFilesOverriden,
421
425
  interfaceFilesOverriden.forEach((interfaceFileLoser) => {
422
426
  const configValueSourceWinner = getConfigValueSource(configName, interfaceFileWinner, configDef, userRootDir);
423
427
  const configValueSourceLoser = getConfigValueSource(configName, interfaceFileLoser, configDef, userRootDir);
424
- assertWarning(false, `${getConfigDefinedAtString(configName, configValueSourceLoser, true)} overriden by another ${getConfigDefinedAtString(configName, configValueSourceWinner, false)}, remove one of the two`, { onlyOnce: false });
428
+ assert(!configValueSourceLoser.isComputed);
429
+ assert(!configValueSourceWinner.isComputed);
430
+ assertWarning(false, `${getConfigSourceDefinedAtString(configName, configValueSourceLoser, undefined, true)} overriden by another ${getConfigSourceDefinedAtString(configName, configValueSourceWinner, undefined, false)}, remove one of the two`, { onlyOnce: false });
425
431
  });
426
432
  }
427
433
  function isInterfaceFileUserLand(interfaceFile) {
428
434
  return (interfaceFile.isConfigFile && !interfaceFile.isConfigExtend) || interfaceFile.isValueFile;
429
435
  }
430
436
  function getConfigValueSource(configName, interfaceFile, configDef, userRootDir) {
431
- // TODO: rethink file paths of ConfigElement
432
- const filePathToShowToUser = interfaceFile.filePath.filePathRelativeToUserRootDir ?? interfaceFile.filePath.filePathAbsolute;
433
437
  const conf = interfaceFile.configMap[configName];
434
438
  assert(conf);
435
439
  const configEnv = configDef.env;
436
- const definedAtInfoConfigFile = {
437
- filePath: filePathToShowToUser,
440
+ const definedAtConfigFile = {
441
+ ...interfaceFile.filePath,
438
442
  fileExportPath: ['default', configName]
439
443
  };
440
444
  if (configDef._valueIsFilePath) {
441
- let filePath;
445
+ let definedAtInfo;
446
+ let valueFilePath;
442
447
  if (interfaceFile.isConfigFile) {
443
448
  const { configValue } = conf;
444
449
  const import_ = resolveImport(configValue, interfaceFile.filePath, userRootDir, configEnv, configName);
445
- const configDefinedAt = getConfigDefinedAtString(configName, { definedAtInfo: definedAtInfoConfigFile }, true);
450
+ const configDefinedAt = getConfigSourceDefinedAtString(configName, { definedAtInfo: definedAtConfigFile });
446
451
  assertUsage(import_, `${configDefinedAt} should be an import`);
447
- filePath = import_.filePathToShowToUser;
452
+ valueFilePath = import_.filePathRelativeToUserRootDir ?? import_.importPathAbsolute;
453
+ definedAtInfo = import_;
448
454
  }
449
455
  else {
450
456
  assert(interfaceFile.isValueFile);
451
- filePath =
452
- interfaceFile.filePath.filePathRelativeToUserRootDir ??
453
- // Experimental: is this needed? Would it work?
454
- interfaceFile.filePath.filePathAbsolute;
457
+ valueFilePath = interfaceFile.filePath.filePathRelativeToUserRootDir;
458
+ definedAtInfo = {
459
+ ...interfaceFile.filePath,
460
+ fileExportPath: []
461
+ };
455
462
  }
456
463
  const configValueSource = {
457
- value: filePath,
464
+ value: valueFilePath,
458
465
  valueIsFilePath: true,
459
466
  configEnv,
460
467
  valueIsImportedAtRuntime: true,
461
468
  isComputed: false,
462
- definedAtInfo: {
463
- filePath,
464
- fileExportPath: []
465
- }
469
+ definedAtInfo
466
470
  };
467
471
  return configValueSource;
468
472
  }
@@ -471,15 +475,11 @@ function getConfigValueSource(configName, interfaceFile, configDef, userRootDir)
471
475
  const { configValue } = conf;
472
476
  const import_ = resolveImport(configValue, interfaceFile.filePath, userRootDir, configEnv, configName);
473
477
  if (import_) {
474
- const { filePathToShowToUser, fileExportName: exportName } = import_;
475
478
  const configValueSource = {
476
479
  configEnv,
477
480
  valueIsImportedAtRuntime: true,
478
481
  isComputed: false,
479
- definedAtInfo: {
480
- filePath: filePathToShowToUser,
481
- fileExportPath: [exportName]
482
- }
482
+ definedAtInfo: import_
483
483
  };
484
484
  return configValueSource;
485
485
  }
@@ -489,23 +489,21 @@ function getConfigValueSource(configName, interfaceFile, configDef, userRootDir)
489
489
  configEnv,
490
490
  valueIsImportedAtRuntime: false,
491
491
  isComputed: false,
492
- definedAtInfo: definedAtInfoConfigFile
492
+ definedAtInfo: definedAtConfigFile
493
493
  };
494
494
  return configValueSource;
495
495
  }
496
496
  }
497
497
  else if (interfaceFile.isValueFile) {
498
498
  // TODO: rethink file paths of ConfigElement
499
- const importPath = interfaceFile.filePath.filePathRelativeToUserRootDir ?? interfaceFile.filePath.filePathAbsolute;
500
- const exportName = configName === interfaceFile.configName ? 'default' : configName;
501
499
  const valueAlreadyLoaded = 'configValue' in conf;
502
500
  const configValueSource = {
503
501
  configEnv,
504
502
  valueIsImportedAtRuntime: !valueAlreadyLoaded,
505
503
  isComputed: false,
506
504
  definedAtInfo: {
507
- filePath: importPath,
508
- fileExportPath: [exportName]
505
+ ...interfaceFile.filePath,
506
+ fileExportPath: configName === interfaceFile.configName ? [] : [configName]
509
507
  }
510
508
  };
511
509
  if (valueAlreadyLoaded) {
@@ -554,7 +552,8 @@ function resolveImport(configValue, importerFilePath, userRootDir, configEnv, co
554
552
  return null;
555
553
  const { importPath, exportName } = importData;
556
554
  const filePathAbsolute = resolveImportPath(importData, importerFilePath);
557
- let filePathToShowToUser;
555
+ assertFileEnv(filePathAbsolute ?? importPath, configEnv, configName);
556
+ const fileExportPath = exportName === 'default' || exportName === configName ? [] : [exportName];
558
557
  if (importPath.startsWith('.')) {
559
558
  // We need to resolve relative paths into absolute paths. Because the import paths are included in virtual files:
560
559
  // ```
@@ -562,22 +561,26 @@ function resolveImport(configValue, importerFilePath, userRootDir, configEnv, co
562
561
  // ```
563
562
  assertImportPath(filePathAbsolute, importData, importerFilePath);
564
563
  const filePathRelativeToUserRootDir = resolveImportPath_relativeToUserRootDir(filePathAbsolute, importData, importerFilePath, userRootDir);
565
- filePathToShowToUser = filePathRelativeToUserRootDir;
564
+ return {
565
+ exportName,
566
+ fileExportPath,
567
+ filePathAbsolute,
568
+ filePathRelativeToUserRootDir,
569
+ importPathAbsolute: null
570
+ };
566
571
  }
567
572
  else {
568
573
  // importPath can be:
569
574
  // - an npm package import
570
575
  // - a path alias
571
- filePathToShowToUser = importPath;
572
- }
573
- {
574
- const filePathForEnvCheck = filePathAbsolute ?? importPath;
575
- assertFileEnv(filePathForEnvCheck, configEnv, configName);
576
+ return {
577
+ exportName,
578
+ fileExportPath,
579
+ filePathAbsolute,
580
+ filePathRelativeToUserRootDir: null,
581
+ importPathAbsolute: importPath
582
+ };
576
583
  }
577
- return {
578
- filePathToShowToUser,
579
- fileExportName: exportName
580
- };
581
584
  }
582
585
  function resolveImportPath_relativeToUserRootDir(filePathAbsolute, importData, configFilePath, userRootDir) {
583
586
  assertPosixPath(userRootDir);
@@ -670,24 +673,26 @@ function applyEffects(pageConfig, configDefinitionsRelevant) {
670
673
  `Adding an effect to ${pc.cyan(configName)} may not work as expected because ${pc.cyan(configName)} has an ${pc.cyan('env')} that is different than ${pc.cyan('config-only')} (its env is ${pc.cyan(configDef.env)}).`,
671
674
  'Reach out to a maintainer if you want to use this in production.'
672
675
  ].join(' '), { onlyOnce: true });
673
- const configValue = pageConfig.configValueSources[configName]?.[0];
674
- if (!configValue)
676
+ const source = pageConfig.configValueSources[configName]?.[0];
677
+ if (!source)
675
678
  return;
679
+ assert(!source.isComputed);
676
680
  const configModFromEffect = configDef.effect({
677
- configValue: configValue.value,
678
- configDefinedAt: getConfigDefinedAtString(configName, configValue, true)
681
+ configValue: source.value,
682
+ configDefinedAt: getConfigSourceDefinedAtString(configName, source)
679
683
  });
680
684
  if (!configModFromEffect)
681
685
  return;
682
- assert(hasProp(configValue, 'value')); // We need to assume that the config value is loaded at build-time
683
- applyEffect(configModFromEffect, configValue, pageConfig.configValueSources);
686
+ assert(hasProp(source, 'value')); // We need to assume that the config value is loaded at build-time
687
+ applyEffect(configModFromEffect, source, pageConfig.configValueSources);
684
688
  });
685
689
  }
686
690
  function applyEffect(configModFromEffect, configValueEffectSource, configValueSources) {
687
691
  const notSupported = `config.meta[configName].effect currently only supports modifying the the ${pc.cyan('env')} of a config. Reach out to a maintainer if you need more capabilities.`;
688
692
  objectEntries(configModFromEffect).forEach(([configName, configValue]) => {
689
693
  if (configName === 'meta') {
690
- assertMetaValue(configValue, getConfigDefinedAtString(configName, configValueEffectSource, true, 'effect'));
694
+ assert(!configValueEffectSource.isComputed);
695
+ assertMetaValue(configValue, getConfigSourceDefinedAtString(configName, configValueEffectSource, true));
691
696
  objectEntries(configValue).forEach(([configTargetName, configTargetDef]) => {
692
697
  {
693
698
  const keys = Object.keys(configTargetDef);
@@ -797,7 +802,7 @@ function assertNoUnexpectedPlusSign(filePath, fileName) {
797
802
  assertUsage(!fileName.slice(1).includes('+'), `Character '+' is only allowed at the beginning of filenames: make sure ${filePath} doesn't contain any '+' in its filename other than its first letter`);
798
803
  }
799
804
  async function loadConfigFile(configFilePath, userRootDir, visited) {
800
- const { filePathAbsolute, filePathRelativeToUserRootDir } = configFilePath;
805
+ const { filePathAbsolute } = configFilePath;
801
806
  assertNoInfiniteLoop(visited, filePathAbsolute);
802
807
  const { fileExports } = await transpileAndExecuteFile(configFilePath, false, userRootDir);
803
808
  const { extendsConfigs, extendsFilePaths } = await loadExtendsConfigs(fileExports, configFilePath, userRootDir, [
@@ -806,10 +811,7 @@ async function loadConfigFile(configFilePath, userRootDir, visited) {
806
811
  ]);
807
812
  const configFile = {
808
813
  fileExports,
809
- filePath: {
810
- filePathRelativeToUserRootDir,
811
- filePathAbsolute
812
- },
814
+ filePath: configFilePath,
813
815
  extendsFilePaths
814
816
  };
815
817
  return { configFile, extendsConfigs };
@@ -832,11 +834,14 @@ async function loadExtendsConfigs(configFileExports, configFilePath, userRootDir
832
834
  const filePathAbsolute = resolveImportPath(importData, configFilePath);
833
835
  assertImportPath(filePathAbsolute, importData, configFilePath);
834
836
  assertExtendsImportPath(importPath, filePathAbsolute, configFilePath);
837
+ // - filePathRelativeToUserRootDir has no functionality beyond nicer error messages for user
838
+ // - Using importPath would be visually nicer but it's ambigous => we rather pick filePathAbsolute for added clarity
839
+ const filePathRelativeToUserRootDir = determineFilePathRelativeToUserDir(filePathAbsolute, userRootDir);
835
840
  extendsConfigFiles.push({
836
841
  filePathAbsolute,
837
- // - filePathRelativeToUserRootDir has no functionality beyond nicer error messages for user
838
- // - Using importPath would be visually nicer but it's ambigous => we rather pick filePathAbsolute for added clarity
839
- filePathRelativeToUserRootDir: determineFilePathRelativeToUserDir(filePathAbsolute, userRootDir)
842
+ // TODO: fix type cast
843
+ filePathRelativeToUserRootDir: filePathRelativeToUserRootDir,
844
+ importPathAbsolute: importPath
840
845
  });
841
846
  });
842
847
  const extendsConfigs = [];
@@ -999,11 +1004,13 @@ function getFilesystemRoutingRootEffect(configFilesystemRoutingRoot, configName)
999
1004
  // Eagerly loaded since it's config-only
1000
1005
  assert('value' in configFilesystemRoutingRoot);
1001
1006
  const { value } = configFilesystemRoutingRoot;
1002
- const configDefinedAt = getConfigDefinedAtString(configName, configFilesystemRoutingRoot, false);
1007
+ assert(!configFilesystemRoutingRoot.isComputed);
1008
+ const configDefinedAt = getConfigSourceDefinedAtString(configName, configFilesystemRoutingRoot);
1003
1009
  assertUsage(typeof value === 'string', `${configDefinedAt} should be a string`);
1004
1010
  assertUsage(value.startsWith('/'), `${configDefinedAt} is ${pc.cyan(value)} but it should start with a leading slash ${pc.cyan('/')}`);
1005
1011
  assert(!configFilesystemRoutingRoot.isComputed);
1006
- const before = getFilesystemRouteString(getLocationId(configFilesystemRoutingRoot.definedAtInfo.filePath));
1012
+ assert(configFilesystemRoutingRoot.definedAtInfo.filePathRelativeToUserRootDir);
1013
+ const before = getFilesystemRouteString(getLocationId(configFilesystemRoutingRoot.definedAtInfo.filePathRelativeToUserRootDir));
1007
1014
  const after = value;
1008
1015
  const filesystemRoutingRootEffect = { before, after };
1009
1016
  return { filesystemRoutingRootEffect, filesystemRoutingRootDefinedAt: configDefinedAt };
@@ -1048,10 +1055,11 @@ function getConfigValues(configValueSources, configDefinitionsRelevant) {
1048
1055
  if (!configDef.cumulative) {
1049
1056
  const configValueSource = sources[0];
1050
1057
  if ('value' in configValueSource) {
1051
- const { value, definedAtInfo } = configValueSource;
1058
+ const { value } = configValueSource;
1059
+ const definedAt = configValueSource.isComputed ? { isComputed: true } : getDefinedAt(configValueSource);
1052
1060
  configValues[configName] = {
1053
1061
  value,
1054
- definedAtInfo
1062
+ definedAt
1055
1063
  };
1056
1064
  }
1057
1065
  }
@@ -1059,7 +1067,10 @@ function getConfigValues(configValueSources, configDefinitionsRelevant) {
1059
1067
  const value = mergeCumulative(configName, sources);
1060
1068
  configValues[configName] = {
1061
1069
  value,
1062
- definedAtInfo: null
1070
+ definedAt: {
1071
+ isCumulative: true,
1072
+ sources: sources.map((source) => getSourceDefinedAt(source))
1073
+ }
1063
1074
  };
1064
1075
  }
1065
1076
  });
@@ -1071,7 +1082,7 @@ function mergeCumulative(configName, configValueSources) {
1071
1082
  let configValueSourcePrevious = null;
1072
1083
  configValueSources.forEach((configValueSource) => {
1073
1084
  assert(!configValueSource.isComputed);
1074
- const configDefinedAt = getConfigDefinedAtString(configName, configValueSource, true);
1085
+ const configDefinedAt = getConfigSourceDefinedAtString(configName, configValueSource);
1075
1086
  const configNameColored = pc.cyan(configName);
1076
1087
  // We could, in principle, also support cumulative values to be defined in +${configName}.js but it ins't completely trivial to implement
1077
1088
  assertUsage('value' in configValueSource, `${configDefinedAt} is only allowed to be defined in a +config.h.js file. (Because the values of ${configNameColored} are cumulative.)`);
@@ -1079,7 +1090,7 @@ function mergeCumulative(configName, configValueSources) {
1079
1090
  const explanation = `(Because the values of ${configNameColored} are cumulative and therefore merged together.)` as const
1080
1091
  */
1081
1092
  // Make sure configValueSource.value is serializable
1082
- getConfigValueSerialized(configValueSource.value, configName, configValueSource.definedAtInfo);
1093
+ getConfigValueSerialized(configValueSource.value, configName, getDefinedAt(configValueSource));
1083
1094
  const assertNoMixing = (isSet) => {
1084
1095
  const vals1 = isSet ? valuesSet : valuesArr;
1085
1096
  const t1 = isSet ? 'a Set' : 'an array';
@@ -1089,7 +1100,8 @@ function mergeCumulative(configName, configValueSources) {
1089
1100
  if (vals2.length === 0)
1090
1101
  return;
1091
1102
  assert(configValueSourcePrevious);
1092
- const configPreviousDefinedAt = getConfigDefinedAtString(configName, configValueSourcePrevious, false);
1103
+ assert(!configValueSourcePrevious.isComputed);
1104
+ const configPreviousDefinedAt = getConfigSourceDefinedAtString(configName, configValueSourcePrevious, undefined, true);
1093
1105
  assertUsage(false, `${configDefinedAt} sets ${t1} but another ${configPreviousDefinedAt} sets ${t2} which is forbidden: the values must be all arrays or all sets (you cannot mix).`);
1094
1106
  };
1095
1107
  const { value } = configValueSource;
@@ -1120,3 +1132,46 @@ function mergeCumulative(configName, configValueSources) {
1120
1132
  }
1121
1133
  assert(false);
1122
1134
  }
1135
+ // TODO: rename
1136
+ // TODO: refactor
1137
+ function getConfigSourceDefinedAtString(configName, { definedAtInfo }, isEffect = undefined, sentenceBegin = true) {
1138
+ return getConfigDefinedAtString(configName, {
1139
+ definedAt: {
1140
+ isEffect,
1141
+ source: {
1142
+ filePathToShowToUser: getFilePathToShowToUser2(definedAtInfo),
1143
+ fileExportPath: definedAtInfo.fileExportPath
1144
+ }
1145
+ }
1146
+ }, sentenceBegin);
1147
+ }
1148
+ // TODO: rename
1149
+ function getFilePathToShowToUser2(definedAtInfo) {
1150
+ return definedAtInfo.filePathRelativeToUserRootDir ?? definedAtInfo.importPathAbsolute;
1151
+ /*
1152
+ if (definedAtInfo.filePathRelativeToUserRootDir !== null) {
1153
+ return definedAtInfo.filePathRelativeToUserRootDir
1154
+ }
1155
+ if (definedAtInfo.importPathAbsolute !== null) {
1156
+ return definedAtInfo.importPathAbsolute
1157
+ } else {
1158
+ const filePathToShowToUser = definedAtInfo.filePathAbsolute
1159
+ // TypeScript failes to infer that definedAtInfo.filePathAbsolute cannot be null
1160
+ assert(filePathToShowToUser)
1161
+ return filePathToShowToUser
1162
+ }
1163
+ */
1164
+ }
1165
+ // TODO: rename
1166
+ function getSourceDefinedAt(source) {
1167
+ assert(!source.isComputed);
1168
+ return {
1169
+ filePathToShowToUser: getFilePathToShowToUser2(source.definedAtInfo),
1170
+ fileExportPath: source.definedAtInfo.fileExportPath
1171
+ };
1172
+ }
1173
+ function getDefinedAt(configValueSource) {
1174
+ return {
1175
+ source: getSourceDefinedAt(configValueSource)
1176
+ };
1177
+ }
@@ -53,30 +53,31 @@ function getLoadConfigValuesAll(pageConfig, isForClientSide, pageId, includeAsse
53
53
  return code;
54
54
  }
55
55
  function serializeConfigValueImported(configValueSource, configName, whitespace, varCounterContainer, importStatements) {
56
+ assert(!configValueSource.valueIsFilePath);
56
57
  assert(whitespace.replaceAll(' ', '').length === 0);
57
58
  const { valueIsImportedAtRuntime, definedAtInfo } = configValueSource;
58
59
  assert(valueIsImportedAtRuntime);
59
- const { filePath, fileExportPath } = definedAtInfo;
60
- assertPosixPath(filePath);
61
- const fileName = path.posix.basename(filePath);
60
+ const { filePathRelativeToUserRootDir, importPathAbsolute, exportName } = definedAtInfo;
61
+ const importPath = filePathRelativeToUserRootDir ?? importPathAbsolute;
62
+ assertPosixPath(importPath);
63
+ const fileName = path.posix.basename(importPath);
62
64
  const isValueFile = fileName.startsWith('+');
63
- const fileExportName = fileExportPath[0];
64
- assert(!configValueSource.valueIsFilePath);
65
- assert(fileExportName);
66
- const { importName, importStatement } = generateEagerImport(filePath, varCounterContainer.varCounter++, isValueFile ? undefined : fileExportName);
65
+ if (isValueFile)
66
+ assert(exportName === undefined);
67
+ const { importName, importStatement } = generateEagerImport(importPath, varCounterContainer.varCounter++, exportName);
67
68
  importStatements.push(importStatement);
68
69
  const lines = [];
69
70
  lines.push(` {`);
70
71
  lines.push(` configName: '${configName}',`);
71
- lines.push(` importPath: '${filePath}',`);
72
+ lines.push(` importPath: '${importPath}',`);
72
73
  lines.push(` isValueFile: ${JSON.stringify(isValueFile)},`);
73
74
  if (isValueFile) {
74
75
  lines.push(` importFileExports: ${importName},`);
75
76
  }
76
77
  else {
77
78
  lines.push(` importFileExportValue: ${importName},`);
78
- assert(fileExportName);
79
- lines.push(` exportName: ${JSON.stringify(fileExportName)},`);
79
+ assert(exportName);
80
+ lines.push(` exportName: ${JSON.stringify(exportName)},`);
80
81
  }
81
82
  lines.push(` },`);
82
83
  return lines;
@@ -1,6 +1,6 @@
1
1
  export { getVirtualFilePageConfigs };
2
2
  export { getConfigValueSerialized };
3
- import type { DefinedAtInfo } from '../../../../../shared/page-configs/PageConfig.js';
3
+ import type { DefinedAt } from '../../../../../shared/page-configs/PageConfig.js';
4
4
  import type { ConfigVikeResolved } from '../../../../../shared/ConfigVike.js';
5
5
  declare function getVirtualFilePageConfigs(userRootDir: string, isForClientSide: boolean, isDev: boolean, id: string, configVike: ConfigVikeResolved, isClientRouting: boolean): Promise<string>;
6
- declare function getConfigValueSerialized(value: unknown, configName: string, definedAtInfo: null | DefinedAtInfo): string;
6
+ declare function getConfigValueSerialized(value: unknown, configName: string, definedAt: DefinedAt): string;
@@ -9,6 +9,7 @@ import pc from '@brillout/picocolors';
9
9
  import { getVikeConfig } from './getVikeConfig.js';
10
10
  import { isConfigEnvMatch } from './isConfigEnvMatch.js';
11
11
  import { serializeConfigValueImported } from './getVirtualFilePageConfigValuesAll.js';
12
+ import { getConfigValueFilePathToShowToUser } from '../../../../../shared/page-configs/utils.js';
12
13
  async function getVirtualFilePageConfigs(userRootDir, isForClientSide, isDev, id, configVike, isClientRouting) {
13
14
  const { pageConfigs, pageConfigGlobal } = await getVikeConfig(userRootDir, isDev, configVike.extensions, true);
14
15
  return getContent(pageConfigs, pageConfigGlobal, isForClientSide, isDev, id, isClientRouting);
@@ -34,9 +35,9 @@ function getContent(pageConfigs, pageConfigGlobal, isForClientSide, isDev, id, i
34
35
  assert(configEnv, configName);
35
36
  if (!isConfigEnvMatch(configEnv, isForClientSide, isClientRouting))
36
37
  return;
37
- const { value, definedAtInfo } = configValue;
38
- const valueSerialized = getConfigValueSerialized(value, configName, definedAtInfo);
39
- serializeConfigValue(lines, configName, { definedAtInfo, valueSerialized });
38
+ const { value, definedAt } = configValue;
39
+ const valueSerialized = getConfigValueSerialized(value, configName, definedAt);
40
+ serializeConfigValue(lines, configName, { definedAt, valueSerialized });
40
41
  }
41
42
  });
42
43
  lines.push(` },`);
@@ -93,13 +94,13 @@ function serializeConfigValue(lines, configName, configValueSerialized) {
93
94
  lines.push(`${whitespace}['${configName}']: {`);
94
95
  whitespace += ' ';
95
96
  Object.entries(configValueSerialized).forEach(([key, val]) => {
96
- const valSerialized = key === 'definedAtInfo' ? JSON.stringify(val) : val;
97
+ const valSerialized = key === 'definedAt' ? JSON.stringify(val) : val;
97
98
  lines.push(`${whitespace} ${key}: ${valSerialized},`);
98
99
  });
99
100
  whitespace = whitespace.slice(2);
100
101
  lines.push(`${whitespace}},`);
101
102
  }
102
- function getConfigValueSerialized(value, configName, definedAtInfo) {
103
+ function getConfigValueSerialized(value, configName, definedAt) {
103
104
  let configValueSerialized;
104
105
  const valueName = `config${getPropAccessNotation(configName)}`;
105
106
  try {
@@ -107,15 +108,14 @@ function getConfigValueSerialized(value, configName, definedAtInfo) {
107
108
  }
108
109
  catch (err) {
109
110
  assert(hasProp(err, 'messageCore', 'string'));
110
- // definedAtInfo is null when config value is:
111
+ const configValueFilePathToShowToUser = getConfigValueFilePathToShowToUser({ definedAt });
112
+ // definedAt is null when config value is:
111
113
  // - computed => all computed values defined by Vike can are serializable
112
114
  // - cumulative => the values are already ensured to be serializable
113
- assert(definedAtInfo);
114
- const configDefinedByFile = definedAtInfo.filePath;
115
- assert(configDefinedByFile);
115
+ assert(configValueFilePathToShowToUser);
116
116
  assertUsage(false, [
117
- `The value of the config ${pc.cyan(configName)} cannot be defined inside the file ${configDefinedByFile}:`,
118
- `its value must be defined in an another file and then imported by ${configDefinedByFile}. (Because the value isn't serializable: ${err.messageCore}.)`,
117
+ `The value of the config ${pc.cyan(configName)} cannot be defined inside the file ${configValueFilePathToShowToUser}:`,
118
+ `its value must be defined in an another file and then imported by ${configValueFilePathToShowToUser}. (Because the value isn't serializable: ${err.messageCore}.)`,
119
119
  `Only serializable config values can be defined inside +config.h.js files, see https://vike.dev/header-file.`
120
120
  ].join(' '));
121
121
  }
@@ -16,7 +16,7 @@ import { getConfigVike } from '../shared/getConfigVike.js';
16
16
  import { getPageFilesServerSide } from '../../shared/getPageFiles.js';
17
17
  import { getPageContextRequestUrl } from '../../shared/getPageContextRequestUrl.js';
18
18
  import { getUrlFromRouteString } from '../../shared/route/resolveRouteString.js';
19
- import { getConfigDefinedAtInfo, getConfigValue } from '../../shared/page-configs/utils.js';
19
+ import { getConfigValue, getConfigValueFilePathToShowToUser, getHookFilePathToShowToUser } from '../../shared/page-configs/utils.js';
20
20
  import { loadConfigValues } from '../../shared/page-configs/loadConfigValues.js';
21
21
  import { isErrorPage } from '../../shared/error-page.js';
22
22
  import { addUrlComputedProps } from '../../shared/addUrlComputedProps.js';
@@ -87,12 +87,13 @@ async function collectDoNoPrerenderList(renderContext, doNotPrerenderList, concu
87
87
  const configName = 'prerender';
88
88
  const configValue = getConfigValue(pageConfig, configName, 'boolean');
89
89
  if (configValue?.value === false) {
90
- const definedAtInfo = getConfigDefinedAtInfo(pageConfig, configName);
90
+ const filePath = getConfigValueFilePathToShowToUser(configValue);
91
+ assert(filePath);
91
92
  doNotPrerenderList.push({
92
93
  pageId: pageConfig.pageId,
93
94
  setByConfigName: 'prerender',
94
95
  setByConfigValue: false,
95
- setByConfigFile: definedAtInfo.filePath
96
+ setByConfigFile: filePath
96
97
  });
97
98
  }
98
99
  });
@@ -148,8 +149,7 @@ async function callOnBeforePrerenderStartHooks(prerenderContext, renderContext,
148
149
  if (!configValue)
149
150
  return;
150
151
  const hookFn = configValue.value;
151
- const definedAtInfo = getConfigDefinedAtInfo(pageConfigLoaded, hookName);
152
- const hookFilePath = definedAtInfo.filePath;
152
+ const hookFilePath = getHookFilePathToShowToUser(configValue);
153
153
  assert(hookFilePath);
154
154
  assertHookFn(hookFn, { hookName, hookFilePath });
155
155
  onBeforePrerenderStartHooks.push({
@@ -282,11 +282,12 @@ async function callOnPrerenderStartHook(prerenderContext, renderContext) {
282
282
  // V1 design
283
283
  if (renderContext.pageConfigs.length > 0) {
284
284
  const { pageConfigGlobal } = renderContext;
285
- if (pageConfigGlobal.configValues.onPrerenderStart?.value) {
286
- const { value: hookFn, definedAtInfo } = pageConfigGlobal.configValues.onPrerenderStart;
285
+ const configValue = pageConfigGlobal.configValues.onPrerenderStart;
286
+ if (configValue?.value) {
287
+ const { value: hookFn } = configValue;
287
288
  // config.onPrerenderStart isn't a computed nor a cumulative config => definedAtInfo should always be defined
288
- assert(definedAtInfo);
289
- const hookFilePath = definedAtInfo.filePath;
289
+ const hookFilePath = getHookFilePathToShowToUser(configValue);
290
+ assert(hookFilePath);
290
291
  onPrerenderStartHook = {
291
292
  hookFn,
292
293
  hookName: 'onPrerenderStart',
@@ -106,7 +106,7 @@ async function getHtmlTags(pageContext, injectToStream, injectFilter) {
106
106
  if (!isHtmlOnly) {
107
107
  // Don't allow the user to manipulate with injectFilter(): injecting <script type="application/json"> before the stream can break the app when:
108
108
  // - using https://vike.dev/stream#initial-data-after-stream-end
109
- // - `pageContext` is modified during the stream, e.g. /examples/vue-pinia which uses https://vuejs.org/api/composition-api-lifecycle.html#onserverprefetch
109
+ // - `pageContext` is modified during the stream, e.g. https://github.com/brillout/vike-with-pinia which uses https://vuejs.org/api/composition-api-lifecycle.html#onserverprefetch
110
110
  // The <script> tags are handled separately by vike down below.
111
111
  htmlTags.push({
112
112
  // Needs to be called after `resolvePageContextPromise()`
@@ -67,8 +67,8 @@ function getPagesAndRoutesInfo(pageRoutes) {
67
67
  ...entries
68
68
  ];
69
69
  const terminalWidth = getTerminalWidth() || 134;
70
- let width2 = Math.max(...linesContent.map(({ routeTypeSrc }) => routeTypeSrc.length));
71
- let width3 = Math.max(...linesContent.map(({ routeDefinedBy }) => routeDefinedBy.length));
70
+ let width2 = Math.max(...linesContent.map(({ routeTypeSrc }) => stripAnsi(routeTypeSrc).length));
71
+ let width3 = Math.max(...linesContent.map(({ routeDefinedBy }) => stripAnsi(routeDefinedBy).length));
72
72
  let width1 = terminalWidth - width3 - width2 - 10;
73
73
  linesContent.forEach((lineContent) => {
74
74
  let { routeStr } = lineContent;
@@ -83,9 +83,9 @@ function getPagesAndRoutesInfo(pageRoutes) {
83
83
  });
84
84
  width1 = Math.max(...linesContent.map(({ routeStr }) => stripAnsi(routeStr).length));
85
85
  let lines = linesContent.map(({ routeStr, routeTypeSrc, routeDefinedBy }, i) => {
86
- let cell1 = routeStr.padEnd(width1 + (routeStr.length - stripAnsi(routeStr).length), ' ');
87
- let cell2 = routeTypeSrc.padEnd(width2, ' ');
88
- let cell3 = routeDefinedBy.padEnd(width3, ' ');
86
+ let cell1 = padEnd(routeStr, width1 + (stripAnsi(routeStr).length - stripAnsi(routeStr).length));
87
+ let cell2 = padEnd(routeTypeSrc, width2);
88
+ let cell3 = padEnd(routeDefinedBy, width3);
89
89
  const isHeader = i === 0;
90
90
  if (isHeader) {
91
91
  cell1 = pc.dim(cell1);
@@ -119,6 +119,11 @@ function truncateRouteFunction(routeStr, lenMax) {
119
119
  routeStr = truncateString(routeStr, lenMax, (s) => pc.dim(s));
120
120
  return routeStr;
121
121
  }
122
+ /** Same as String.prototype.padEnd but with stripAnsi() */
123
+ function padEnd(str, width) {
124
+ const padWidth = Math.max(0, width - stripAnsi(str).length);
125
+ return str + ''.padEnd(padWidth, ' ');
126
+ }
122
127
  function removeNonAscii(str) {
123
128
  // https://stackoverflow.com/questions/20856197/remove-non-ascii-character-in-string/20856346#20856346
124
129
  return str.replace(/[^\x00-\x7F]/g, '');
@@ -20,6 +20,7 @@ import { preparePageContextForUserConsumptionServerSide } from './preparePageCon
20
20
  import { executeGuardHook } from '../../../shared/route/executeGuardHook.js';
21
21
  import { loadPageRoutes } from '../../../shared/route/loadPageRoutes.js';
22
22
  import pc from '@brillout/picocolors';
23
+ import { getConfigValueFilePathToShowToUser } from '../../../shared/page-configs/utils.js';
23
24
  async function renderPageAlreadyRouted(pageContext) {
24
25
  // pageContext._pageId can either be the:
25
26
  // - ID of the page matching the routing, or the
@@ -166,9 +167,9 @@ function assertNonMixedDesign(pageFilesAll, pageConfigs) {
166
167
  const indent = '- ';
167
168
  const v1Files = unique(pageConfigs
168
169
  .map((p) => Object.values(p.configValues)
169
- .map(({ definedAtInfo }) => definedAtInfo)
170
+ .map(getConfigValueFilePathToShowToUser)
170
171
  .filter(isNotNullish)
171
- .map((definedAtInfo) => indent + definedAtInfo.filePath))
172
+ .map((filePathToShowToUser) => indent + filePathToShowToUser))
172
173
  .flat(2));
173
174
  assertUsage(false, [
174
175
  'Mixing the new V1 design with the old V0.4 design is forbidden.',
@@ -1,15 +1,9 @@
1
1
  export { getClientEntryFilePath };
2
- import { getConfigDefinedAtInfo, getConfigValue } from '../../shared/page-configs/utils.js';
3
- import { assert } from './utils.js';
2
+ import { getConfigValue } from '../../shared/page-configs/utils.js';
4
3
  function getClientEntryFilePath(pageConfig) {
5
4
  const configName = 'client';
6
5
  const configValue = getConfigValue(pageConfig, configName, 'string');
7
6
  if (!configValue)
8
7
  return null;
9
- const definedAtInfo = getConfigDefinedAtInfo(pageConfig, configName);
10
- const { value } = configValue;
11
- // Users should be able to suppress client entry by setting its value to null
12
- assert(value !== null);
13
- const clientEntryFilePath = definedAtInfo.filePath;
14
- return clientEntryFilePath;
8
+ return configValue.value;
15
9
  }
@@ -4,7 +4,8 @@ export type { PageContextUrlComputedPropsInternal };
4
4
  export type { PageContextUrlComputedPropsClient };
5
5
  export type { PageContextUrlComputedPropsServer };
6
6
  export type { PageContextUrlSources };
7
- type UrlParsed = {
7
+ export type { Url };
8
+ type Url = {
8
9
  /** The URL origin, e.g. `https://example.com` of `https://example.com/product/42?details=yes#reviews` */
9
10
  origin: null | string;
10
11
  /** The URL pathname, e.g. `/product/42` of `https://example.com/product/42?details=yes#reviews` */
@@ -34,8 +35,9 @@ type PageContextUrlComputedPropsClient = {
34
35
  /** The URL pathname, e.g. `/product/42` of `https://example.com/product/42?details=yes#reviews` */
35
36
  urlPathname: string;
36
37
  /** Parsed information about the current URL */
37
- urlParsed: UrlParsed;
38
+ urlParsed: Url;
38
39
  };
40
+ /** For Vike internal use */
39
41
  type PageContextUrlComputedPropsInternal = PageContextUrlComputedPropsClient & {
40
42
  _urlRewrite: string | null;
41
43
  };