vike 0.4.172-commit-c1dcd5f → 0.4.172-commit-55d8662

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 (25) hide show
  1. package/dist/cjs/node/plugin/plugins/commonConfig.js +4 -8
  2. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/assertExtensions.js +71 -0
  3. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/configDefinitionsBuiltIn.js +3 -0
  4. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +60 -32
  5. package/dist/cjs/node/plugin/utils.js +1 -1
  6. package/dist/cjs/utils/findFile.js +5 -3
  7. package/dist/cjs/utils/findPackageJson.js +19 -0
  8. package/dist/cjs/utils/joinEnglish.js +1 -1
  9. package/dist/cjs/utils/projectInfo.js +1 -1
  10. package/dist/esm/node/plugin/plugins/commonConfig.js +5 -9
  11. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/assertExtensions.d.ts +3 -0
  12. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/assertExtensions.js +65 -0
  13. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/configDefinitionsBuiltIn.js +3 -0
  14. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.d.ts +10 -0
  15. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +59 -31
  16. package/dist/esm/node/plugin/utils.d.ts +1 -1
  17. package/dist/esm/node/plugin/utils.js +1 -1
  18. package/dist/esm/shared/page-configs/Config.d.ts +5 -0
  19. package/dist/esm/utils/findFile.js +5 -3
  20. package/dist/esm/utils/findPackageJson.d.ts +5 -0
  21. package/dist/esm/utils/findPackageJson.js +16 -0
  22. package/dist/esm/utils/joinEnglish.js +1 -1
  23. package/dist/esm/utils/projectInfo.d.ts +2 -2
  24. package/dist/esm/utils/projectInfo.js +1 -1
  25. package/package.json +1 -1
@@ -9,11 +9,7 @@ const buildConfig_js_1 = require("./buildConfig.js");
9
9
  const require_shim_1 = require("@brillout/require-shim");
10
10
  const picocolors_1 = __importDefault(require("@brillout/picocolors"));
11
11
  const path_1 = __importDefault(require("path"));
12
- const module_1 = require("module");
13
12
  const assertResolveAlias_js_1 = require("./commonConfig/assertResolveAlias.js");
14
- // @ts-ignore Shimmed by dist-cjs-fixup.js for CJS build.
15
- const importMetaUrl = `file://${__filename}`;
16
- const require_ = (0, module_1.createRequire)(importMetaUrl);
17
13
  const pluginName = 'vike:commonConfig-1';
18
14
  function commonConfig() {
19
15
  return [
@@ -70,11 +66,11 @@ function workaroundCI(config) {
70
66
  }
71
67
  }
72
68
  function assertEsm(userViteRoot) {
73
- const packageJsonPath = (0, utils_js_1.findFile)('package.json', userViteRoot);
74
- if (!packageJsonPath)
69
+ const found = (0, utils_js_1.findPackageJson)(userViteRoot);
70
+ if (!found)
75
71
  return;
76
- const packageJson = require_(packageJsonPath);
77
- let dir = path_1.default.dirname(packageJsonPath);
72
+ const { packageJson, packageJsonPath } = found;
73
+ let dir = path_1.default.posix.dirname(packageJsonPath);
78
74
  if (dir !== '/') {
79
75
  (0, utils_js_1.assert)(!dir.endsWith('/'));
80
76
  dir = dir + '/';
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.assertExtensionsPeerDependencies = void 0;
7
+ const picocolors_1 = __importDefault(require("@brillout/picocolors"));
8
+ const isObjectOfStrings_js_1 = require("../../../../../utils/isObjectOfStrings.js");
9
+ const utils_js_1 = require("../../../utils.js");
10
+ const getVikeConfig_js_1 = require("./getVikeConfig.js");
11
+ const path_1 = __importDefault(require("path"));
12
+ const semver_1 = __importDefault(require("semver"));
13
+ function assertExtensionsPeerDependencies(interfaceFilesRelevantList) {
14
+ // Get installed extensions
15
+ const extensions = {};
16
+ interfaceFilesRelevantList.forEach((interfaceFile) => {
17
+ const name = getConfigNameValue(interfaceFile);
18
+ if (name) {
19
+ const extensionConfigFilePath = interfaceFile.filePath.filePathAbsoluteFilesystem;
20
+ const version = getExtensionVersion(extensionConfigFilePath, name);
21
+ extensions[name] = version;
22
+ }
23
+ });
24
+ // Enforce peer dependencies
25
+ interfaceFilesRelevantList.forEach((interfaceFile) => {
26
+ const require = getConfigRequireValue(interfaceFile);
27
+ if (!require)
28
+ return;
29
+ const name = getConfigNameValue(interfaceFile);
30
+ // TODO: unify assertUsage()?
31
+ (0, utils_js_1.assertUsage)(name, `Setting ${picocolors_1.default.bold('name')} is required when using setting ${picocolors_1.default.bold('require')}.`);
32
+ Object.entries(require).forEach(([reqName, reqVersion]) => {
33
+ const extensionVersion = extensions[reqName];
34
+ const errBase = `The Vike extension ${picocolors_1.default.bold(name)} requires ${picocolors_1.default.bold(reqName)}`;
35
+ (0, utils_js_1.assertUsage)(extensionVersion, `${errBase}.`);
36
+ (0, utils_js_1.assertUsage)(semver_1.default.satisfies(extensionVersion, reqVersion), `${errBase} version ${picocolors_1.default.bold(reqVersion)} but ${picocolors_1.default.bold(extensionVersion)} is installed.`);
37
+ });
38
+ });
39
+ }
40
+ exports.assertExtensionsPeerDependencies = assertExtensionsPeerDependencies;
41
+ function getConfigRequireValue(interfaceFile) {
42
+ const require = (0, getVikeConfig_js_1.getConfigValueInterfaceFile)(interfaceFile, 'require');
43
+ if (!require)
44
+ return null;
45
+ const { filePathToShowToUserResolved } = interfaceFile.filePath;
46
+ (0, utils_js_1.assert)(filePathToShowToUserResolved);
47
+ (0, utils_js_1.assertUsage)((0, isObjectOfStrings_js_1.isObjectOfStrings)(require), `The setting ${picocolors_1.default.bold('require')} defined at ${filePathToShowToUserResolved} should be an object with string values (${picocolors_1.default.bold('Record<string, string>')}).`);
48
+ return require;
49
+ }
50
+ function getConfigNameValue(interfaceFile) {
51
+ const name = (0, getVikeConfig_js_1.getConfigValueInterfaceFile)(interfaceFile, 'name');
52
+ if (!name)
53
+ return null;
54
+ // TODO: move assertUsage() here
55
+ (0, utils_js_1.assert)(typeof name === 'string');
56
+ return name;
57
+ }
58
+ // We use a forever cache: users need to restart the dev server anyways when touching node_modules/**/* (I presume Vite doesn't pick up node_modules/**/* changes).
59
+ const extensionsVersion = {};
60
+ function getExtensionVersion(extensionConfigFilePath, name) {
61
+ if (!extensionsVersion[name]) {
62
+ const found = (0, utils_js_1.findPackageJson)(path_1.default.posix.dirname(extensionConfigFilePath));
63
+ (0, utils_js_1.assert)(found);
64
+ const { packageJson, packageJsonPath } = found;
65
+ (0, utils_js_1.assertUsage)(packageJson.name === name, `The setting ${picocolors_1.default.bold('name')} set by ${extensionConfigFilePath} is ${picocolors_1.default.bold(JSON.stringify(name))} but it should be equal to ${packageJsonPath}${picocolors_1.default.dim('#')}${picocolors_1.default.bold('name')} which is ${picocolors_1.default.bold(JSON.stringify(packageJson.name))}`);
66
+ const { version } = packageJson;
67
+ (0, utils_js_1.assert)(typeof version === 'string');
68
+ extensionsVersion[name] = version;
69
+ }
70
+ return extensionsVersion[name];
71
+ }
@@ -107,6 +107,9 @@ const configDefinitionsBuiltIn = {
107
107
  },
108
108
  name: {
109
109
  env: { config: true }
110
+ },
111
+ require: {
112
+ env: { config: true }
110
113
  }
111
114
  };
112
115
  exports.configDefinitionsBuiltIn = configDefinitionsBuiltIn;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.isV1Design = exports.isVikeConfigFile = exports.vikeConfigDependencies = exports.reloadVikeConfig = exports.getVikeConfig = void 0;
6
+ exports.getConfigValueInterfaceFile = exports.isV1Design = exports.isVikeConfigFile = exports.vikeConfigDependencies = exports.reloadVikeConfig = exports.getVikeConfig = void 0;
7
7
  const utils_js_1 = require("../../../utils.js");
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const configDefinitionsBuiltIn_js_1 = require("./getVikeConfig/configDefinitionsBuiltIn.js");
@@ -22,6 +22,7 @@ const resolvePointerImport_js_1 = require("./getVikeConfig/resolvePointerImport.
22
22
  const getFilePath_js_1 = require("../../../shared/getFilePath.js");
23
23
  const getConfigValueBuildTime_js_1 = require("../../../../../shared/page-configs/getConfigValueBuildTime.js");
24
24
  const getConfigVike_js_1 = require("../../../../shared/getConfigVike.js");
25
+ const assertExtensions_js_1 = require("./assertExtensions.js");
25
26
  (0, utils_js_1.assertIsNotProductionRuntime)();
26
27
  let devServerIsCorrupt = false;
27
28
  let wasConfigInvalid = null;
@@ -125,29 +126,7 @@ async function loadInterfaceFiles(userRootDir, outDirRoot, isDev, crawlWithGit)
125
126
  ```
126
127
  */
127
128
  const interfaceFile = getInterfaceFileFromConfigFile(extendsConfig, true, locationId);
128
- {
129
- const alreadyMigrated = [
130
- 'vike-react',
131
- 'vike-react-query',
132
- 'vike-react-zustand',
133
- 'vike-vue',
134
- 'vike-pinia',
135
- 'vike-solid'
136
- ];
137
- (0, utils_js_1.assert)(extendsConfig.filePath.importPathAbsolute);
138
- const extensionName = extendsConfig.filePath.importPathAbsolute.split('/')[0];
139
- const warnMsg = alreadyMigrated.includes(extensionName)
140
- ? `You're using a deprecated version of the Vike extension ${extensionName}, update ${extensionName} to its latest version.`
141
- : `The config of the Vike extension ${extensionName} should set a ${picocolors_1.default.cyan('name')} value`;
142
- const isNameDefined = interfaceFile.fileExportsByConfigName.name?.configValue;
143
- if (alreadyMigrated) {
144
- // Eventually always make it a assertUsage()
145
- (0, utils_js_1.assertWarning)(isNameDefined, warnMsg, { onlyOnce: true });
146
- }
147
- else {
148
- (0, utils_js_1.assertUsage)(isNameDefined, warnMsg);
149
- }
150
- }
129
+ assertVikeExtensionConventions(extendsConfig, interfaceFile);
151
130
  interfaceFilesByLocationId[locationId].push(interfaceFile);
152
131
  });
153
132
  }),
@@ -186,6 +165,56 @@ async function loadInterfaceFiles(userRootDir, outDirRoot, isDev, crawlWithGit)
186
165
  assertAllConfigsAreKnown(interfaceFilesByLocationId);
187
166
  return interfaceFilesByLocationId;
188
167
  }
168
+ function assertVikeExtensionConventions(extendsConfig, interfaceFile) {
169
+ const alreadyMigrated = [
170
+ 'vike-react',
171
+ 'vike-react-query',
172
+ 'vike-react-zustand',
173
+ 'vike-vue',
174
+ 'vike-pinia',
175
+ 'vike-solid'
176
+ ];
177
+ const { importPathAbsolute } = extendsConfig.filePath;
178
+ (0, utils_js_1.assert)(importPathAbsolute);
179
+ const extensionName = importPathAbsolute
180
+ .split('/')
181
+ .slice(0, importPathAbsolute.startsWith('@') ? 2 : 1)
182
+ .join('/');
183
+ const errMsg = alreadyMigrated.includes(extensionName)
184
+ ? `You're using a deprecated version of the Vike extension ${extensionName}, update ${extensionName} to its latest version.`
185
+ : `The config of the Vike extension ${extensionName} should define the ${picocolors_1.default.cyan('name')} setting.`;
186
+ const extensionNameValue = getConfigValueInterfaceFile(interfaceFile, 'name');
187
+ if (alreadyMigrated) {
188
+ // Eventually remove (always use assertUsage())
189
+ (0, utils_js_1.assertWarning)(extensionNameValue, errMsg, { onlyOnce: true });
190
+ }
191
+ else {
192
+ (0, utils_js_1.assertUsage)(extensionNameValue, errMsg);
193
+ }
194
+ {
195
+ const { filePathToShowToUserResolved } = interfaceFile.filePath;
196
+ (0, utils_js_1.assert)(filePathToShowToUserResolved);
197
+ const errPrefix = `The setting ${picocolors_1.default.bold('name')} defined at ${filePathToShowToUserResolved}`;
198
+ (0, utils_js_1.assertUsage)(typeof extensionNameValue === 'string', `${errPrefix} should be a string.`);
199
+ (0, utils_js_1.assertWarning)(extensionNameValue === extensionName, `${errPrefix} is ${picocolors_1.default.bold(extensionNameValue)} but it should be ${picocolors_1.default.bold(extensionName)} instead.`, { onlyOnce: true });
200
+ }
201
+ {
202
+ const importPathAbsoluteExpected = `${extensionName}/config`;
203
+ (0, utils_js_1.assertWarning)(importPathAbsolute === importPathAbsoluteExpected, `The Vike configuration of ${extensionName} is exported at ${picocolors_1.default.bold(importPathAbsolute)} but it should be exported at ${picocolors_1.default.bold(importPathAbsoluteExpected)} instead.`, { onlyOnce: true });
204
+ }
205
+ if (extensionName.startsWith('vike-')) {
206
+ const prefix = [
207
+ //
208
+ 'vike-react',
209
+ 'vike-vue',
210
+ 'vike-solid',
211
+ 'vike-svelte',
212
+ 'vike-angular',
213
+ 'vike-preact'
214
+ ];
215
+ (0, utils_js_1.assertWarning)(prefix.some((p) => extensionName === p || extensionName.startsWith(`${p}-`)), `The name of the Vike extension ${picocolors_1.default.bold(extensionName)} should be or start with ${(0, utils_js_1.joinEnglish)(prefix.map(picocolors_1.default.bold), 'or')}.`, { onlyOnce: true });
216
+ }
217
+ }
189
218
  function getInterfaceFileFromConfigFile(configFile, isConfigExtend, locationId) {
190
219
  const { fileExports, filePath, extendsFilePaths } = configFile;
191
220
  const interfaceFile = {
@@ -265,9 +294,11 @@ async function loadVikeConfig(userRootDir, outDirRoot, isDev, crawlWithGit) {
265
294
  .filter(([_pageId, interfaceFiles]) => isDefiningPage(interfaceFiles))
266
295
  .map(async ([locationId]) => {
267
296
  const interfaceFilesRelevant = getInterfaceFilesRelevant(interfaceFilesByLocationId, locationId);
297
+ const interfaceFilesRelevantList = Object.values(interfaceFilesByLocationId).flat(1);
298
+ (0, assertExtensions_js_1.assertExtensionsPeerDependencies)(interfaceFilesRelevantList);
268
299
  const configDefinitions = getConfigDefinitions(interfaceFilesRelevant);
269
300
  // Load value files of custom config-only configs
270
- await Promise.all(getInterfaceFileList(interfaceFilesRelevant).map(async (interfaceFile) => {
301
+ await Promise.all(interfaceFilesRelevantList.map(async (interfaceFile) => {
271
302
  if (!interfaceFile.isValueFile)
272
303
  return;
273
304
  const { configName } = interfaceFile;
@@ -355,13 +386,6 @@ function getInterfaceFilesRelevant(interfaceFilesByLocationId, locationIdPage) {
355
386
  .sort(([locationId1], [locationId2]) => (0, filesystemRouting_js_1.sortAfterInheritanceOrder)(locationId1, locationId2, locationIdPage)));
356
387
  return interfaceFilesRelevant;
357
388
  }
358
- function getInterfaceFileList(interfaceFilesByLocationId) {
359
- const interfaceFiles = [];
360
- Object.values(interfaceFilesByLocationId).forEach((interfaceFiles_) => {
361
- interfaceFiles.push(...interfaceFiles_);
362
- });
363
- return interfaceFiles;
364
- }
365
389
  async function getGlobalConfigs(interfaceFilesByLocationId, userRootDir, importedFilesLoaded) {
366
390
  const locationIds = (0, utils_js_1.objectKeys)(interfaceFilesByLocationId);
367
391
  const interfaceFilesGlobal = (0, utils_js_1.objectFromEntries)((0, utils_js_1.objectEntries)(interfaceFilesByLocationId).filter(([locationId]) => {
@@ -975,3 +999,7 @@ function sortConfigValueSources(configValueSources, locationIdPage) {
975
999
  // Sort after the filesystem inheritance of the config value
976
1000
  .sort(([, [source1]], [, [source2]]) => (0, utils_js_1.reverse)((0, filesystemRouting_js_1.sortAfterInheritanceOrder)(source1.locationId, source2.locationId, locationIdPage))));
977
1001
  }
1002
+ function getConfigValueInterfaceFile(interfaceFile, configName) {
1003
+ return interfaceFile.fileExportsByConfigName[configName]?.configValue;
1004
+ }
1005
+ exports.getConfigValueInterfaceFile = getConfigValueInterfaceFile;
@@ -32,7 +32,7 @@ __exportStar(require("../../utils/escapeRegex.js"), exports);
32
32
  __exportStar(require("../../utils/stripAnsi.js"), exports);
33
33
  __exportStar(require("../../utils/trimWithAnsi.js"), exports);
34
34
  __exportStar(require("../../utils/removeEmptyLines.js"), exports);
35
- __exportStar(require("../../utils/findFile.js"), exports);
35
+ __exportStar(require("../../utils/findPackageJson.js"), exports);
36
36
  __exportStar(require("../../utils/getPropAccessNotation.js"), exports);
37
37
  __exportStar(require("../../utils/deepEqual.js"), exports);
38
38
  __exportStar(require("../../utils/assertKeys.js"), exports);
@@ -7,19 +7,21 @@ exports.findFile = void 0;
7
7
  const path_1 = __importDefault(require("path"));
8
8
  const fs_1 = __importDefault(require("fs"));
9
9
  const isArray_js_1 = require("./isArray.js");
10
+ const filesystemPathHandling_js_1 = require("./filesystemPathHandling.js");
10
11
  function findFile(arg, cwd) {
12
+ (0, filesystemPathHandling_js_1.assertPosixPath)(cwd);
11
13
  const filenames = (0, isArray_js_1.isArray)(arg) ? arg : [arg];
12
14
  let dir = cwd;
13
15
  while (true) {
14
16
  for (const filename of filenames) {
15
- const configFilePath = path_1.default.join(dir, `./${filename}`);
17
+ const configFilePath = path_1.default.posix.join(dir, `./${filename}`);
16
18
  if (fs_1.default.existsSync(configFilePath)) {
17
- // return toPosixPath(configFilePath)
19
+ (0, filesystemPathHandling_js_1.assertPosixPath)(configFilePath);
18
20
  return configFilePath;
19
21
  }
20
22
  }
21
23
  const dirPrevious = dir;
22
- dir = path_1.default.dirname(dir);
24
+ dir = path_1.default.posix.dirname(dir);
23
25
  if (dir === dirPrevious) {
24
26
  return null;
25
27
  }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findPackageJson = void 0;
4
+ const findFile_js_1 = require("./findFile.js");
5
+ const module_1 = require("module");
6
+ // @ts-ignore Shimmed by dist-cjs-fixup.js for CJS build.
7
+ const importMetaUrl = `file://${__filename}`;
8
+ const require_ = (0, module_1.createRequire)(importMetaUrl);
9
+ function findPackageJson(cwd) {
10
+ const packageJsonPath = (0, findFile_js_1.findFile)('package.json', cwd);
11
+ if (!packageJsonPath)
12
+ return null;
13
+ const packageJson = require_(packageJsonPath);
14
+ return {
15
+ packageJson,
16
+ packageJsonPath
17
+ };
18
+ }
19
+ exports.findPackageJson = findPackageJson;
@@ -9,6 +9,6 @@ function joinEnglish(arr, conjunction, colorizer = (s) => s) {
9
9
  return colorizer(arr[0]);
10
10
  const firsts = arr.slice(0, arr.length - 1);
11
11
  const last = arr[arr.length - 1];
12
- return firsts.map(colorizer).join(', ') + ` ${conjunction} ` + colorizer(last);
12
+ return firsts.map(colorizer).join(', ') + `, ${conjunction} ` + colorizer(last);
13
13
  }
14
14
  exports.joinEnglish = joinEnglish;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PROJECT_VERSION = exports.projectInfo = void 0;
4
- const PROJECT_VERSION = '0.4.172-commit-c1dcd5f';
4
+ const PROJECT_VERSION = '0.4.172-commit-55d8662';
5
5
  exports.PROJECT_VERSION = PROJECT_VERSION;
6
6
  const projectInfo = {
7
7
  projectName: 'Vike',
@@ -1,14 +1,10 @@
1
1
  export { commonConfig };
2
- import { assert, assertUsage, assertWarning, findFile } from '../utils.js';
2
+ import { assert, assertUsage, assertWarning, findPackageJson } from '../utils.js';
3
3
  import { assertRollupInput } from './buildConfig.js';
4
4
  import { installRequireShim_setUserRootDir } from '@brillout/require-shim';
5
5
  import pc from '@brillout/picocolors';
6
6
  import path from 'path';
7
- import { createRequire } from 'module';
8
7
  import { assertResolveAlias } from './commonConfig/assertResolveAlias.js';
9
- // @ts-ignore Shimmed by dist-cjs-fixup.js for CJS build.
10
- const importMetaUrl = import.meta.url;
11
- const require_ = createRequire(importMetaUrl);
12
8
  const pluginName = 'vike:commonConfig-1';
13
9
  function commonConfig() {
14
10
  return [
@@ -64,11 +60,11 @@ function workaroundCI(config) {
64
60
  }
65
61
  }
66
62
  function assertEsm(userViteRoot) {
67
- const packageJsonPath = findFile('package.json', userViteRoot);
68
- if (!packageJsonPath)
63
+ const found = findPackageJson(userViteRoot);
64
+ if (!found)
69
65
  return;
70
- const packageJson = require_(packageJsonPath);
71
- let dir = path.dirname(packageJsonPath);
66
+ const { packageJson, packageJsonPath } = found;
67
+ let dir = path.posix.dirname(packageJsonPath);
72
68
  if (dir !== '/') {
73
69
  assert(!dir.endsWith('/'));
74
70
  dir = dir + '/';
@@ -0,0 +1,3 @@
1
+ export { assertExtensionsPeerDependencies };
2
+ import { type InterfaceFile } from './getVikeConfig.js';
3
+ declare function assertExtensionsPeerDependencies(interfaceFilesRelevantList: InterfaceFile[]): void;
@@ -0,0 +1,65 @@
1
+ export { assertExtensionsPeerDependencies };
2
+ import pc from '@brillout/picocolors';
3
+ import { isObjectOfStrings } from '../../../../../utils/isObjectOfStrings.js';
4
+ import { assert, assertUsage, findPackageJson } from '../../../utils.js';
5
+ import { getConfigValueInterfaceFile } from './getVikeConfig.js';
6
+ import path from 'path';
7
+ import semver from 'semver';
8
+ function assertExtensionsPeerDependencies(interfaceFilesRelevantList) {
9
+ // Get installed extensions
10
+ const extensions = {};
11
+ interfaceFilesRelevantList.forEach((interfaceFile) => {
12
+ const name = getConfigNameValue(interfaceFile);
13
+ if (name) {
14
+ const extensionConfigFilePath = interfaceFile.filePath.filePathAbsoluteFilesystem;
15
+ const version = getExtensionVersion(extensionConfigFilePath, name);
16
+ extensions[name] = version;
17
+ }
18
+ });
19
+ // Enforce peer dependencies
20
+ interfaceFilesRelevantList.forEach((interfaceFile) => {
21
+ const require = getConfigRequireValue(interfaceFile);
22
+ if (!require)
23
+ return;
24
+ const name = getConfigNameValue(interfaceFile);
25
+ // TODO: unify assertUsage()?
26
+ assertUsage(name, `Setting ${pc.bold('name')} is required when using setting ${pc.bold('require')}.`);
27
+ Object.entries(require).forEach(([reqName, reqVersion]) => {
28
+ const extensionVersion = extensions[reqName];
29
+ const errBase = `The Vike extension ${pc.bold(name)} requires ${pc.bold(reqName)}`;
30
+ assertUsage(extensionVersion, `${errBase}.`);
31
+ assertUsage(semver.satisfies(extensionVersion, reqVersion), `${errBase} version ${pc.bold(reqVersion)} but ${pc.bold(extensionVersion)} is installed.`);
32
+ });
33
+ });
34
+ }
35
+ function getConfigRequireValue(interfaceFile) {
36
+ const require = getConfigValueInterfaceFile(interfaceFile, 'require');
37
+ if (!require)
38
+ return null;
39
+ const { filePathToShowToUserResolved } = interfaceFile.filePath;
40
+ assert(filePathToShowToUserResolved);
41
+ assertUsage(isObjectOfStrings(require), `The setting ${pc.bold('require')} defined at ${filePathToShowToUserResolved} should be an object with string values (${pc.bold('Record<string, string>')}).`);
42
+ return require;
43
+ }
44
+ function getConfigNameValue(interfaceFile) {
45
+ const name = getConfigValueInterfaceFile(interfaceFile, 'name');
46
+ if (!name)
47
+ return null;
48
+ // TODO: move assertUsage() here
49
+ assert(typeof name === 'string');
50
+ return name;
51
+ }
52
+ // We use a forever cache: users need to restart the dev server anyways when touching node_modules/**/* (I presume Vite doesn't pick up node_modules/**/* changes).
53
+ const extensionsVersion = {};
54
+ function getExtensionVersion(extensionConfigFilePath, name) {
55
+ if (!extensionsVersion[name]) {
56
+ const found = findPackageJson(path.posix.dirname(extensionConfigFilePath));
57
+ assert(found);
58
+ const { packageJson, packageJsonPath } = found;
59
+ assertUsage(packageJson.name === name, `The setting ${pc.bold('name')} set by ${extensionConfigFilePath} is ${pc.bold(JSON.stringify(name))} but it should be equal to ${packageJsonPath}${pc.dim('#')}${pc.bold('name')} which is ${pc.bold(JSON.stringify(packageJson.name))}`);
60
+ const { version } = packageJson;
61
+ assert(typeof version === 'string');
62
+ extensionsVersion[name] = version;
63
+ }
64
+ return extensionsVersion[name];
65
+ }
@@ -106,6 +106,9 @@ const configDefinitionsBuiltIn = {
106
106
  },
107
107
  name: {
108
108
  env: { config: true }
109
+ },
110
+ require: {
111
+ env: { config: true }
109
112
  }
110
113
  };
111
114
  const configDefinitionsBuiltInGlobal = {
@@ -3,12 +3,15 @@ export { reloadVikeConfig };
3
3
  export { vikeConfigDependencies };
4
4
  export { isVikeConfigFile };
5
5
  export { isV1Design };
6
+ export { getConfigValueInterfaceFile };
6
7
  export type { VikeConfigObject };
7
8
  export type { InterfaceValueFile };
9
+ export type { InterfaceFile };
8
10
  import type { PageConfigGlobalBuildTime, PageConfigBuildTime } from '../../../../../shared/page-configs/PageConfig.js';
9
11
  import { type LocationId } from './getVikeConfig/filesystemRouting.js';
10
12
  import type { ResolvedConfig } from 'vite';
11
13
  import type { FilePathResolved } from '../../../../../shared/page-configs/FilePath.js';
14
+ type InterfaceFile = InterfaceConfigFile | InterfaceValueFile;
12
15
  type InterfaceFileCommons = {
13
16
  locationId: LocationId;
14
17
  filePath: FilePathResolved;
@@ -16,6 +19,12 @@ type InterfaceFileCommons = {
16
19
  configValue?: unknown;
17
20
  }>;
18
21
  };
22
+ type InterfaceConfigFile = InterfaceFileCommons & {
23
+ isConfigFile: true;
24
+ isValueFile: false;
25
+ extendsFilePaths: string[];
26
+ isConfigExtend: boolean;
27
+ };
19
28
  type InterfaceValueFile = InterfaceFileCommons & {
20
29
  isConfigFile: false;
21
30
  isValueFile: true;
@@ -35,3 +44,4 @@ declare function getVikeConfig(config: ResolvedConfig, isDev: boolean, { crawlWi
35
44
  }): Promise<VikeConfigObject>;
36
45
  declare function isV1Design(config: ResolvedConfig, isDev: boolean): Promise<boolean>;
37
46
  declare function isVikeConfigFile(filePath: string): boolean;
47
+ declare function getConfigValueInterfaceFile(interfaceFile: InterfaceFile, configName: string): unknown;
@@ -3,6 +3,7 @@ export { reloadVikeConfig };
3
3
  export { vikeConfigDependencies };
4
4
  export { isVikeConfigFile };
5
5
  export { isV1Design };
6
+ export { getConfigValueInterfaceFile };
6
7
  import { assertPosixPath, assert, isObject, assertUsage, assertWarning, objectEntries, hasProp, arrayIncludes, assertIsNotProductionRuntime, getMostSimilar, joinEnglish, lowerFirst, getOutDirs, assertKeys, objectKeys, objectFromEntries, makeFirst, isNpmPackageImport, reverse } from '../../../utils.js';
7
8
  import path from 'path';
8
9
  import { configDefinitionsBuiltIn, configDefinitionsBuiltInGlobal } from './getVikeConfig/configDefinitionsBuiltIn.js';
@@ -21,6 +22,7 @@ import { clearFilesEnvMap, resolvePointerImportOfConfig } from './getVikeConfig/
21
22
  import { getFilePathResolved } from '../../../shared/getFilePath.js';
22
23
  import { getConfigValueBuildTime } from '../../../../../shared/page-configs/getConfigValueBuildTime.js';
23
24
  import { getConfigVike } from '../../../../shared/getConfigVike.js';
25
+ import { assertExtensionsPeerDependencies } from './assertExtensions.js';
24
26
  assertIsNotProductionRuntime();
25
27
  let devServerIsCorrupt = false;
26
28
  let wasConfigInvalid = null;
@@ -120,29 +122,7 @@ async function loadInterfaceFiles(userRootDir, outDirRoot, isDev, crawlWithGit)
120
122
  ```
121
123
  */
122
124
  const interfaceFile = getInterfaceFileFromConfigFile(extendsConfig, true, locationId);
123
- {
124
- const alreadyMigrated = [
125
- 'vike-react',
126
- 'vike-react-query',
127
- 'vike-react-zustand',
128
- 'vike-vue',
129
- 'vike-pinia',
130
- 'vike-solid'
131
- ];
132
- assert(extendsConfig.filePath.importPathAbsolute);
133
- const extensionName = extendsConfig.filePath.importPathAbsolute.split('/')[0];
134
- const warnMsg = alreadyMigrated.includes(extensionName)
135
- ? `You're using a deprecated version of the Vike extension ${extensionName}, update ${extensionName} to its latest version.`
136
- : `The config of the Vike extension ${extensionName} should set a ${pc.cyan('name')} value`;
137
- const isNameDefined = interfaceFile.fileExportsByConfigName.name?.configValue;
138
- if (alreadyMigrated) {
139
- // Eventually always make it a assertUsage()
140
- assertWarning(isNameDefined, warnMsg, { onlyOnce: true });
141
- }
142
- else {
143
- assertUsage(isNameDefined, warnMsg);
144
- }
145
- }
125
+ assertVikeExtensionConventions(extendsConfig, interfaceFile);
146
126
  interfaceFilesByLocationId[locationId].push(interfaceFile);
147
127
  });
148
128
  }),
@@ -181,6 +161,56 @@ async function loadInterfaceFiles(userRootDir, outDirRoot, isDev, crawlWithGit)
181
161
  assertAllConfigsAreKnown(interfaceFilesByLocationId);
182
162
  return interfaceFilesByLocationId;
183
163
  }
164
+ function assertVikeExtensionConventions(extendsConfig, interfaceFile) {
165
+ const alreadyMigrated = [
166
+ 'vike-react',
167
+ 'vike-react-query',
168
+ 'vike-react-zustand',
169
+ 'vike-vue',
170
+ 'vike-pinia',
171
+ 'vike-solid'
172
+ ];
173
+ const { importPathAbsolute } = extendsConfig.filePath;
174
+ assert(importPathAbsolute);
175
+ const extensionName = importPathAbsolute
176
+ .split('/')
177
+ .slice(0, importPathAbsolute.startsWith('@') ? 2 : 1)
178
+ .join('/');
179
+ const errMsg = alreadyMigrated.includes(extensionName)
180
+ ? `You're using a deprecated version of the Vike extension ${extensionName}, update ${extensionName} to its latest version.`
181
+ : `The config of the Vike extension ${extensionName} should define the ${pc.cyan('name')} setting.`;
182
+ const extensionNameValue = getConfigValueInterfaceFile(interfaceFile, 'name');
183
+ if (alreadyMigrated) {
184
+ // Eventually remove (always use assertUsage())
185
+ assertWarning(extensionNameValue, errMsg, { onlyOnce: true });
186
+ }
187
+ else {
188
+ assertUsage(extensionNameValue, errMsg);
189
+ }
190
+ {
191
+ const { filePathToShowToUserResolved } = interfaceFile.filePath;
192
+ assert(filePathToShowToUserResolved);
193
+ const errPrefix = `The setting ${pc.bold('name')} defined at ${filePathToShowToUserResolved}`;
194
+ assertUsage(typeof extensionNameValue === 'string', `${errPrefix} should be a string.`);
195
+ assertWarning(extensionNameValue === extensionName, `${errPrefix} is ${pc.bold(extensionNameValue)} but it should be ${pc.bold(extensionName)} instead.`, { onlyOnce: true });
196
+ }
197
+ {
198
+ const importPathAbsoluteExpected = `${extensionName}/config`;
199
+ assertWarning(importPathAbsolute === importPathAbsoluteExpected, `The Vike configuration of ${extensionName} is exported at ${pc.bold(importPathAbsolute)} but it should be exported at ${pc.bold(importPathAbsoluteExpected)} instead.`, { onlyOnce: true });
200
+ }
201
+ if (extensionName.startsWith('vike-')) {
202
+ const prefix = [
203
+ //
204
+ 'vike-react',
205
+ 'vike-vue',
206
+ 'vike-solid',
207
+ 'vike-svelte',
208
+ 'vike-angular',
209
+ 'vike-preact'
210
+ ];
211
+ assertWarning(prefix.some((p) => extensionName === p || extensionName.startsWith(`${p}-`)), `The name of the Vike extension ${pc.bold(extensionName)} should be or start with ${joinEnglish(prefix.map(pc.bold), 'or')}.`, { onlyOnce: true });
212
+ }
213
+ }
184
214
  function getInterfaceFileFromConfigFile(configFile, isConfigExtend, locationId) {
185
215
  const { fileExports, filePath, extendsFilePaths } = configFile;
186
216
  const interfaceFile = {
@@ -260,9 +290,11 @@ async function loadVikeConfig(userRootDir, outDirRoot, isDev, crawlWithGit) {
260
290
  .filter(([_pageId, interfaceFiles]) => isDefiningPage(interfaceFiles))
261
291
  .map(async ([locationId]) => {
262
292
  const interfaceFilesRelevant = getInterfaceFilesRelevant(interfaceFilesByLocationId, locationId);
293
+ const interfaceFilesRelevantList = Object.values(interfaceFilesByLocationId).flat(1);
294
+ assertExtensionsPeerDependencies(interfaceFilesRelevantList);
263
295
  const configDefinitions = getConfigDefinitions(interfaceFilesRelevant);
264
296
  // Load value files of custom config-only configs
265
- await Promise.all(getInterfaceFileList(interfaceFilesRelevant).map(async (interfaceFile) => {
297
+ await Promise.all(interfaceFilesRelevantList.map(async (interfaceFile) => {
266
298
  if (!interfaceFile.isValueFile)
267
299
  return;
268
300
  const { configName } = interfaceFile;
@@ -350,13 +382,6 @@ function getInterfaceFilesRelevant(interfaceFilesByLocationId, locationIdPage) {
350
382
  .sort(([locationId1], [locationId2]) => sortAfterInheritanceOrder(locationId1, locationId2, locationIdPage)));
351
383
  return interfaceFilesRelevant;
352
384
  }
353
- function getInterfaceFileList(interfaceFilesByLocationId) {
354
- const interfaceFiles = [];
355
- Object.values(interfaceFilesByLocationId).forEach((interfaceFiles_) => {
356
- interfaceFiles.push(...interfaceFiles_);
357
- });
358
- return interfaceFiles;
359
- }
360
385
  async function getGlobalConfigs(interfaceFilesByLocationId, userRootDir, importedFilesLoaded) {
361
386
  const locationIds = objectKeys(interfaceFilesByLocationId);
362
387
  const interfaceFilesGlobal = objectFromEntries(objectEntries(interfaceFilesByLocationId).filter(([locationId]) => {
@@ -969,3 +994,6 @@ function sortConfigValueSources(configValueSources, locationIdPage) {
969
994
  // Sort after the filesystem inheritance of the config value
970
995
  .sort(([, [source1]], [, [source2]]) => reverse(sortAfterInheritanceOrder(source1.locationId, source2.locationId, locationIdPage))));
971
996
  }
997
+ function getConfigValueInterfaceFile(interfaceFile, configName) {
998
+ return interfaceFile.fileExportsByConfigName[configName]?.configValue;
999
+ }
@@ -10,7 +10,7 @@ export * from '../../utils/escapeRegex.js';
10
10
  export * from '../../utils/stripAnsi.js';
11
11
  export * from '../../utils/trimWithAnsi.js';
12
12
  export * from '../../utils/removeEmptyLines.js';
13
- export * from '../../utils/findFile.js';
13
+ export * from '../../utils/findPackageJson.js';
14
14
  export * from '../../utils/getPropAccessNotation.js';
15
15
  export * from '../../utils/deepEqual.js';
16
16
  export * from '../../utils/assertKeys.js';
@@ -16,7 +16,7 @@ export * from '../../utils/escapeRegex.js';
16
16
  export * from '../../utils/stripAnsi.js';
17
17
  export * from '../../utils/trimWithAnsi.js';
18
18
  export * from '../../utils/removeEmptyLines.js';
19
- export * from '../../utils/findFile.js';
19
+ export * from '../../utils/findPackageJson.js';
20
20
  export * from '../../utils/getPropAccessNotation.js';
21
21
  export * from '../../utils/deepEqual.js';
22
22
  export * from '../../utils/assertKeys.js';
@@ -358,6 +358,11 @@ type ConfigBuiltIn = {
358
358
  * https://vike.dev/extends
359
359
  */
360
360
  name?: string;
361
+ /** Used by Vike extensions to enforce their peer dependencies.
362
+ *
363
+ * https://vike.dev/require
364
+ */
365
+ require?: string;
361
366
  };
362
367
  type ConfigMeta = Record<string, ConfigDefinition>;
363
368
  type ImportString = `import:${string}`;
@@ -2,19 +2,21 @@ export { findFile };
2
2
  import path from 'path';
3
3
  import fs from 'fs';
4
4
  import { isArray } from './isArray.js';
5
+ import { assertPosixPath } from './filesystemPathHandling.js';
5
6
  function findFile(arg, cwd) {
7
+ assertPosixPath(cwd);
6
8
  const filenames = isArray(arg) ? arg : [arg];
7
9
  let dir = cwd;
8
10
  while (true) {
9
11
  for (const filename of filenames) {
10
- const configFilePath = path.join(dir, `./${filename}`);
12
+ const configFilePath = path.posix.join(dir, `./${filename}`);
11
13
  if (fs.existsSync(configFilePath)) {
12
- // return toPosixPath(configFilePath)
14
+ assertPosixPath(configFilePath);
13
15
  return configFilePath;
14
16
  }
15
17
  }
16
18
  const dirPrevious = dir;
17
- dir = path.dirname(dir);
19
+ dir = path.posix.dirname(dir);
18
20
  if (dir === dirPrevious) {
19
21
  return null;
20
22
  }
@@ -0,0 +1,5 @@
1
+ export { findPackageJson };
2
+ declare function findPackageJson(cwd: string): null | {
3
+ packageJson: Record<string, unknown>;
4
+ packageJsonPath: string;
5
+ };
@@ -0,0 +1,16 @@
1
+ export { findPackageJson };
2
+ import { findFile } from './findFile.js';
3
+ import { createRequire } from 'module';
4
+ // @ts-ignore Shimmed by dist-cjs-fixup.js for CJS build.
5
+ const importMetaUrl = import.meta.url;
6
+ const require_ = createRequire(importMetaUrl);
7
+ function findPackageJson(cwd) {
8
+ const packageJsonPath = findFile('package.json', cwd);
9
+ if (!packageJsonPath)
10
+ return null;
11
+ const packageJson = require_(packageJsonPath);
12
+ return {
13
+ packageJson,
14
+ packageJsonPath
15
+ };
16
+ }
@@ -7,5 +7,5 @@ function joinEnglish(arr, conjunction, colorizer = (s) => s) {
7
7
  return colorizer(arr[0]);
8
8
  const firsts = arr.slice(0, arr.length - 1);
9
9
  const last = arr[arr.length - 1];
10
- return firsts.map(colorizer).join(', ') + ` ${conjunction} ` + colorizer(last);
10
+ return firsts.map(colorizer).join(', ') + `, ${conjunction} ` + colorizer(last);
11
11
  }
@@ -1,7 +1,7 @@
1
1
  export { projectInfo };
2
2
  export { PROJECT_VERSION };
3
- declare const PROJECT_VERSION: "0.4.172-commit-c1dcd5f";
3
+ declare const PROJECT_VERSION: "0.4.172-commit-55d8662";
4
4
  declare const projectInfo: {
5
5
  projectName: "Vike";
6
- projectVersion: "0.4.172-commit-c1dcd5f";
6
+ projectVersion: "0.4.172-commit-55d8662";
7
7
  };
@@ -1,6 +1,6 @@
1
1
  export { projectInfo };
2
2
  export { PROJECT_VERSION };
3
- const PROJECT_VERSION = '0.4.172-commit-c1dcd5f';
3
+ const PROJECT_VERSION = '0.4.172-commit-55d8662';
4
4
  const projectInfo = {
5
5
  projectName: 'Vike',
6
6
  projectVersion: PROJECT_VERSION
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vike",
3
- "version": "0.4.172-commit-c1dcd5f",
3
+ "version": "0.4.172-commit-55d8662",
4
4
  "scripts": {
5
5
  "dev": "tsc --watch",
6
6
  "build": "rimraf dist/ && pnpm run build:esm && pnpm run build:cjs",