vike 0.4.241 → 0.4.242-commit-4a9fae0

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 (44) hide show
  1. package/dist/esm/node/api/build.js +6 -6
  2. package/dist/esm/node/api/dev.js +2 -2
  3. package/dist/esm/node/api/prepareViteApiCall.d.ts +2 -9
  4. package/dist/esm/node/api/prepareViteApiCall.js +4 -156
  5. package/dist/esm/node/api/prerender.js +2 -2
  6. package/dist/esm/node/api/preview.js +2 -2
  7. package/dist/esm/node/api/resolveViteConfigFromUser.d.ts +20 -0
  8. package/dist/esm/node/api/resolveViteConfigFromUser.js +207 -0
  9. package/dist/esm/node/prerender/runPrerenderEntry.js +4 -4
  10. package/dist/esm/node/runtime/logErrorServer.js +8 -1
  11. package/dist/esm/node/runtime-dev/createDevMiddleware.js +2 -2
  12. package/dist/esm/node/vite/index.d.ts +1 -1
  13. package/dist/esm/node/vite/index.js +52 -21
  14. package/dist/esm/node/vite/plugins/build/handleAssetsManifest.d.ts +2 -4
  15. package/dist/esm/node/vite/plugins/build/handleAssetsManifest.js +7 -11
  16. package/dist/esm/node/vite/plugins/build/pluginBuildApp.js +6 -9
  17. package/dist/esm/node/vite/plugins/build/pluginBuildConfig.js +3 -16
  18. package/dist/esm/node/vite/plugins/pluginCommon.d.ts +1 -1
  19. package/dist/esm/node/vite/plugins/pluginCommon.js +9 -7
  20. package/dist/esm/node/vite/plugins/pluginReplaceConstantsGlobalThis.d.ts +1 -0
  21. package/dist/esm/node/vite/plugins/pluginViteConfigVikeExtensions.d.ts +3 -0
  22. package/dist/esm/node/vite/plugins/pluginViteConfigVikeExtensions.js +32 -0
  23. package/dist/esm/node/vite/shared/isViteCli.d.ts +13 -0
  24. package/dist/esm/node/vite/shared/isViteCli.js +143 -0
  25. package/dist/esm/node/vite/shared/resolveVikeConfigInternal/transpileAndExecuteFile.js +11 -2
  26. package/dist/esm/node/vite/shared/resolveVikeConfigInternal.d.ts +2 -0
  27. package/dist/esm/node/vite/shared/resolveVikeConfigInternal.js +4 -0
  28. package/dist/esm/node/vite/utils.d.ts +1 -0
  29. package/dist/esm/node/vite/utils.js +1 -0
  30. package/dist/esm/shared/modifyUrlSameOrigin.js +2 -2
  31. package/dist/esm/shared/route/abort.js +2 -2
  32. package/dist/esm/shared/route/execHookOnBeforeRoute.js +3 -3
  33. package/dist/esm/types/index.d.ts +1 -0
  34. package/dist/esm/utils/PROJECT_VERSION.d.ts +1 -1
  35. package/dist/esm/utils/PROJECT_VERSION.js +1 -1
  36. package/dist/esm/utils/isExactlyOneTruthy.d.ts +1 -0
  37. package/dist/esm/utils/isExactlyOneTruthy.js +4 -0
  38. package/dist/esm/utils/parseUrl.d.ts +4 -2
  39. package/dist/esm/utils/parseUrl.js +32 -25
  40. package/dist/esm/utils/unique.d.ts +1 -2
  41. package/dist/esm/utils/unique.js +1 -2
  42. package/package.json +2 -2
  43. package/dist/esm/node/vite/shared/isViteCliCall.d.ts +0 -10
  44. package/dist/esm/node/vite/shared/isViteCliCall.js +0 -81
@@ -7,16 +7,16 @@ import { createBuilder } from 'vite';
7
7
  * https://vike.dev/api#build
8
8
  */
9
9
  async function build(options = {}) {
10
- const { viteConfigFromUserEnhanced } = await prepareViteApiCall(options, 'build');
10
+ const { viteConfigFromUserResolved } = await prepareViteApiCall(options, 'build');
11
11
  // Pass it to vike:build:pluginBuildApp
12
- if (viteConfigFromUserEnhanced)
13
- viteConfigFromUserEnhanced._viteConfigFromUserEnhanced = viteConfigFromUserEnhanced;
14
- const builder = await createBuilder(viteConfigFromUserEnhanced);
12
+ if (viteConfigFromUserResolved)
13
+ viteConfigFromUserResolved._viteConfigFromUserResolved = viteConfigFromUserResolved;
14
+ const builder = await createBuilder(viteConfigFromUserResolved);
15
15
  // buildApp() is implemented by vike:build:pluginBuildApp
16
16
  await builder.buildApp();
17
17
  return {
18
- /* We don't return `viteConfig` because `viteConfigFromUserEnhanced` is `InlineConfig` not `ResolvedConfig`
19
- viteConfig: viteConfigFromUserEnhanced,
18
+ /* We don't return `viteConfig` because `viteConfigFromUserResolved` is `InlineConfig` not `ResolvedConfig`
19
+ viteConfig: viteConfigFromUserResolved,
20
20
  */
21
21
  };
22
22
  }
@@ -7,8 +7,8 @@ import { createServer } from 'vite';
7
7
  * https://vike.dev/api#dev
8
8
  */
9
9
  async function dev(options = {}) {
10
- const { viteConfigFromUserEnhanced } = await prepareViteApiCall(options, 'dev');
11
- const server = await createServer(viteConfigFromUserEnhanced);
10
+ const { viteConfigFromUserResolved } = await prepareViteApiCall(options, 'dev');
11
+ const server = await createServer(viteConfigFromUserResolved);
12
12
  return {
13
13
  viteServer: server,
14
14
  viteConfig: server.config,
@@ -1,13 +1,6 @@
1
1
  export { prepareViteApiCall };
2
- export { getViteRoot };
3
- export { assertViteRoot };
4
- export { normalizeViteRoot };
5
- import type { InlineConfig, ResolvedConfig } from 'vite';
6
2
  import type { ApiOptions, ApiOperation } from './types.js';
7
3
  declare function prepareViteApiCall(options: ApiOptions, operation: ApiOperation): Promise<{
8
- viteConfigResolved: ResolvedConfig;
9
- viteConfigFromUserEnhanced: InlineConfig | undefined;
4
+ viteConfigResolved: import("vite").ResolvedConfig;
5
+ viteConfigFromUserResolved: import("vite").InlineConfig | undefined;
10
6
  }>;
11
- declare function getViteRoot(operation: ApiOperation): Promise<string>;
12
- declare function normalizeViteRoot(root: string): string;
13
- declare function assertViteRoot(root: string, config: ResolvedConfig): void;
@@ -1,168 +1,16 @@
1
1
  export { prepareViteApiCall };
2
- export { getViteRoot };
3
- export { assertViteRoot };
4
- export { normalizeViteRoot };
5
- import { loadConfigFromFile, mergeConfig, resolveConfig } from 'vite';
6
2
  import { clearContextVikeApiOperation, setContextVikeApiOperation } from './context.js';
7
- import { getVikeConfigInternal, getVikeConfigFromCliOrEnv, setVikeConfigContext, } from '../vite/shared/resolveVikeConfigInternal.js';
8
- import path from 'node:path';
9
- import { assert, assertUsage, getGlobalObject, isObject, pick, toPosixPath } from './utils.js';
10
- import pc from '@brillout/picocolors';
11
3
  import { clearGlobalContext } from '../runtime/globalContext.js';
12
- import { getEnvVarObject } from '../vite/shared/getEnvVarObject.js';
13
- const globalObject = getGlobalObject('api/prepareViteApiCall.ts', {});
4
+ import { getViteContextWithOperation, resolveViteConfigFromUser } from './resolveViteConfigFromUser.js';
14
5
  async function prepareViteApiCall(options, operation) {
15
6
  clear();
16
7
  setContextVikeApiOperation(operation, options);
17
- const viteConfigFromUserApiOptions = options.viteConfig;
18
- return resolveConfigs(viteConfigFromUserApiOptions, operation);
8
+ const viteConfigFromUserVikeApiOptions = options.viteConfig;
9
+ const viteContext = getViteContextWithOperation(operation);
10
+ return resolveViteConfigFromUser(viteConfigFromUserVikeApiOptions, viteContext);
19
11
  }
20
12
  // For subsequent API calls, e.g. calling prerender() after build()
21
13
  function clear() {
22
14
  clearContextVikeApiOperation();
23
15
  clearGlobalContext();
24
16
  }
25
- async function resolveConfigs(viteConfigFromUserApiOptions, operation) {
26
- const viteInfo = await getViteInfo(viteConfigFromUserApiOptions, operation);
27
- setVikeConfigContext({
28
- userRootDir: viteInfo.root,
29
- isDev: operation === 'dev',
30
- vikeVitePluginOptions: viteInfo.vikeVitePluginOptions,
31
- });
32
- const vikeConfig = await getVikeConfigInternal();
33
- const viteConfigFromUserEnhanced = applyVikeViteConfig(viteInfo.viteConfigFromUserEnhanced, vikeConfig);
34
- const { viteConfigResolved } = await assertViteRoot2(viteInfo.root, viteConfigFromUserEnhanced, operation);
35
- return {
36
- viteConfigResolved, // ONLY USE if strictly necessary. (We plan to remove assertViteRoot2() as explained in the comments of that function.)
37
- viteConfigFromUserEnhanced,
38
- };
39
- }
40
- // Apply +vite
41
- // - For example, Vike extensions adding Vite plugins
42
- function applyVikeViteConfig(viteConfigFromUserEnhanced, vikeConfig) {
43
- const viteConfigs = vikeConfig._from.configsCumulative.vite;
44
- if (!viteConfigs)
45
- return viteConfigFromUserEnhanced;
46
- viteConfigs.values.forEach((v) => {
47
- assertUsage(isObject(v.value), `${v.definedAt} should be an object`);
48
- viteConfigFromUserEnhanced = mergeConfig(viteConfigFromUserEnhanced ?? {}, v.value);
49
- assertUsage(!findVikeVitePlugin(v.value), "Using the +vite setting to add Vike's Vite plugin is forbidden");
50
- });
51
- return viteConfigFromUserEnhanced;
52
- }
53
- async function getViteRoot(operation) {
54
- if (!globalObject.root)
55
- await getViteInfo(undefined, operation);
56
- assert(globalObject.root);
57
- return globalObject.root;
58
- }
59
- async function getViteInfo(viteConfigFromUserApiOptions, operation) {
60
- let viteConfigFromUserEnhanced = viteConfigFromUserApiOptions;
61
- // Precedence:
62
- // 1) viteConfigFromUserEnvVar (highest precedence)
63
- // 2) viteConfigFromUserVikeConfig
64
- // 2) viteConfigFromUserApiOptions
65
- // 3) viteConfigFromUserViteFile (lowest precedence)
66
- // Resolve Vike's +mode setting
67
- {
68
- const viteConfigFromUserVikeConfig = pick(getVikeConfigFromCliOrEnv().vikeConfigFromCliOrEnv, ['mode']);
69
- if (Object.keys(viteConfigFromUserVikeConfig).length > 0) {
70
- viteConfigFromUserEnhanced = mergeConfig(viteConfigFromUserEnhanced ?? {}, viteConfigFromUserVikeConfig);
71
- }
72
- }
73
- // Resolve VITE_CONFIG
74
- const viteConfigFromUserEnvVar = getEnvVarObject('VITE_CONFIG');
75
- if (viteConfigFromUserEnvVar) {
76
- viteConfigFromUserEnhanced = mergeConfig(viteConfigFromUserEnhanced ?? {}, viteConfigFromUserEnvVar);
77
- }
78
- // Resolve vite.config.js
79
- const viteConfigFromUserViteFile = await loadViteConfigFile(viteConfigFromUserEnhanced, operation);
80
- // Correct precedence, replicates Vite:
81
- // https://github.com/vitejs/vite/blob/4f5845a3182fc950eb9cd76d7161698383113b18/packages/vite/src/node/config.ts#L1001
82
- const viteConfigResolved = mergeConfig(viteConfigFromUserViteFile ?? {}, viteConfigFromUserEnhanced ?? {});
83
- const root = normalizeViteRoot(viteConfigResolved.root ?? process.cwd());
84
- globalObject.root = root;
85
- // - Find options `vike(options)` set in vite.config.js
86
- // - TO-DO/next-major-release: remove
87
- // - Add Vike's Vite plugin if missing
88
- let vikeVitePluginOptions;
89
- const found = findVikeVitePlugin(viteConfigResolved);
90
- if (found) {
91
- vikeVitePluginOptions = found.vikeVitePluginOptions;
92
- }
93
- else {
94
- // Add Vike to plugins if not present.
95
- // Using a dynamic import because the script calling the Vike API may not live in the same place as vite.config.js, thus vike/plugin may resolved to two different node_modules/vike directories.
96
- const { plugin: vikePlugin } = await import('../vite/index.js');
97
- viteConfigFromUserEnhanced = {
98
- ...viteConfigFromUserEnhanced,
99
- plugins: [...(viteConfigFromUserEnhanced?.plugins ?? []), vikePlugin()],
100
- };
101
- const res = findVikeVitePlugin(viteConfigFromUserEnhanced);
102
- assert(res);
103
- vikeVitePluginOptions = res.vikeVitePluginOptions;
104
- }
105
- assert(vikeVitePluginOptions);
106
- return { root, vikeVitePluginOptions, viteConfigFromUserEnhanced };
107
- }
108
- function findVikeVitePlugin(viteConfig) {
109
- let vikeVitePluginOptions;
110
- let vikeVitePuginFound = false;
111
- viteConfig?.plugins?.forEach((p) => {
112
- if (p && '_vikeVitePluginOptions' in p) {
113
- vikeVitePuginFound = true;
114
- const options = p._vikeVitePluginOptions;
115
- vikeVitePluginOptions ?? (vikeVitePluginOptions = {});
116
- Object.assign(vikeVitePluginOptions, options);
117
- }
118
- });
119
- if (!vikeVitePuginFound)
120
- return null;
121
- return { vikeVitePluginOptions };
122
- }
123
- // Copied from https://github.com/vitejs/vite/blob/4f5845a3182fc950eb9cd76d7161698383113b18/packages/vite/src/node/config.ts#L961-L1005
124
- async function loadViteConfigFile(viteConfigFromUserApiOptions, operation) {
125
- const [inlineConfig, command, defaultMode, _defaultNodeEnv, isPreview] = getResolveConfigArgs(viteConfigFromUserApiOptions, operation);
126
- let config = inlineConfig;
127
- let mode = inlineConfig.mode || defaultMode;
128
- const configEnv = {
129
- mode,
130
- command,
131
- isSsrBuild: command === 'build' && !!config.build?.ssr,
132
- isPreview,
133
- };
134
- let { configFile } = config;
135
- if (configFile !== false) {
136
- const loadResult = await loadConfigFromFile(configEnv, configFile, config.root, config.logLevel, config.customLogger);
137
- return loadResult?.config;
138
- }
139
- return null;
140
- }
141
- function getResolveConfigArgs(viteConfig = {}, operation) {
142
- const inlineConfig = viteConfig;
143
- const command = operation === 'build' || operation === 'prerender' ? 'build' : 'serve';
144
- const defaultMode = operation === 'dev' ? 'development' : 'production';
145
- const defaultNodeEnv = defaultMode;
146
- const isPreview = operation === 'preview';
147
- return [inlineConfig, command, defaultMode, defaultNodeEnv, isPreview];
148
- }
149
- function normalizeViteRoot(root) {
150
- // `path.resolve(viteConfigFromUserViteFile.configFile, root)` could be more intuitive than `path.resolve(process.cwd(), root)` but we replicate Vite's behavior (`vite.config.js` should follow Vite's API), see:
151
- // https://github.com/vitejs/vite/blob/4f5845a3182fc950eb9cd76d7161698383113b18/packages/vite/src/node/config.ts#L1063
152
- return toPosixPath(
153
- // Equivalent to `path.resolve(process.cwd(), root)`
154
- path.resolve(root));
155
- }
156
- const errMsg = `A Vite plugin is modifying Vite's setting ${pc.cyan('root')} which is forbidden`;
157
- async function assertViteRoot2(root, viteConfigFromUserEnhanced, operation) {
158
- const args = getResolveConfigArgs(viteConfigFromUserEnhanced, operation);
159
- // We can eventually remove this resolveConfig() call (along with removing the whole assertViteRoot2() function which is redundant with the assertViteRoot() function) so that Vike doesn't make any resolveConfig() (except for pre-rendering and preview which is required). But let's keep it for now, just to see whether calling resolveConfig() can be problematic.
160
- const viteConfigResolved = await resolveConfig(...args);
161
- assertUsage(normalizeViteRoot(viteConfigResolved.root) === normalizeViteRoot(root), errMsg);
162
- return { viteConfigResolved };
163
- }
164
- function assertViteRoot(root, config) {
165
- if (globalObject.root)
166
- assert(normalizeViteRoot(globalObject.root) === normalizeViteRoot(root));
167
- assertUsage(normalizeViteRoot(root) === normalizeViteRoot(config.root), errMsg);
168
- }
@@ -7,8 +7,8 @@ import { prepareViteApiCall } from './prepareViteApiCall.js';
7
7
  * https://vike.dev/api#prerender
8
8
  */
9
9
  async function prerender(options = {}) {
10
- const { viteConfigFromUserEnhanced } = await prepareViteApiCall(options, 'prerender');
11
- options.viteConfig = viteConfigFromUserEnhanced;
10
+ const { viteConfigFromUserResolved } = await prepareViteApiCall(options, 'prerender');
11
+ options.viteConfig = viteConfigFromUserResolved;
12
12
  const { viteConfig } = await runPrerenderFromAPI(options);
13
13
  return {
14
14
  viteConfig,
@@ -13,7 +13,7 @@ import path from 'node:path';
13
13
  */
14
14
  async function preview(options = {}) {
15
15
  onSetupPreview();
16
- const { viteConfigFromUserEnhanced, viteConfigResolved } = await prepareViteApiCall(options, 'preview');
16
+ const { viteConfigFromUserResolved, viteConfigResolved } = await prepareViteApiCall(options, 'preview');
17
17
  if (viteConfigResolved.vitePluginServerEntry?.inject) {
18
18
  const outDir = getOutDirs(viteConfigResolved, undefined).outDirRoot;
19
19
  const { outServerIndex } = await importServerProductionIndex({ outDir });
@@ -24,7 +24,7 @@ async function preview(options = {}) {
24
24
  };
25
25
  }
26
26
  else {
27
- const server = await previewVite(viteConfigFromUserEnhanced);
27
+ const server = await previewVite(viteConfigFromUserResolved);
28
28
  return {
29
29
  viteServer: server,
30
30
  viteConfig: server.config,
@@ -0,0 +1,20 @@
1
+ export { resolveViteConfigFromUser };
2
+ export { isOnlyResolvingUserConfig };
3
+ export { getVikeConfigInternalEarly };
4
+ export { getViteContextWithOperation };
5
+ export { getViteRoot };
6
+ export { assertViteRoot };
7
+ export { normalizeViteRoot };
8
+ import type { InlineConfig, ResolvedConfig } from 'vite';
9
+ import type { ApiOperation } from './types.js';
10
+ declare function resolveViteConfigFromUser(viteConfigFromUserVikeApiOptions: InlineConfig | undefined, viteContext: ViteContext): Promise<{
11
+ viteConfigResolved: ResolvedConfig;
12
+ viteConfigFromUserResolved: InlineConfig | undefined;
13
+ }>;
14
+ declare function getVikeConfigInternalEarly(): Promise<import("../vite/shared/resolveVikeConfigInternal.js").VikeConfigInternal>;
15
+ declare function isOnlyResolvingUserConfig(): boolean | undefined;
16
+ declare function getViteRoot(viteContext: ViteContext): Promise<string>;
17
+ type ViteContext = 'build' | 'preview' | 'dev';
18
+ declare function getViteContextWithOperation(operation: ApiOperation): ViteContext;
19
+ declare function normalizeViteRoot(root: string): string;
20
+ declare function assertViteRoot(root: string, config: ResolvedConfig): void;
@@ -0,0 +1,207 @@
1
+ export { resolveViteConfigFromUser };
2
+ export { isOnlyResolvingUserConfig };
3
+ export { getVikeConfigInternalEarly };
4
+ export { getViteContextWithOperation };
5
+ export { getViteRoot };
6
+ export { assertViteRoot };
7
+ export { normalizeViteRoot };
8
+ import { loadConfigFromFile, mergeConfig, resolveConfig } from 'vite';
9
+ import { getVikeConfigInternal, getVikeConfigFromCliOrEnv, setVikeConfigContext, isVikeConfigContextSet, } from '../vite/shared/resolveVikeConfigInternal.js';
10
+ import path from 'node:path';
11
+ import { assert, assertUsage, assertWarning, getGlobalObject, pick, toPosixPath } from './utils.js';
12
+ import pc from '@brillout/picocolors';
13
+ import { getEnvVarObject } from '../vite/shared/getEnvVarObject.js';
14
+ import { getVikeApiOperation, isVikeCliOrApi } from './context.js';
15
+ import { getViteCommandFromCli } from '../vite/shared/isViteCli.js';
16
+ const globalObject = getGlobalObject('api/prepareViteApiCall.ts', {});
17
+ async function resolveViteConfigFromUser(viteConfigFromUserVikeApiOptions, viteContext) {
18
+ const viteInfo = await getViteInfo(viteConfigFromUserVikeApiOptions, viteContext);
19
+ setVikeConfigContext_(viteInfo, viteContext);
20
+ const { viteConfigFromUserResolved } = viteInfo;
21
+ const { viteConfigResolved } = await assertViteRoot2(viteInfo.root, viteConfigFromUserResolved, viteContext);
22
+ return {
23
+ viteConfigResolved, // ONLY USE if strictly necessary. (We plan to remove assertViteRoot2() as explained in the comments of that function.)
24
+ viteConfigFromUserResolved,
25
+ };
26
+ }
27
+ async function getVikeConfigInternalEarly() {
28
+ assert(!globalObject.isOnlyResolvingUserConfig); // ensure no infinite loop
29
+ if (!isVikeConfigContextSet()) {
30
+ const viteContext = getViteContext();
31
+ const viteInfo = await getViteInfo(undefined, viteContext);
32
+ setVikeConfigContext_(viteInfo, viteContext);
33
+ }
34
+ return await getVikeConfigInternal();
35
+ }
36
+ function setVikeConfigContext_(viteInfo, viteContext) {
37
+ setVikeConfigContext({
38
+ userRootDir: viteInfo.root,
39
+ isDev: viteContext === 'dev',
40
+ vikeVitePluginOptions: viteInfo.vikeVitePluginOptions,
41
+ });
42
+ }
43
+ function isOnlyResolvingUserConfig() {
44
+ return globalObject.isOnlyResolvingUserConfig;
45
+ }
46
+ async function getViteRoot(viteContext) {
47
+ if (!globalObject.root)
48
+ await getViteInfo(undefined, viteContext);
49
+ assert(globalObject.root);
50
+ return globalObject.root;
51
+ }
52
+ async function getViteInfo(viteConfigFromUserVikeApiOptions, viteContext) {
53
+ let viteConfigFromUserResolved = viteConfigFromUserVikeApiOptions;
54
+ // Precedence:
55
+ // 1) viteConfigFromUserEnvVar (highest precedence)
56
+ // 2) viteConfigFromUserVikeConfig
57
+ // 2) viteConfigFromUserVikeApiOptions
58
+ // 3) viteConfigFromUserViteFile (lowest precedence)
59
+ // Resolve Vike's +mode setting
60
+ {
61
+ const viteConfigFromUserVikeConfig = pick(getVikeConfigFromCliOrEnv().vikeConfigFromCliOrEnv, ['mode']);
62
+ if (Object.keys(viteConfigFromUserVikeConfig).length > 0) {
63
+ viteConfigFromUserResolved = mergeConfig(viteConfigFromUserResolved ?? {}, viteConfigFromUserVikeConfig);
64
+ }
65
+ }
66
+ // Resolve VITE_CONFIG
67
+ const viteConfigFromUserEnvVar = getEnvVarObject('VITE_CONFIG');
68
+ if (viteConfigFromUserEnvVar) {
69
+ viteConfigFromUserResolved = mergeConfig(viteConfigFromUserResolved ?? {}, viteConfigFromUserEnvVar);
70
+ }
71
+ // Resolve vite.config.js
72
+ globalObject.isOnlyResolvingUserConfig = true;
73
+ const viteConfigFromUserViteConfigFile = await loadViteConfigFile(viteConfigFromUserResolved, viteContext);
74
+ globalObject.isOnlyResolvingUserConfig = false;
75
+ // Correct precedence, replicates Vite:
76
+ // https://github.com/vitejs/vite/blob/4f5845a3182fc950eb9cd76d7161698383113b18/packages/vite/src/node/config.ts#L1001
77
+ const viteConfigResolved = mergeConfig(viteConfigFromUserViteConfigFile ?? {}, viteConfigFromUserResolved ?? {});
78
+ const root = normalizeViteRoot(viteConfigResolved.root ?? process.cwd());
79
+ globalObject.root = root;
80
+ // - Find options `vike(options)` set in vite.config.js
81
+ // - TO-DO/next-major-release: remove
82
+ // - Add Vike's Vite plugin if missing
83
+ let vikeVitePluginOptions;
84
+ const found = findVikeVitePlugin(viteConfigResolved);
85
+ if (found) {
86
+ vikeVitePluginOptions = found.vikeVitePluginOptions;
87
+ }
88
+ else {
89
+ // Show a warning because Vike supports Vite's CLI (as well as third-party CLIs).
90
+ // - Encourage users to define a vite.config.js file that also works with Vite's CLI (and potentially other third-party CLIs).
91
+ // - Vike-based frameworks, such as DocPress, allow their users to omit defining a vite.config.js file.
92
+ assertWarning(viteConfigFromUserViteConfigFile, // Only show the warning if the user defined a vite.config.js file
93
+ "Omitting Vike's Vite plugin (inside your vite.config.js) is deprecated — make sure to always add Vike's Vite plugin https://vike.dev/vite-plugin", { onlyOnce: true });
94
+ // Add Vike to plugins if not present.
95
+ // Using a dynamic import because the script calling the Vike API may not live in the same place as vite.config.js, thus vike/plugin may resolved to two different node_modules/vike directories.
96
+ const { plugin: vikePlugin } = await import('../vite/index.js');
97
+ viteConfigFromUserResolved = {
98
+ ...viteConfigFromUserResolved,
99
+ plugins: [...(viteConfigFromUserResolved?.plugins ?? []), vikePlugin()],
100
+ };
101
+ const res = findVikeVitePlugin(viteConfigFromUserResolved);
102
+ assert(res);
103
+ vikeVitePluginOptions = res.vikeVitePluginOptions;
104
+ }
105
+ assert(vikeVitePluginOptions);
106
+ return { root, vikeVitePluginOptions, viteConfigFromUserResolved };
107
+ }
108
+ function findVikeVitePlugin(viteConfig) {
109
+ let vikeVitePluginOptions;
110
+ let vikeVitePuginFound = false;
111
+ viteConfig?.plugins?.forEach((p) => {
112
+ if (p && '_vikeVitePluginOptions' in p) {
113
+ vikeVitePuginFound = true;
114
+ const options = p._vikeVitePluginOptions;
115
+ vikeVitePluginOptions ?? (vikeVitePluginOptions = {});
116
+ Object.assign(vikeVitePluginOptions, options);
117
+ }
118
+ });
119
+ if (!vikeVitePuginFound)
120
+ return null;
121
+ return { vikeVitePluginOptions };
122
+ }
123
+ // Copied from https://github.com/vitejs/vite/blob/4f5845a3182fc950eb9cd76d7161698383113b18/packages/vite/src/node/config.ts#L961-L1005
124
+ async function loadViteConfigFile(viteConfigFromUserResolved, viteContext) {
125
+ const viteContextResolved = resolveViteContext(viteConfigFromUserResolved, viteContext);
126
+ const [inlineConfig, command, defaultMode, _defaultNodeEnv, isPreview] = viteContextResolved;
127
+ let config = inlineConfig;
128
+ let mode = inlineConfig.mode || defaultMode;
129
+ const configEnv = {
130
+ mode,
131
+ command,
132
+ isSsrBuild: command === 'build' && !!config.build?.ssr,
133
+ isPreview,
134
+ };
135
+ let { configFile } = config;
136
+ if (configFile !== false) {
137
+ const loadResult = await loadConfigFromFile(configEnv, configFile, config.root, config.logLevel, config.customLogger);
138
+ if (!loadResult)
139
+ return null;
140
+ assert(loadResult.config);
141
+ return loadResult.config;
142
+ }
143
+ return null;
144
+ }
145
+ function getViteContext() {
146
+ const vikeApiOperation = getVikeApiOperation();
147
+ const viteCommand = getViteCommandFromCli();
148
+ assert(!(viteCommand && vikeApiOperation));
149
+ if (vikeApiOperation)
150
+ return getViteContextWithOperation(vikeApiOperation.operation);
151
+ assert(!isVikeCliOrApi());
152
+ if (viteCommand === 'dev' || viteCommand === 'optimize') {
153
+ return 'dev';
154
+ }
155
+ if (viteCommand === 'build') {
156
+ return 'build';
157
+ }
158
+ if (viteCommand === 'preview') {
159
+ return 'preview';
160
+ }
161
+ // Third-party CLIs.
162
+ // - Component development (e.g. Storybook) => let's consider it development
163
+ // - Testing (e.g. Vitest) => let's consider it development
164
+ return 'dev';
165
+ }
166
+ function getViteContextWithOperation(operation) {
167
+ if (operation === 'build' || operation === 'prerender') {
168
+ return 'build';
169
+ }
170
+ if (operation === 'preview') {
171
+ return 'preview';
172
+ }
173
+ if (operation === 'dev') {
174
+ return 'dev';
175
+ }
176
+ assert(false);
177
+ }
178
+ function resolveViteContext(inlineConfig = {}, viteContext) {
179
+ const isBuild = viteContext === 'build';
180
+ const isPreview = viteContext === 'preview';
181
+ const isDev = viteContext === 'dev';
182
+ const command = isBuild ? 'build' : 'serve';
183
+ const defaultMode = isDev ? 'development' : 'production';
184
+ const defaultNodeEnv = defaultMode;
185
+ const viteContextResolved = [inlineConfig, command, defaultMode, defaultNodeEnv, isPreview];
186
+ return viteContextResolved;
187
+ }
188
+ function normalizeViteRoot(root) {
189
+ // `path.resolve(viteConfigFromUserViteFile.configFile, root)` could be more intuitive than `path.resolve(process.cwd(), root)` but we replicate Vite's behavior (`vite.config.js` should follow Vite's API), see:
190
+ // https://github.com/vitejs/vite/blob/4f5845a3182fc950eb9cd76d7161698383113b18/packages/vite/src/node/config.ts#L1063
191
+ return toPosixPath(
192
+ // Equivalent to `path.resolve(process.cwd(), root)`
193
+ path.resolve(root));
194
+ }
195
+ const errMsg = `A Vite plugin is modifying Vite's setting ${pc.cyan('root')} which is forbidden`;
196
+ async function assertViteRoot2(root, viteConfigFromUserResolved, viteContext) {
197
+ const viteContextResolved = resolveViteContext(viteConfigFromUserResolved, viteContext);
198
+ // We can eventually remove this resolveConfig() call (along with removing the whole assertViteRoot2() function which is redundant with the assertViteRoot() function) so that Vike doesn't make any resolveConfig() (except for pre-rendering and preview which is required). But let's keep it for now, just to see whether calling resolveConfig() can be problematic.
199
+ const viteConfigResolved = await resolveConfig(...viteContextResolved);
200
+ assertUsage(normalizeViteRoot(viteConfigResolved.root) === normalizeViteRoot(root), errMsg);
201
+ return { viteConfigResolved };
202
+ }
203
+ function assertViteRoot(root, config) {
204
+ if (globalObject.root)
205
+ assert(normalizeViteRoot(globalObject.root) === normalizeViteRoot(root));
206
+ assertUsage(normalizeViteRoot(root) === normalizeViteRoot(config.root), errMsg);
207
+ }
@@ -6,7 +6,7 @@ import { assert } from './utils.js';
6
6
  import { logErrorHint } from '../runtime/renderPage/logErrorHint.js';
7
7
  import { prepareViteApiCall } from '../api/prepareViteApiCall.js';
8
8
  import { isVikeCli } from '../cli/context.js';
9
- import { isViteCliCall } from '../vite/shared/isViteCliCall.js';
9
+ import { isViteCli } from '../vite/shared/isViteCli.js';
10
10
  import { runPrerender } from './runPrerender.js';
11
11
  async function runPrerenderFromAPI(options = {}) {
12
12
  // - We purposely propagate the error to the user land, so that the error interrupts the user land. It's also, I guess, a nice-to-have that the user has control over the error.
@@ -16,8 +16,8 @@ async function runPrerenderFromAPI(options = {}) {
16
16
  }
17
17
  async function runPrerenderFromCLIPrerenderCommand() {
18
18
  try {
19
- const { viteConfigFromUserEnhanced } = await prepareViteApiCall({}, 'prerender');
20
- await runPrerender({ viteConfig: viteConfigFromUserEnhanced }, '$ vike prerender');
19
+ const { viteConfigFromUserResolved } = await prepareViteApiCall({}, 'prerender');
20
+ await runPrerender({ viteConfig: viteConfigFromUserResolved }, '$ vike prerender');
21
21
  }
22
22
  catch (err) {
23
23
  console.error(err);
@@ -38,7 +38,7 @@ async function runPrerenderFromAutoRun(viteConfig) {
38
38
  logErrorHint(err);
39
39
  process.exit(1);
40
40
  }
41
- const forceExit = isVikeCli() || isViteCliCall();
41
+ const forceExit = isVikeCli() || isViteCli();
42
42
  return { forceExit };
43
43
  }
44
44
  function runPrerender_forceExit() {
@@ -1,9 +1,16 @@
1
1
  export { logErrorServer };
2
2
  import pc from '@brillout/picocolors';
3
- import { isObject } from './utils.js';
3
+ import { isCallable, isObject } from './utils.js';
4
4
  import { execHookOnError } from './renderPage/execHookOnError.js';
5
5
  function logErrorServer(err) {
6
6
  execHookOnError(err);
7
+ // Set by react-streaming
8
+ // - https://github.com/brillout/react-streaming/blob/0fb5510d0a5a614f577668a519bccd62de40aed8/src/server/renderToStream/common.ts#L59-L62
9
+ // - https://gist.github.com/brillout/066293a687ab7cf695e62ad867bc6a9c
10
+ // - It doesn't seem to be needed? (The error Vike receives is already enhanced.) Should we remove this?
11
+ if (isObject(err) && isCallable(err.getEnhancedError)) {
12
+ err = err.getEnhancedError(err);
13
+ }
7
14
  // We ensure we print a string; Cloudflare Workers doesn't seem to properly stringify `Error` objects.
8
15
  // - TO-DO/eventually: is that still true? Let's eventually remove it and see if it crashes Cloudflare.
9
16
  const errStr = isObject(err) && 'stack' in err ? String(err.stack) : String(err);
@@ -18,8 +18,8 @@ async function createDevMiddleware(options = {}) {
18
18
  },
19
19
  },
20
20
  };
21
- const { viteConfigFromUserEnhanced } = await prepareViteApiCall(optionsMod, 'dev');
22
- const server = await createServer(viteConfigFromUserEnhanced);
21
+ const { viteConfigFromUserResolved } = await prepareViteApiCall(optionsMod, 'dev');
22
+ const server = await createServer(viteConfigFromUserResolved);
23
23
  const devMiddleware = server.middlewares;
24
24
  return { devMiddleware, viteServer: server, viteConfig: server.config };
25
25
  }
@@ -8,7 +8,7 @@ export type { VikeVitePluginOptions };
8
8
  type PluginInterop = Record<string, unknown> & {
9
9
  name: string;
10
10
  };
11
- declare function plugin(vikeVitePluginOptions?: VikeVitePluginOptions): PluginInterop[];
11
+ declare function plugin(vikeVitePluginOptions?: VikeVitePluginOptions): Promise<PluginInterop[]>;
12
12
  /** @deprecated Define Vike settings in +config.js instead of vite.config.js */
13
13
  type VikeVitePluginOptions = {
14
14
  /** @deprecated Define Vike settings in +config.js instead of vite.config.js */
@@ -6,7 +6,7 @@ export { getVikeConfig } from './shared/resolveVikeConfigInternal.js';
6
6
  export { PROJECT_VERSION as version } from './utils.js';
7
7
  import { getClientEntrySrcDev } from './shared/getClientEntrySrcDev.js';
8
8
  import { setGetClientEntrySrcDev } from '../runtime/renderPage/getPageAssets/retrievePageAssetsDev.js';
9
- import { assertIsNotProductionRuntime, assertUsage } from './utils.js';
9
+ import { assertIsNotProductionRuntime, assertUsage, isVitest } from './utils.js';
10
10
  import pc from '@brillout/picocolors';
11
11
  import { pluginPreview } from './plugins/pluginPreview.js';
12
12
  import { pluginDev } from './plugins/pluginDev.js';
@@ -31,31 +31,40 @@ import { pluginProdBuildEntry } from './plugins/build/pluginProdBuildEntry.js';
31
31
  import { pluginBuildConfig } from './plugins/build/pluginBuildConfig.js';
32
32
  import { pluginModuleBanner } from './plugins/build/pluginModuleBanner.js';
33
33
  import { pluginReplaceConstantsNonRunnableDev } from './plugins/non-runnable-dev/pluginReplaceConstantsNonRunnableDev.js';
34
+ import { isVikeCliOrApi } from '../api/context.js';
35
+ import { pluginViteConfigVikeExtensions } from './plugins/pluginViteConfigVikeExtensions.js';
36
+ import { isOnlyResolvingUserConfig } from '../api/resolveViteConfigFromUser.js';
34
37
  // We don't call this in ./onLoad.ts to avoid a cyclic dependency with utils.ts
35
38
  setGetClientEntrySrcDev(getClientEntrySrcDev);
36
39
  assertIsNotProductionRuntime();
37
40
  // Return `PluginInterop` instead of `Plugin` to avoid type mismatch upon different Vite versions
38
41
  function plugin(vikeVitePluginOptions = {}) {
39
- const plugins = [
40
- ...pluginCommon(vikeVitePluginOptions),
41
- ...pluginVirtualFiles(),
42
- ...pluginDev(),
43
- ...pluginBuild(),
44
- ...pluginPreview(),
45
- ...pluginExtractAssets(),
46
- ...pluginExtractExportNames(),
47
- ...pluginSetGlobalContext(),
48
- ...pluginBaseUrls(),
49
- ...pluginReplaceConstantsEnvVars(),
50
- ...pluginFileEnv(),
51
- ...pluginWorkaroundCssModuleHmr(),
52
- ...pluginWorkaroundVite6HmrRegression(),
53
- ...pluginReplaceConstantsPageContext(),
54
- ...pluginReplaceConstantsGlobalThis(),
55
- ...pluginNonRunnabeDev(),
56
- ];
57
- Object.assign(plugins, { _vikeVitePluginOptions: vikeVitePluginOptions });
58
- return plugins;
42
+ const promise = (async () => {
43
+ if (skip())
44
+ return [];
45
+ const plugins = [
46
+ ...pluginCommon(vikeVitePluginOptions),
47
+ ...pluginVirtualFiles(),
48
+ ...pluginDev(),
49
+ ...pluginBuild(),
50
+ ...pluginPreview(),
51
+ ...pluginExtractAssets(),
52
+ ...pluginExtractExportNames(),
53
+ ...pluginSetGlobalContext(),
54
+ ...pluginBaseUrls(),
55
+ ...pluginReplaceConstantsEnvVars(),
56
+ ...pluginFileEnv(),
57
+ ...pluginWorkaroundCssModuleHmr(),
58
+ ...pluginWorkaroundVite6HmrRegression(),
59
+ ...pluginReplaceConstantsPageContext(),
60
+ ...pluginReplaceConstantsGlobalThis(),
61
+ ...pluginNonRunnabeDev(),
62
+ ...(await pluginViteConfigVikeExtensions()),
63
+ ];
64
+ return plugins;
65
+ })();
66
+ Object.assign(promise, { _vikeVitePluginOptions: vikeVitePluginOptions });
67
+ return promise;
59
68
  }
60
69
  function pluginBuild() {
61
70
  return [
@@ -71,6 +80,28 @@ function pluginBuild() {
71
80
  function pluginNonRunnabeDev() {
72
81
  return [...pluginViteRPC(), ...pluginReplaceConstantsNonRunnableDev()];
73
82
  }
83
+ function skip() {
84
+ // Early resolving of user Vite configs
85
+ if (isOnlyResolvingUserConfig()) {
86
+ return true;
87
+ }
88
+ // For Vitest, we only add Vike's Vite plugin if Vike's JavaScript API is used.
89
+ // - In the context of running unit tests with Vitest, Vike's Vite plugin doesn't add any value AFAICT.
90
+ // - If the user calls Vike's JavaScript API inside Vitest (e.g. `build()` inside `beforeAll()`) => vite.config.js is loaded twice: once by Vitest and once by Vike => problematic because Vitest's environment is `development` whereas Vike's `build()` environment is `production` => the globalContext.ts isProd() function throws an assertion fail (I don't know why the two globalContext.ts instances aren't independent from each other) => that's why we skip Vike's Vite plugin when it's Vitest that loads vite.config.js
91
+ // - When calling `$ vitest` Vitest loads vite.config.js if it lives at process.cwd()
92
+ // - The user is supposed to use Vike's API instead of Vite's API. Vike supports Vite's API only for third parties (e.g. Vitest or Storybook).
93
+ // - https://vike.dev/vitest
94
+ if (
95
+ /* Maybe also all third party tools such as Storybook?
96
+ !isViteCli() &&
97
+ /*/
98
+ isVitest() &&
99
+ ///*/
100
+ !isVikeCliOrApi()) {
101
+ return true;
102
+ }
103
+ return false;
104
+ }
74
105
  // Error upon wrong usage
75
106
  Object.defineProperty(plugin, 'apply', {
76
107
  enumerable: true,