vike 0.4.230 → 0.4.231

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 (28) hide show
  1. package/dist/cjs/node/api/build.js +1 -0
  2. package/dist/cjs/node/plugin/onLoad.js +2 -0
  3. package/dist/cjs/node/plugin/plugins/build/pluginDistFileNames.js +1 -0
  4. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/assertExtensions.js +34 -12
  5. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/getPlusFilesAll.js +6 -0
  6. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +11 -2
  7. package/dist/cjs/node/runtime/html/serializeContext.js +3 -1
  8. package/dist/cjs/node/runtime/renderPage/getHttpResponseBody.js +1 -1
  9. package/dist/cjs/utils/PROJECT_VERSION.js +1 -1
  10. package/dist/cjs/utils/isDev.js +3 -1
  11. package/dist/esm/node/api/build.js +1 -0
  12. package/dist/esm/node/plugin/onLoad.js +2 -0
  13. package/dist/esm/node/plugin/plugins/build/pluginDistFileNames.js +1 -0
  14. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/assertExtensions.d.ts +1 -2
  15. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/assertExtensions.js +35 -13
  16. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/configDefinitionsBuiltIn.d.ts +12 -2
  17. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/getPlusFilesAll.js +7 -1
  18. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/loadFileAtConfigTime.d.ts +3 -3
  19. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.d.ts +2 -2
  20. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +11 -2
  21. package/dist/esm/node/runtime/html/serializeContext.js +3 -1
  22. package/dist/esm/node/runtime/renderPage/getHttpResponseBody.js +1 -1
  23. package/dist/esm/shared/page-configs/Config.d.ts +4 -1
  24. package/dist/esm/shared/page-configs/PageConfig.d.ts +3 -3
  25. package/dist/esm/utils/PROJECT_VERSION.d.ts +1 -1
  26. package/dist/esm/utils/PROJECT_VERSION.js +1 -1
  27. package/dist/esm/utils/isDev.js +3 -1
  28. package/package.json +1 -1
@@ -17,6 +17,7 @@ async function build(options = {}) {
17
17
  if (viteConfigFromUserEnhanced)
18
18
  viteConfigFromUserEnhanced._viteConfigFromUserEnhanced = viteConfigFromUserEnhanced;
19
19
  if (vikeConfig.global.config.vite6BuilderApp) {
20
+ // This assertion isn't reliable: the user may still use a Vite version older than 6.0.0 — see https://github.com/vitejs/vite/pull/19355
20
21
  (0, utils_js_1.assertVersion)('Vite', vite_1.version, '6.0.0');
21
22
  const builder = await (0, vite_1.createBuilder)(viteConfigFromUserEnhanced);
22
23
  // See Vite plugin vike:build:pluginBuildApp
@@ -11,6 +11,8 @@ function onLoad() {
11
11
  (0, assertIsNotBrowser_js_1.assertIsNotBrowser)();
12
12
  (0, assertNodeVersion_js_1.assertNodeVersion)();
13
13
  // package.json#peerDependencies isn't enough as users often ignore it
14
+ // This assertion isn't reliable: the user may still use a Vite version older than 5.1.0 — see https://github.com/vitejs/vite/pull/19355
15
+ // TO-DO/soon: let's also use this.meta.viteVersion https://github.com/vitejs/vite/pull/20088
14
16
  (0, assertVersion_js_1.assertVersion)('Vite', vite_1.version, '5.1.0');
15
17
  // Ensure we don't bloat the server runtime with heavy dependencies such Vite and esbuild
16
18
  (0, assertSetup_js_1.assertIsNotProductionRuntime)();
@@ -52,6 +52,7 @@ function pluginDistFileNames() {
52
52
  }
53
53
  }
54
54
  // Disable CSS bundling to workaround https://github.com/vikejs/vike/issues/1815
55
+ // TO-DO/eventually: let's bundle CSS again once Rolldown replaces Rollup
55
56
  if (id.endsWith('.css')) {
56
57
  const userRootDir = config.root;
57
58
  if (id.startsWith(userRootDir)) {
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.assertExtensionsConventions = assertExtensionsConventions;
7
7
  exports.assertExtensionsRequire = assertExtensionsRequire;
8
8
  const picocolors_1 = __importDefault(require("@brillout/picocolors"));
9
- const isObjectOfStrings_js_1 = require("../../../../../../utils/isObjectOfStrings.js");
10
9
  const utils_js_1 = require("../../../../utils.js");
11
10
  const getVikeConfig_js_1 = require("../getVikeConfig.js");
12
11
  const path_1 = __importDefault(require("path"));
@@ -33,8 +32,8 @@ function assertExtensionName(plusFile) {
33
32
  const name = getNameValue(plusFile);
34
33
  (0, utils_js_1.assertUsage)(name, `Vike extension name missing: the config ${filePathToShowToUser} must define the setting ${picocolors_1.default.cyan('name')}`);
35
34
  }
36
- function assertExtensionsRequire(pageConfig) {
37
- const plusFilesRelevantList = pageConfig.plusFiles;
35
+ function assertExtensionsRequire(plusFiles) {
36
+ const plusFilesRelevantList = plusFiles;
38
37
  // Collect extensions
39
38
  const extensions = {};
40
39
  plusFilesRelevantList.forEach((plusFile) => {
@@ -46,34 +45,57 @@ function assertExtensionsRequire(pageConfig) {
46
45
  });
47
46
  // Enforce `require`
48
47
  plusFilesRelevantList.forEach((plusFile) => {
49
- const require = getConfigRequireValue(plusFile);
48
+ const require = resolveRequireSetting(plusFile);
50
49
  if (!require)
51
50
  return;
52
51
  const name = getNameValue(plusFile);
53
52
  const filePathToShowToUser = getFilePathToShowToUser(plusFile);
54
53
  (0, utils_js_1.assertUsage)(name, `Setting ${picocolors_1.default.bold('name')} is required for being able to use setting ${picocolors_1.default.bold('require')} in ${filePathToShowToUser}.`);
55
- Object.entries(require).forEach(([reqName, reqVersion]) => {
54
+ Object.entries(require).forEach(([reqName, req]) => {
56
55
  const errBase = `${picocolors_1.default.bold(name)} requires ${picocolors_1.default.bold(reqName)}`;
57
56
  if (reqName === 'vike') {
58
- (0, utils_js_1.assertUsage)(isVersionRange(utils_js_1.PROJECT_VERSION, reqVersion), `${errBase} version ${picocolors_1.default.bold(reqVersion)}, but ${picocolors_1.default.bold(utils_js_1.PROJECT_VERSION)} is installed.`);
57
+ let errMsg = `${errBase} version ${picocolors_1.default.bold(req.version)}, but ${picocolors_1.default.bold(utils_js_1.PROJECT_VERSION)} is installed.`;
58
+ if (req.optional) {
59
+ errMsg += " Either update it, or remove it (it's an optional peer dependency).";
60
+ }
61
+ (0, utils_js_1.assertUsage)(isVersionRange(utils_js_1.PROJECT_VERSION, req.version), errMsg);
59
62
  return;
60
63
  }
61
64
  const extensionVersion = extensions[reqName];
62
- (0, utils_js_1.assertUsage)(extensionVersion, `${errBase}.`);
63
- (0, utils_js_1.assertUsage)(isVersionRange(extensionVersion, reqVersion), `${errBase} version ${picocolors_1.default.bold(reqVersion)}, but ${picocolors_1.default.bold(extensionVersion)} is installed.`);
65
+ if (!extensionVersion) {
66
+ if (req.optional) {
67
+ return;
68
+ }
69
+ else {
70
+ (0, utils_js_1.assertUsage)(false, `${errBase}.`);
71
+ }
72
+ }
73
+ (0, utils_js_1.assertUsage)(isVersionRange(extensionVersion, req.version), `${errBase} version ${picocolors_1.default.bold(req.version)}, but ${picocolors_1.default.bold(extensionVersion)} is installed.`);
64
74
  });
65
75
  });
66
76
  }
67
- function getConfigRequireValue(plusFile) {
77
+ function resolveRequireSetting(plusFile) {
68
78
  const confVal = (0, getVikeConfig_js_1.getConfVal)(plusFile, 'require');
69
79
  if (!confVal)
70
80
  return null;
71
81
  (0, utils_js_1.assert)(confVal.valueIsLoaded);
72
- const require = confVal.value;
82
+ const requireValue = confVal.value;
73
83
  const { filePathToShowToUserResolved } = plusFile.filePath;
74
84
  (0, utils_js_1.assert)(filePathToShowToUserResolved);
75
- (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>')}).`);
76
- return require;
85
+ (0, utils_js_1.assertUsage)((0, utils_js_1.isObject)(requireValue), `The setting ${picocolors_1.default.bold('+require')} defined at ${filePathToShowToUserResolved} should be an object`);
86
+ const requireSetting = {};
87
+ Object.entries(requireValue).forEach(([reqName, req]) => {
88
+ if (typeof req === 'string') {
89
+ requireSetting[reqName] = { version: req, optional: false };
90
+ return;
91
+ }
92
+ if ((0, utils_js_1.isObject)(req)) {
93
+ requireSetting[reqName] = req;
94
+ return;
95
+ }
96
+ (0, utils_js_1.assertUsage)(false, `Invalid +require[${JSON.stringify(reqName)}] value ${picocolors_1.default.cyan(JSON.stringify(req))}`);
97
+ });
98
+ return requireSetting;
77
99
  }
78
100
  function getNameValue(plusFile) {
79
101
  const confVal = (0, getVikeConfig_js_1.getConfVal)(plusFile, 'name');
@@ -82,8 +82,14 @@ async function getPlusFilesAll(userRootDir, esbuildCache) {
82
82
  Object.entries(plusFilesAll).forEach(([_locationId, plusFiles]) => {
83
83
  plusFiles.sort(sortMakeDeterministic);
84
84
  });
85
+ assertPlusFiles(plusFilesAll);
85
86
  return plusFilesAll;
86
87
  }
88
+ function assertPlusFiles(plusFilesAll) {
89
+ const plusFiles = Object.values(plusFilesAll).flat();
90
+ // The earlier we call it the better, so that +require can be used by Vike extensions to depend on new Vike features
91
+ (0, assertExtensions_js_1.assertExtensionsRequire)(plusFiles);
92
+ }
87
93
  function getPlusFileFromConfigFile(configFile, isExtensionConfig, locationId, userRootDir) {
88
94
  const { fileExports, filePath, extendsFilePaths } = configFile;
89
95
  const fileExportsByConfigName = {};
@@ -25,7 +25,6 @@ const loadFileAtConfigTime_js_1 = require("./getVikeConfig/loadFileAtConfigTime.
25
25
  const resolvePointerImport_js_1 = require("./getVikeConfig/resolvePointerImport.js");
26
26
  const getFilePath_js_1 = require("../../../shared/getFilePath.js");
27
27
  const getConfigValueBuildTime_js_1 = require("../../../../../shared/page-configs/getConfigValueBuildTime.js");
28
- const assertExtensions_js_1 = require("./getVikeConfig/assertExtensions.js");
29
28
  const getUserFriendlyConfigs_js_1 = require("../../../../../shared/page-configs/getUserFriendlyConfigs.js");
30
29
  const serializeConfigValues_js_1 = require("../../../../../shared/page-configs/serialize/serializeConfigValues.js");
31
30
  const getPlusFilesAll_js_1 = require("./getVikeConfig/getPlusFilesAll.js");
@@ -327,7 +326,6 @@ function assertGlobalConfigLocation(configName, sources, plusFilesAll, configDef
327
326
  }
328
327
  function assertPageConfigs(pageConfigs) {
329
328
  pageConfigs.forEach((pageConfig) => {
330
- (0, assertExtensions_js_1.assertExtensionsRequire)(pageConfig);
331
329
  assertOnBeforeRenderEnv(pageConfig);
332
330
  });
333
331
  }
@@ -710,6 +708,8 @@ function getConfigDefinitions(plusFilesRelevant, filter) {
710
708
  assertMetaUsage(meta, `Config ${picocolors_1.default.cyan('meta')} defined at ${plusFile.filePath.filePathToShowToUser}`);
711
709
  // Set configDef._userEffectDefinedAtFilePath
712
710
  Object.entries(meta).forEach(([configName, configDef]) => {
711
+ if ('isDefinedByPeerDependency' in configDef)
712
+ return;
713
713
  if (!configDef.effect)
714
714
  return;
715
715
  (0, utils_js_1.assert)(plusFile.isConfigFile);
@@ -719,6 +719,12 @@ function getConfigDefinitions(plusFilesRelevant, filter) {
719
719
  };
720
720
  });
721
721
  (0, utils_js_1.objectEntries)(meta).forEach(([configName, configDefinitionUserLand]) => {
722
+ if ('isDefinedByPeerDependency' in configDefinitionUserLand) {
723
+ configDefinitionUserLand = {
724
+ env: { client: false, server: false, config: false },
725
+ ...configDefinitionUserLand
726
+ };
727
+ }
722
728
  // User can override an existing config definition
723
729
  configDefinitions[configName] = {
724
730
  ...configDefinitions[configName],
@@ -741,6 +747,8 @@ function assertMetaUsage(metaVal, metaConfigDefinedAt) {
741
747
  (0, utils_js_1.assert)(metaConfigDefinedAt); // We expect internal effects to return a valid meta value
742
748
  (0, utils_js_1.assertUsage)(false, `${metaConfigDefinedAt} sets ${picocolors_1.default.cyan(`meta.${configName}`)} to a value with an invalid type ${picocolors_1.default.cyan(typeof def)}: it should be an object instead.`);
743
749
  }
750
+ if (def.isDefinedByPeerDependency)
751
+ return;
744
752
  // env
745
753
  let configEnv;
746
754
  {
@@ -851,6 +859,7 @@ function applyEffectMetaEnv(configModFromEffect, configValueSources, configDefEf
851
859
  }
852
860
  assertMetaUsage(configValue, configDefinedAt);
853
861
  (0, utils_js_1.objectEntries)(configValue).forEach(([configTargetName, configTargetDef]) => {
862
+ (0, utils_js_1.assert)(!('isDefinedByPeerDependency' in configTargetDef));
854
863
  {
855
864
  const keys = Object.keys(configTargetDef);
856
865
  (0, utils_js_1.assertUsage)(keys.includes('env'), notSupported);
@@ -71,7 +71,9 @@ function serializeObject(obj, objName, passToClient) {
71
71
  if ((0, stringify_1.isJsonSerializerError)(err)) {
72
72
  pathString = err.pathString;
73
73
  }
74
- (0, utils_js_1.assertUsage)(false, `Cannot serialize config ${h(pathString)} set by useConfig(), see https://vike.dev/useConfig#serialization-error`);
74
+ // There used to be a `## Serialization Error` section in the docs but we removed it at:
75
+ // https://github.com/vikejs/vike/commit/c9da2f577db01bd1c8f72265ff83e78484ddc2c0
76
+ (0, utils_js_1.assertUsage)(false, `Cannot serialize config value ${h(pathString)} set by useConfig()`);
75
77
  }
76
78
  // Non-serializable property set by the user
77
79
  let msg = [
@@ -105,7 +105,7 @@ function getHttpResponseBodyStreamHandlers(htmlRender, renderHook) {
105
105
  (0, utils_js_1.assert)(['a ', 'an ', 'the '].some((s) => streamName.startsWith(s)));
106
106
  (0, utils_js_1.assert)(renderHook);
107
107
  const { hookFilePath, hookName } = renderHook;
108
- return `Make sure the ${hookName}() defined by ${hookFilePath} hook provides ${streamName} instead`;
108
+ return `Make sure the ${hookName}() hook defined by ${hookFilePath} provides ${streamName} instead`;
109
109
  }
110
110
  }
111
111
  function getErrMsg(htmlRender, renderHook, method, msgAddendum) {
@@ -2,4 +2,4 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PROJECT_VERSION = void 0;
4
4
  // Automatically updated by @brillout/release-me
5
- exports.PROJECT_VERSION = '0.4.230';
5
+ exports.PROJECT_VERSION = '0.4.231';
@@ -6,7 +6,9 @@ exports.applyPreview = applyPreview;
6
6
  const assert_js_1 = require("./assert.js");
7
7
  function isDevCheck(configEnv) {
8
8
  const { isPreview, command } = configEnv;
9
- // `assertVersion('Vite', version, '5.1.0')` isn't enough: https://github.com/vitejs/vite/pull/19355
9
+ // Note that:
10
+ // - `assertVersion('Vite', version, '5.1.0')` at node/plugin/onLoad.ts isn't enough: https://github.com/vitejs/vite/pull/19355
11
+ // - We'll eventually be able to make this an assert() instead of assertUsage() once Vike requires a Vite version that supports this.meta.viteVersion
10
12
  (0, assert_js_1.assertUsage)(typeof isPreview === 'boolean', 'You are using an old Vite version; make sure to use Vite 5.1.0 or above.');
11
13
  return command === 'serve' && !isPreview;
12
14
  }
@@ -15,6 +15,7 @@ async function build(options = {}) {
15
15
  if (viteConfigFromUserEnhanced)
16
16
  viteConfigFromUserEnhanced._viteConfigFromUserEnhanced = viteConfigFromUserEnhanced;
17
17
  if (vikeConfig.global.config.vite6BuilderApp) {
18
+ // This assertion isn't reliable: the user may still use a Vite version older than 6.0.0 — see https://github.com/vitejs/vite/pull/19355
18
19
  assertVersion('Vite', version, '6.0.0');
19
20
  const builder = await createBuilder(viteConfigFromUserEnhanced);
20
21
  // See Vite plugin vike:build:pluginBuildApp
@@ -9,6 +9,8 @@ function onLoad() {
9
9
  assertIsNotBrowser();
10
10
  assertNodeVersion();
11
11
  // package.json#peerDependencies isn't enough as users often ignore it
12
+ // This assertion isn't reliable: the user may still use a Vite version older than 5.1.0 — see https://github.com/vitejs/vite/pull/19355
13
+ // TO-DO/soon: let's also use this.meta.viteVersion https://github.com/vitejs/vite/pull/20088
12
14
  assertVersion('Vite', version, '5.1.0');
13
15
  // Ensure we don't bloat the server runtime with heavy dependencies such Vite and esbuild
14
16
  assertIsNotProductionRuntime();
@@ -47,6 +47,7 @@ function pluginDistFileNames() {
47
47
  }
48
48
  }
49
49
  // Disable CSS bundling to workaround https://github.com/vikejs/vike/issues/1815
50
+ // TO-DO/eventually: let's bundle CSS again once Rolldown replaces Rollup
50
51
  if (id.endsWith('.css')) {
51
52
  const userRootDir = config.root;
52
53
  if (id.startsWith(userRootDir)) {
@@ -1,6 +1,5 @@
1
1
  export { assertExtensionsConventions };
2
2
  export { assertExtensionsRequire };
3
3
  import type { PlusFile } from './getPlusFilesAll.js';
4
- import { PageConfigBuildTime } from '../../../../../../shared/page-configs/PageConfig.js';
5
4
  declare function assertExtensionsConventions(plusFile: PlusFile): void;
6
- declare function assertExtensionsRequire(pageConfig: PageConfigBuildTime): void;
5
+ declare function assertExtensionsRequire(plusFiles: PlusFile[]): void;
@@ -1,8 +1,7 @@
1
1
  export { assertExtensionsConventions };
2
2
  export { assertExtensionsRequire };
3
3
  import pc from '@brillout/picocolors';
4
- import { isObjectOfStrings } from '../../../../../../utils/isObjectOfStrings.js';
5
- import { PROJECT_VERSION, assert, assertUsage, assertWarning, findPackageJson } from '../../../../utils.js';
4
+ import { PROJECT_VERSION, assert, assertUsage, assertWarning, findPackageJson, isObject } from '../../../../utils.js';
6
5
  import { getConfVal } from '../getVikeConfig.js';
7
6
  import path from 'path';
8
7
  import semver from 'semver';
@@ -28,8 +27,8 @@ function assertExtensionName(plusFile) {
28
27
  const name = getNameValue(plusFile);
29
28
  assertUsage(name, `Vike extension name missing: the config ${filePathToShowToUser} must define the setting ${pc.cyan('name')}`);
30
29
  }
31
- function assertExtensionsRequire(pageConfig) {
32
- const plusFilesRelevantList = pageConfig.plusFiles;
30
+ function assertExtensionsRequire(plusFiles) {
31
+ const plusFilesRelevantList = plusFiles;
33
32
  // Collect extensions
34
33
  const extensions = {};
35
34
  plusFilesRelevantList.forEach((plusFile) => {
@@ -41,34 +40,57 @@ function assertExtensionsRequire(pageConfig) {
41
40
  });
42
41
  // Enforce `require`
43
42
  plusFilesRelevantList.forEach((plusFile) => {
44
- const require = getConfigRequireValue(plusFile);
43
+ const require = resolveRequireSetting(plusFile);
45
44
  if (!require)
46
45
  return;
47
46
  const name = getNameValue(plusFile);
48
47
  const filePathToShowToUser = getFilePathToShowToUser(plusFile);
49
48
  assertUsage(name, `Setting ${pc.bold('name')} is required for being able to use setting ${pc.bold('require')} in ${filePathToShowToUser}.`);
50
- Object.entries(require).forEach(([reqName, reqVersion]) => {
49
+ Object.entries(require).forEach(([reqName, req]) => {
51
50
  const errBase = `${pc.bold(name)} requires ${pc.bold(reqName)}`;
52
51
  if (reqName === 'vike') {
53
- assertUsage(isVersionRange(PROJECT_VERSION, reqVersion), `${errBase} version ${pc.bold(reqVersion)}, but ${pc.bold(PROJECT_VERSION)} is installed.`);
52
+ let errMsg = `${errBase} version ${pc.bold(req.version)}, but ${pc.bold(PROJECT_VERSION)} is installed.`;
53
+ if (req.optional) {
54
+ errMsg += " Either update it, or remove it (it's an optional peer dependency).";
55
+ }
56
+ assertUsage(isVersionRange(PROJECT_VERSION, req.version), errMsg);
54
57
  return;
55
58
  }
56
59
  const extensionVersion = extensions[reqName];
57
- assertUsage(extensionVersion, `${errBase}.`);
58
- assertUsage(isVersionRange(extensionVersion, reqVersion), `${errBase} version ${pc.bold(reqVersion)}, but ${pc.bold(extensionVersion)} is installed.`);
60
+ if (!extensionVersion) {
61
+ if (req.optional) {
62
+ return;
63
+ }
64
+ else {
65
+ assertUsage(false, `${errBase}.`);
66
+ }
67
+ }
68
+ assertUsage(isVersionRange(extensionVersion, req.version), `${errBase} version ${pc.bold(req.version)}, but ${pc.bold(extensionVersion)} is installed.`);
59
69
  });
60
70
  });
61
71
  }
62
- function getConfigRequireValue(plusFile) {
72
+ function resolveRequireSetting(plusFile) {
63
73
  const confVal = getConfVal(plusFile, 'require');
64
74
  if (!confVal)
65
75
  return null;
66
76
  assert(confVal.valueIsLoaded);
67
- const require = confVal.value;
77
+ const requireValue = confVal.value;
68
78
  const { filePathToShowToUserResolved } = plusFile.filePath;
69
79
  assert(filePathToShowToUserResolved);
70
- assertUsage(isObjectOfStrings(require), `The setting ${pc.bold('require')} defined at ${filePathToShowToUserResolved} should be an object with string values (${pc.bold('Record<string, string>')}).`);
71
- return require;
80
+ assertUsage(isObject(requireValue), `The setting ${pc.bold('+require')} defined at ${filePathToShowToUserResolved} should be an object`);
81
+ const requireSetting = {};
82
+ Object.entries(requireValue).forEach(([reqName, req]) => {
83
+ if (typeof req === 'string') {
84
+ requireSetting[reqName] = { version: req, optional: false };
85
+ return;
86
+ }
87
+ if (isObject(req)) {
88
+ requireSetting[reqName] = req;
89
+ return;
90
+ }
91
+ assertUsage(false, `Invalid +require[${JSON.stringify(reqName)}] value ${pc.cyan(JSON.stringify(req))}`);
92
+ });
93
+ return requireSetting;
72
94
  }
73
95
  function getNameValue(plusFile) {
74
96
  const confVal = getConfVal(plusFile, 'name');
@@ -1,6 +1,7 @@
1
1
  export { configDefinitionsBuiltIn };
2
2
  export type { ConfigDefinition };
3
3
  export type { ConfigDefinitions };
4
+ export type { ConfigDefinitionsInternal };
4
5
  export type { ConfigDefinitionInternal };
5
6
  export type { ConfigEffect };
6
7
  import type { ConfigEnvInternal, ConfigEnv, ConfigValueSources, DefinedAtFilePath } from '../../../../../../shared/page-configs/PageConfig.js';
@@ -10,7 +11,8 @@ import { type ConfigDefinedAt } from '../../../../../../shared/page-configs/getC
10
11
  *
11
12
  * https://vike.dev/meta
12
13
  */
13
- type ConfigDefinition = {
14
+ type ConfigDefinition = ConfigDefinition_ | ConfigDefinitionDefinedByPeerDependency;
15
+ type ConfigDefinition_ = {
14
16
  /** In what environment(s) the config value is loaded.
15
17
  *
16
18
  * https://vike.dev/meta
@@ -49,6 +51,12 @@ type ConfigDefinition = {
49
51
  }) => boolean);
50
52
  type?: string | string[];
51
53
  };
54
+ type ConfigDefinitionDefinedByPeerDependency = {
55
+ /**
56
+ * Omit the "unknown config" error without defining the config — useful for optional peer dependencies: for example, vike-server sets +stream.require which is defined by vike-{react,vue,solid} but some users don't use vike-{react,vue,solid}
57
+ */
58
+ isDefinedByPeerDependency: true;
59
+ };
52
60
  /**
53
61
  * Function called when the config value is defined.
54
62
  *
@@ -67,13 +75,15 @@ type ConfigEffect = (config: {
67
75
  configDefinedAt: ConfigDefinedAt;
68
76
  }) => Config | undefined;
69
77
  /** For Vike internal use */
70
- type ConfigDefinitionInternal = Omit<ConfigDefinition, 'env'> & {
78
+ type ConfigDefinitionInternal = Omit<ConfigDefinition_, 'env'> & {
71
79
  _computed?: (configValueSources: ConfigValueSources) => unknown;
72
80
  _valueIsFilePath?: true;
73
81
  _userEffectDefinedAtFilePath?: DefinedAtFilePath;
74
82
  env: ConfigEnvInternal;
75
83
  };
76
84
  type ConfigDefinitions = Record<string, // configName
85
+ ConfigDefinition>;
86
+ type ConfigDefinitionsInternal = Record<string, // configName
77
87
  ConfigDefinitionInternal>;
78
88
  type ConfigDefinitionsBuiltIn = Record<ConfigNameBuiltIn | ConfigNameGlobal, ConfigDefinitionInternal>;
79
89
  declare const configDefinitionsBuiltIn: ConfigDefinitionsBuiltIn;
@@ -7,7 +7,7 @@ import { getConfigFileExport } from './getConfigFileExport.js';
7
7
  import { loadConfigFile, loadValueFile } from './loadFileAtConfigTime.js';
8
8
  import { resolvePointerImport } from './resolvePointerImport.js';
9
9
  import { getFilePathResolved } from '../../../../shared/getFilePath.js';
10
- import { assertExtensionsConventions } from './assertExtensions.js';
10
+ import { assertExtensionsConventions, assertExtensionsRequire } from './assertExtensions.js';
11
11
  async function getPlusFilesAll(userRootDir, esbuildCache) {
12
12
  const plusFiles = await findPlusFiles(userRootDir);
13
13
  const configFiles = [];
@@ -80,8 +80,14 @@ async function getPlusFilesAll(userRootDir, esbuildCache) {
80
80
  Object.entries(plusFilesAll).forEach(([_locationId, plusFiles]) => {
81
81
  plusFiles.sort(sortMakeDeterministic);
82
82
  });
83
+ assertPlusFiles(plusFilesAll);
83
84
  return plusFilesAll;
84
85
  }
86
+ function assertPlusFiles(plusFilesAll) {
87
+ const plusFiles = Object.values(plusFilesAll).flat();
88
+ // The earlier we call it the better, so that +require can be used by Vike extensions to depend on new Vike features
89
+ assertExtensionsRequire(plusFiles);
90
+ }
85
91
  function getPlusFileFromConfigFile(configFile, isExtensionConfig, locationId, userRootDir) {
86
92
  const { fileExports, filePath, extendsFilePaths } = configFile;
87
93
  const fileExportsByConfigName = {};
@@ -7,20 +7,20 @@ import type { FilePathResolved } from '../../../../../../shared/page-configs/Fil
7
7
  import { type EsbuildCache } from './transpileAndExecuteFile.js';
8
8
  import type { PlusFileValue } from './getPlusFilesAll.js';
9
9
  import { PointerImport } from './resolvePointerImport.js';
10
- import type { ConfigDefinitions } from './configDefinitionsBuiltIn.js';
10
+ import type { ConfigDefinitionsInternal } from './configDefinitionsBuiltIn.js';
11
11
  type ConfigFile = {
12
12
  fileExports: Record<string, unknown>;
13
13
  filePath: FilePathResolved;
14
14
  extendsFilePaths: string[];
15
15
  };
16
- declare function loadPointerImport(pointerImport: PointerImportLoaded, userRootDir: string, configName: string, configDefinitions: ConfigDefinitions, esbuildCache: EsbuildCache): Promise<unknown>;
16
+ declare function loadPointerImport(pointerImport: PointerImportLoaded, userRootDir: string, configName: string, configDefinitions: ConfigDefinitionsInternal, esbuildCache: EsbuildCache): Promise<unknown>;
17
17
  type PointerImportLoaded = PointerImport & ({
18
18
  fileExportValueLoaded: true;
19
19
  fileExportValue: unknown;
20
20
  } | {
21
21
  fileExportValueLoaded: false;
22
22
  });
23
- declare function loadValueFile(interfaceValueFile: PlusFileValue, configDefinitions: ConfigDefinitions, userRootDir: string, esbuildCache: EsbuildCache): Promise<void>;
23
+ declare function loadValueFile(interfaceValueFile: PlusFileValue, configDefinitions: ConfigDefinitionsInternal, userRootDir: string, esbuildCache: EsbuildCache): Promise<void>;
24
24
  declare function loadConfigFile(configFilePath: FilePathResolved, userRootDir: string, visited: string[], isExtensionConfig: boolean, esbuildCache: EsbuildCache): Promise<{
25
25
  configFile: ConfigFile;
26
26
  extendsConfigs: ConfigFile[];
@@ -9,7 +9,7 @@ export { getVikeConfigFromCliOrEnv };
9
9
  export { isOverriden };
10
10
  export type { VikeConfigObject };
11
11
  import type { PageConfigGlobalBuildTime, ConfigValueSource, PageConfigBuildTime } from '../../../../../shared/page-configs/PageConfig.js';
12
- import { type ConfigDefinitions, type ConfigDefinitionInternal } from './getVikeConfig/configDefinitionsBuiltIn.js';
12
+ import { type ConfigDefinitionsInternal, type ConfigDefinitionInternal } from './getVikeConfig/configDefinitionsBuiltIn.js';
13
13
  import type { ResolvedConfig, UserConfig } from 'vite';
14
14
  import { type PageConfigUserFriendly, type PageConfigsUserFriendly } from '../../../../../shared/page-configs/getUserFriendlyConfigs.js';
15
15
  import { type PlusFile } from './getVikeConfig/getPlusFilesAll.js';
@@ -34,7 +34,7 @@ declare function getVikeConfigFromCliOrEnv(): {
34
34
  configFromCliOptions: import("../../../../cli/parseCli.js").CliOptions | null;
35
35
  configFromEnvVar: Record<string, unknown> | null;
36
36
  };
37
- declare function getConfigDefinitionOptional(configDefinitions: ConfigDefinitions, configName: string): ConfigDefinitionInternal | null;
37
+ declare function getConfigDefinitionOptional(configDefinitions: ConfigDefinitionsInternal, configName: string): ConfigDefinitionInternal | null;
38
38
  declare function getConfVal(plusFile: PlusFile, configName: string): null | {
39
39
  value: unknown;
40
40
  valueIsLoaded: true;
@@ -20,7 +20,6 @@ import { loadPointerImport, loadValueFile } from './getVikeConfig/loadFileAtConf
20
20
  import { resolvePointerImport } from './getVikeConfig/resolvePointerImport.js';
21
21
  import { getFilePathResolved } from '../../../shared/getFilePath.js';
22
22
  import { getConfigValueBuildTime } from '../../../../../shared/page-configs/getConfigValueBuildTime.js';
23
- import { assertExtensionsRequire } from './getVikeConfig/assertExtensions.js';
24
23
  import { getUserFriendlyConfigsGlobal, getUserFriendlyConfigsPageEager } from '../../../../../shared/page-configs/getUserFriendlyConfigs.js';
25
24
  import { getConfigValuesBase, isJsonValue } from '../../../../../shared/page-configs/serialize/serializeConfigValues.js';
26
25
  import { getPlusFilesAll } from './getVikeConfig/getPlusFilesAll.js';
@@ -322,7 +321,6 @@ function assertGlobalConfigLocation(configName, sources, plusFilesAll, configDef
322
321
  }
323
322
  function assertPageConfigs(pageConfigs) {
324
323
  pageConfigs.forEach((pageConfig) => {
325
- assertExtensionsRequire(pageConfig);
326
324
  assertOnBeforeRenderEnv(pageConfig);
327
325
  });
328
326
  }
@@ -705,6 +703,8 @@ function getConfigDefinitions(plusFilesRelevant, filter) {
705
703
  assertMetaUsage(meta, `Config ${pc.cyan('meta')} defined at ${plusFile.filePath.filePathToShowToUser}`);
706
704
  // Set configDef._userEffectDefinedAtFilePath
707
705
  Object.entries(meta).forEach(([configName, configDef]) => {
706
+ if ('isDefinedByPeerDependency' in configDef)
707
+ return;
708
708
  if (!configDef.effect)
709
709
  return;
710
710
  assert(plusFile.isConfigFile);
@@ -714,6 +714,12 @@ function getConfigDefinitions(plusFilesRelevant, filter) {
714
714
  };
715
715
  });
716
716
  objectEntries(meta).forEach(([configName, configDefinitionUserLand]) => {
717
+ if ('isDefinedByPeerDependency' in configDefinitionUserLand) {
718
+ configDefinitionUserLand = {
719
+ env: { client: false, server: false, config: false },
720
+ ...configDefinitionUserLand
721
+ };
722
+ }
717
723
  // User can override an existing config definition
718
724
  configDefinitions[configName] = {
719
725
  ...configDefinitions[configName],
@@ -736,6 +742,8 @@ function assertMetaUsage(metaVal, metaConfigDefinedAt) {
736
742
  assert(metaConfigDefinedAt); // We expect internal effects to return a valid meta value
737
743
  assertUsage(false, `${metaConfigDefinedAt} sets ${pc.cyan(`meta.${configName}`)} to a value with an invalid type ${pc.cyan(typeof def)}: it should be an object instead.`);
738
744
  }
745
+ if (def.isDefinedByPeerDependency)
746
+ return;
739
747
  // env
740
748
  let configEnv;
741
749
  {
@@ -846,6 +854,7 @@ function applyEffectMetaEnv(configModFromEffect, configValueSources, configDefEf
846
854
  }
847
855
  assertMetaUsage(configValue, configDefinedAt);
848
856
  objectEntries(configValue).forEach(([configTargetName, configTargetDef]) => {
857
+ assert(!('isDefinedByPeerDependency' in configTargetDef));
849
858
  {
850
859
  const keys = Object.keys(configTargetDef);
851
860
  assertUsage(keys.includes('env'), notSupported);
@@ -66,7 +66,9 @@ function serializeObject(obj, objName, passToClient) {
66
66
  if (isJsonSerializerError(err)) {
67
67
  pathString = err.pathString;
68
68
  }
69
- assertUsage(false, `Cannot serialize config ${h(pathString)} set by useConfig(), see https://vike.dev/useConfig#serialization-error`);
69
+ // There used to be a `## Serialization Error` section in the docs but we removed it at:
70
+ // https://github.com/vikejs/vike/commit/c9da2f577db01bd1c8f72265ff83e78484ddc2c0
71
+ assertUsage(false, `Cannot serialize config value ${h(pathString)} set by useConfig()`);
70
72
  }
71
73
  // Non-serializable property set by the user
72
74
  let msg = [
@@ -100,7 +100,7 @@ function getHttpResponseBodyStreamHandlers(htmlRender, renderHook) {
100
100
  assert(['a ', 'an ', 'the '].some((s) => streamName.startsWith(s)));
101
101
  assert(renderHook);
102
102
  const { hookFilePath, hookName } = renderHook;
103
- return `Make sure the ${hookName}() defined by ${hookFilePath} hook provides ${streamName} instead`;
103
+ return `Make sure the ${hookName}() hook defined by ${hookFilePath} provides ${streamName} instead`;
104
104
  }
105
105
  }
106
106
  function getErrMsg(htmlRender, renderHook, method, msgAddendum) {
@@ -538,7 +538,10 @@ type ConfigBuiltIn = {
538
538
  *
539
539
  * https://vike.dev/require
540
540
  */
541
- require?: Record<string, string>;
541
+ require?: Record<string, string | {
542
+ version: string;
543
+ optional?: boolean;
544
+ }>;
542
545
  /** Whether the page scrolls to the top upon navigation.
543
546
  *
544
547
  * https://vike.dev/keepScrollPosition
@@ -23,7 +23,7 @@ export type { DefinedAtFilePath };
23
23
  import type { ConfigValueSerialized } from './serialize/PageConfigSerialized.js';
24
24
  import type { LocationId } from '../../node/plugin/plugins/importUserCode/v1-design/getVikeConfig/filesystemRouting.js';
25
25
  import type { FilePath } from './FilePath.js';
26
- import type { ConfigDefinitions } from '../../node/plugin/plugins/importUserCode/v1-design/getVikeConfig/configDefinitionsBuiltIn.js';
26
+ import type { ConfigDefinitionsInternal } from '../../node/plugin/plugins/importUserCode/v1-design/getVikeConfig/configDefinitionsBuiltIn.js';
27
27
  import type { PlusFile } from '../../node/plugin/plugins/importUserCode/v1-design/getVikeConfig/getPlusFilesAll.js';
28
28
  import type { Operation } from '../../node/api/types.js';
29
29
  type PageConfigCommon = {
@@ -51,7 +51,7 @@ type PageConfigGlobalRuntime = {
51
51
  };
52
52
  /** Page config, build-time data structure */
53
53
  type PageConfigBuildTime = PageConfigCommon & {
54
- configDefinitions: ConfigDefinitions;
54
+ configDefinitions: ConfigDefinitionsInternal;
55
55
  plusFiles: PlusFile[];
56
56
  configValueSources: ConfigValueSources;
57
57
  configValuesComputed: ConfigValuesComputed;
@@ -59,7 +59,7 @@ type PageConfigBuildTime = PageConfigCommon & {
59
59
  /** Global config that applies to all pages, build-time data structure */
60
60
  type PageConfigGlobalBuildTime = {
61
61
  configValueSources: ConfigValueSources;
62
- configDefinitions: ConfigDefinitions;
62
+ configDefinitions: ConfigDefinitionsInternal;
63
63
  configValuesComputed?: undefined;
64
64
  };
65
65
  /** Same as PageConfigRuntime but also contains all lazily loaded config values such as config.Page */
@@ -1 +1 @@
1
- export declare const PROJECT_VERSION: "0.4.230";
1
+ export declare const PROJECT_VERSION: "0.4.231";
@@ -1,2 +1,2 @@
1
1
  // Automatically updated by @brillout/release-me
2
- export const PROJECT_VERSION = '0.4.230';
2
+ export const PROJECT_VERSION = '0.4.231';
@@ -4,7 +4,9 @@ export { applyPreview };
4
4
  import { assertUsage } from './assert.js';
5
5
  function isDevCheck(configEnv) {
6
6
  const { isPreview, command } = configEnv;
7
- // `assertVersion('Vite', version, '5.1.0')` isn't enough: https://github.com/vitejs/vite/pull/19355
7
+ // Note that:
8
+ // - `assertVersion('Vite', version, '5.1.0')` at node/plugin/onLoad.ts isn't enough: https://github.com/vitejs/vite/pull/19355
9
+ // - We'll eventually be able to make this an assert() instead of assertUsage() once Vike requires a Vite version that supports this.meta.viteVersion
8
10
  assertUsage(typeof isPreview === 'boolean', 'You are using an old Vite version; make sure to use Vite 5.1.0 or above.');
9
11
  return command === 'serve' && !isPreview;
10
12
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vike",
3
- "version": "0.4.230",
3
+ "version": "0.4.231",
4
4
  "repository": "https://github.com/vikejs/vike",
5
5
  "exports": {
6
6
  "./server": {