vike 0.4.240 → 0.4.241-commit-60b0676

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 (99) hide show
  1. package/dist/esm/client/runtime-client-routing/getPageContextFromHooks.d.ts +1 -1
  2. package/dist/esm/client/runtime-client-routing/getPageContextFromHooks.js +1 -1
  3. package/dist/esm/client/runtime-client-routing/logErrorClient.d.ts +2 -0
  4. package/dist/esm/client/runtime-client-routing/logErrorClient.js +11 -0
  5. package/dist/esm/client/runtime-client-routing/renderPageClientSide.js +95 -84
  6. package/dist/esm/client/runtime-client-routing/utils.d.ts +0 -1
  7. package/dist/esm/client/runtime-client-routing/utils.js +0 -1
  8. package/dist/esm/node/api/build.js +6 -6
  9. package/dist/esm/node/api/dev.js +2 -2
  10. package/dist/esm/node/api/prepareViteApiCall.d.ts +2 -9
  11. package/dist/esm/node/api/prepareViteApiCall.js +4 -156
  12. package/dist/esm/node/api/prerender.js +2 -2
  13. package/dist/esm/node/api/preview.js +2 -2
  14. package/dist/esm/node/api/resolveViteConfigFromUser.d.ts +20 -0
  15. package/dist/esm/node/api/resolveViteConfigFromUser.js +207 -0
  16. package/dist/esm/node/cli/parseCli.js +10 -6
  17. package/dist/esm/node/prerender/runPrerender.js +2 -1
  18. package/dist/esm/node/prerender/runPrerenderEntry.js +4 -4
  19. package/dist/esm/node/runtime/globalContext.d.ts +92 -0
  20. package/dist/esm/node/runtime/globalContext.js +12 -3
  21. package/dist/esm/node/runtime/logErrorServer.d.ts +2 -0
  22. package/dist/esm/node/runtime/logErrorServer.js +18 -0
  23. package/dist/esm/node/runtime/renderPage/execHookOnError.d.ts +2 -0
  24. package/dist/esm/node/runtime/renderPage/execHookOnError.js +26 -0
  25. package/dist/esm/node/runtime/renderPage/execHookServer.d.ts +1 -1
  26. package/dist/esm/node/runtime/renderPage/loggerProd.js +3 -5
  27. package/dist/esm/node/runtime/renderPage.js +8 -7
  28. package/dist/esm/node/runtime-dev/createDevMiddleware.js +2 -2
  29. package/dist/esm/node/vite/index.d.ts +1 -1
  30. package/dist/esm/node/vite/index.js +55 -24
  31. package/dist/esm/node/vite/onLoad.js +3 -8
  32. package/dist/esm/node/vite/plugins/build/handleAssetsManifest.js +0 -1
  33. package/dist/esm/node/vite/plugins/build/pluginBuildApp.js +6 -6
  34. package/dist/esm/node/vite/plugins/build/pluginDistFileNames.js +2 -2
  35. package/dist/esm/node/vite/plugins/pluginCommon.d.ts +1 -1
  36. package/dist/esm/node/vite/plugins/pluginCommon.js +22 -9
  37. package/dist/esm/node/vite/plugins/pluginFileEnv.js +9 -6
  38. package/dist/esm/node/vite/plugins/pluginReplaceConstantsEnvVars.d.ts +3 -0
  39. package/dist/esm/node/vite/plugins/pluginReplaceConstantsEnvVars.js +129 -0
  40. package/dist/esm/node/vite/plugins/pluginReplaceConstantsGlobalThis.d.ts +10 -0
  41. package/dist/esm/node/vite/plugins/pluginReplaceConstantsGlobalThis.js +77 -0
  42. package/dist/esm/node/vite/plugins/pluginReplaceConstantsPageContext.d.ts +3 -0
  43. package/dist/esm/node/vite/plugins/{pluginReplaceIsClientSide.js → pluginReplaceConstantsPageContext.js} +5 -3
  44. package/dist/esm/node/vite/plugins/pluginVirtualFiles/generateVirtualFileGlobalEntry.js +7 -1
  45. package/dist/esm/node/vite/plugins/pluginVirtualFiles/generateVirtualFileGlobalEntryWithOldDesign.js +3 -0
  46. package/dist/esm/node/vite/plugins/pluginVirtualFiles.js +2 -2
  47. package/dist/esm/node/vite/plugins/pluginViteConfigVikeExtensions.d.ts +3 -0
  48. package/dist/esm/node/vite/plugins/pluginViteConfigVikeExtensions.js +32 -0
  49. package/dist/esm/node/vite/shared/getFilePath.d.ts +4 -6
  50. package/dist/esm/node/vite/shared/getFilePath.js +6 -11
  51. package/dist/esm/node/vite/shared/isViteCli.d.ts +13 -0
  52. package/dist/esm/node/vite/shared/isViteCli.js +143 -0
  53. package/dist/esm/node/vite/shared/isViteServerSide.d.ts +6 -3
  54. package/dist/esm/node/vite/shared/isViteServerSide.js +13 -4
  55. package/dist/esm/node/vite/shared/loggerNotProd/errorWithCodeSnippet.js +2 -2
  56. package/dist/esm/node/vite/shared/loggerNotProd/log.js +8 -2
  57. package/dist/esm/node/vite/shared/loggerNotProd.d.ts +1 -1
  58. package/dist/esm/node/vite/shared/loggerNotProd.js +11 -11
  59. package/dist/esm/node/vite/shared/loggerVite.js +4 -2
  60. package/dist/esm/node/vite/shared/resolveVikeConfigInternal/configDefinitionsBuiltIn.js +12 -2
  61. package/dist/esm/node/vite/shared/resolveVikeConfigInternal/transpileAndExecuteFile.js +12 -8
  62. package/dist/esm/node/vite/shared/resolveVikeConfigInternal.d.ts +2 -0
  63. package/dist/esm/node/vite/shared/resolveVikeConfigInternal.js +4 -0
  64. package/dist/esm/node/vite/utils.d.ts +1 -0
  65. package/dist/esm/node/vite/utils.js +1 -0
  66. package/dist/esm/shared/createGlobalContextShared.d.ts +2 -1
  67. package/dist/esm/shared/createGlobalContextShared.js +1 -1
  68. package/dist/esm/shared/hooks/execHook.d.ts +1 -1
  69. package/dist/esm/shared/hooks/getHook.d.ts +5 -4
  70. package/dist/esm/shared/route/abort.d.ts +1 -0
  71. package/dist/esm/shared/route/abort.js +12 -4
  72. package/dist/esm/shared/route/index.js +13 -4
  73. package/dist/esm/shared/route/utils.d.ts +1 -0
  74. package/dist/esm/shared/route/utils.js +1 -0
  75. package/dist/esm/types/Config.d.ts +14 -3
  76. package/dist/esm/utils/PROJECT_VERSION.d.ts +1 -1
  77. package/dist/esm/utils/PROJECT_VERSION.js +1 -1
  78. package/dist/esm/utils/assert.js +1 -0
  79. package/dist/esm/utils/assertNodeVersion.js +1 -1
  80. package/dist/esm/utils/assertViteVersion.d.ts +2 -0
  81. package/dist/esm/utils/assertViteVersion.js +11 -0
  82. package/dist/esm/utils/debug.d.ts +5 -3
  83. package/dist/esm/utils/debug.js +20 -16
  84. package/dist/esm/utils/getGlobalObject.d.ts +5 -1
  85. package/dist/esm/utils/getGlobalObject.js +5 -1
  86. package/dist/esm/utils/isExactlyOneTruthy.d.ts +1 -0
  87. package/dist/esm/utils/isExactlyOneTruthy.js +4 -0
  88. package/dist/esm/utils/isVikeReactApp.js +2 -1
  89. package/dist/esm/utils/requireResolve.js +1 -1
  90. package/package.json +3 -3
  91. package/dist/esm/node/vite/plugins/pluginEnvVars.d.ts +0 -3
  92. package/dist/esm/node/vite/plugins/pluginEnvVars.js +0 -110
  93. package/dist/esm/node/vite/plugins/pluginReplaceGlobalThisConstants.d.ts +0 -9
  94. package/dist/esm/node/vite/plugins/pluginReplaceGlobalThisConstants.js +0 -45
  95. package/dist/esm/node/vite/plugins/pluginReplaceIsClientSide.d.ts +0 -3
  96. package/dist/esm/node/vite/shared/isViteCliCall.d.ts +0 -10
  97. package/dist/esm/node/vite/shared/isViteCliCall.js +0 -81
  98. package/dist/esm/shared/route/debug.d.ts +0 -6
  99. package/dist/esm/shared/route/debug.js +0 -21
@@ -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';
@@ -16,12 +16,12 @@ import { pluginExtractExportNames } from './plugins/pluginExtractExportNames.js'
16
16
  import { pluginSetGlobalContext } from './plugins/pluginSetGlobalContext.js';
17
17
  import { pluginCommon } from './plugins/pluginCommon.js';
18
18
  import { pluginBaseUrls } from './plugins/pluginBaseUrls.js';
19
- import { pluginEnvVars } from './plugins/pluginEnvVars.js';
19
+ import { pluginReplaceConstantsEnvVars } from './plugins/pluginReplaceConstantsEnvVars.js';
20
20
  import { pluginFileEnv } from './plugins/pluginFileEnv.js';
21
21
  import { pluginWorkaroundCssModuleHmr } from './plugins/pluginWorkaroundCssModuleHmr.js';
22
22
  import { pluginWorkaroundVite6HmrRegression } from './plugins/pluginWorkaroundVite6HmrRegression.js';
23
- import { pluginReplaceIsClientSide } from './plugins/pluginReplaceIsClientSide.js';
24
- import { pluginReplaceGlobalThisConstants } from './plugins/pluginReplaceGlobalThisConstants.js';
23
+ import { pluginReplaceConstantsPageContext } from './plugins/pluginReplaceConstantsPageContext.js';
24
+ import { pluginReplaceConstantsGlobalThis } from './plugins/pluginReplaceConstantsGlobalThis.js';
25
25
  import { pluginViteRPC } from './plugins/non-runnable-dev/pluginViteRPC.js';
26
26
  import { pluginBuildApp } from './plugins/build/pluginBuildApp.js';
27
27
  import { pluginDistPackageJsonFile } from './plugins/build/pluginDistPackageJsonFile.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
- ...pluginEnvVars(),
50
- ...pluginFileEnv(),
51
- ...pluginWorkaroundCssModuleHmr(),
52
- ...pluginWorkaroundVite6HmrRegression(),
53
- ...pluginReplaceIsClientSide(),
54
- ...pluginReplaceGlobalThisConstants(),
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,
@@ -2,18 +2,13 @@ export { onLoad };
2
2
  import { assertIsNotBrowser } from '../../utils/assertIsNotBrowser.js';
3
3
  import { assertIsNotProductionRuntime, markSetup_vikeVitePlugin } from '../../utils/assertSetup.js';
4
4
  import { assertNodeVersion } from '../../utils/assertNodeVersion.js';
5
- import { assertVersion } from '../../utils/assertVersion.js';
6
- import { version } from 'vite';
5
+ import { version as viteVersion } from 'vite';
6
+ import { assertViteVersion } from '../../utils/assertViteVersion.js';
7
7
  function onLoad() {
8
8
  markSetup_vikeVitePlugin();
9
9
  assertIsNotBrowser();
10
10
  assertNodeVersion();
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 6.0.0 — see https://github.com/vitejs/vite/pull/19355
13
- // TO-DO/eventually: let's also use this.meta.viteVersion
14
- // - https://github.com/vitejs/vite/pull/20088
15
- // - https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md#700-2025-06-24
16
- assertVersion('Vite', version, ['6.3.0']);
11
+ assertViteVersion(viteVersion);
17
12
  // Ensure we don't bloat the server runtime with heavy dependencies such Vite and esbuild
18
13
  assertIsNotProductionRuntime();
19
14
  }
@@ -310,7 +310,6 @@ async function handleAssetsManifest_getBuildConfig() {
310
310
  async function handleAssetsManifest(config, viteEnv, options, bundle) {
311
311
  const isSsrEnv = isViteServerSide_onlySsrEnv(config, viteEnv);
312
312
  if (isSsrEnv) {
313
- assert(!globalObject.assetsJsonFilePath);
314
313
  const outDirs = getOutDirs(config, viteEnv);
315
314
  globalObject.assetsJsonFilePath = path.posix.join(outDirs.outDirRoot, 'assets.json');
316
315
  await writeAssetsManifestFile(globalObject.assetsJsonFilePath, config);
@@ -3,7 +3,7 @@ import { runPrerender_forceExit } from '../../../prerender/runPrerenderEntry.js'
3
3
  import { resolveOutDir } from '../../shared/getOutDirs.js';
4
4
  import { assert, assertWarning, getGlobalObject, onSetupBuild } from '../../utils.js';
5
5
  import { isPrerenderAutoRunEnabled, wasPrerenderRun } from '../../../prerender/context.js';
6
- import { isViteCliCall, getViteConfigFromCli } from '../../shared/isViteCliCall.js';
6
+ import { isViteCli, getViteConfigForBuildFromCli } from '../../shared/isViteCli.js';
7
7
  import pc from '@brillout/picocolors';
8
8
  import { logErrorHint } from '../../../runtime/renderPage/logErrorHint.js';
9
9
  import { getVikeConfigInternal } from '../../shared/resolveVikeConfigInternal.js';
@@ -142,7 +142,7 @@ async function triggerPrerendering(config, viteEnv, bundle) {
142
142
  }
143
143
  async function abortViteBuildSsr() {
144
144
  const vikeConfig = await getVikeConfigInternal();
145
- if (vikeConfig.config.disableAutoFullBuild !== true && isViteCliCall() && getViteConfigFromCli()?.build.ssr) {
145
+ if (vikeConfig.config.disableAutoFullBuild !== true && isViteCli() && getViteConfigForBuildFromCli()?.build.ssr) {
146
146
  assertWarning(false, `The CLI call ${pc.cyan('$ vite build --ssr')} is superfluous since ${pc.cyan('$ vite build')} also builds the server-side. If you want two separate build steps then use https://vike.dev/disableAutoFullBuild or use Vite's ${pc.cyan('build()')} API.`, { onlyOnce: true });
147
147
  process.exit(0);
148
148
  }
@@ -150,7 +150,7 @@ async function abortViteBuildSsr() {
150
150
  function isDisabled(vikeConfig) {
151
151
  const { disableAutoFullBuild } = vikeConfig.config;
152
152
  if (disableAutoFullBuild === undefined || disableAutoFullBuild === 'prerender') {
153
- const isUserUsingViteApi = !isViteCliCall() && !isVikeCliOrApi();
153
+ const isUserUsingViteApi = !isViteCli() && !isVikeCliOrApi();
154
154
  return isUserUsingViteApi;
155
155
  }
156
156
  else {
@@ -161,9 +161,9 @@ function isPrerenderForceExit() {
161
161
  return globalObject.forceExit;
162
162
  }
163
163
  function getFullBuildInlineConfig(config) {
164
- const configFromCli = !isViteCliCall() ? null : getViteConfigFromCli();
165
- if (config._viteConfigFromUserEnhanced) {
166
- return config._viteConfigFromUserEnhanced;
164
+ const configFromCli = !isViteCli() ? null : getViteConfigForBuildFromCli();
165
+ if (config._viteConfigFromUserResolved) {
166
+ return config._viteConfigFromUserResolved;
167
167
  }
168
168
  else {
169
169
  return {
@@ -6,7 +6,7 @@ import { assertPosixPath, assert, assertUsage, isArray, isCallable } from '../..
6
6
  import path from 'node:path';
7
7
  import crypto from 'node:crypto';
8
8
  import { getAssetsDir } from '../../shared/getAssetsDir.js';
9
- import { assertModuleId, getModuleFilePathAbsolute } from '../../shared/getFilePath.js';
9
+ import { assertModuleId, getFilePathToShowToUserModule } from '../../shared/getFilePath.js';
10
10
  function pluginDistFileNames() {
11
11
  return [
12
12
  {
@@ -63,7 +63,7 @@ function pluginDistFileNames() {
63
63
  name = isNodeModules[1];
64
64
  }
65
65
  else {
66
- const filePath = getModuleFilePathAbsolute(id, config);
66
+ const filePath = getFilePathToShowToUserModule(id, config);
67
67
  name = filePath;
68
68
  name = name.split('.').slice(0, -1).join('.'); // remove file extension
69
69
  name = name.split('/').filter(Boolean).join('_');
@@ -7,7 +7,7 @@ declare module 'vite' {
7
7
  _isDev?: boolean;
8
8
  _rootResolvedEarly?: string;
9
9
  _baseViteOriginal?: string;
10
- _viteConfigFromUserEnhanced?: InlineConfig;
10
+ _viteConfigFromUserResolved?: InlineConfig;
11
11
  }
12
12
  }
13
13
  declare global {
@@ -1,13 +1,13 @@
1
1
  export { pluginCommon };
2
- import { assert, assertUsage, assertWarning, hasProp, isDevCheck, isDocker, isObject, isVitest } from '../utils.js';
2
+ import { assert, assertUsage, assertWarning, hasProp, isDevCheck, isDocker, isExactlyOneTruthy, isObject, isVitest, } from '../utils.js';
3
3
  import { assertRollupInput } from './build/pluginBuildConfig.js';
4
4
  import { installRequireShim_setUserRootDir } from '@brillout/require-shim';
5
5
  import pc from '@brillout/picocolors';
6
6
  import { assertResolveAlias } from './pluginCommon/assertResolveAlias.js';
7
- import { isViteCliCall } from '../shared/isViteCliCall.js';
7
+ import { isViteCli } from '../shared/isViteCli.js';
8
8
  import { isVikeCliOrApi } from '../../api/context.js';
9
9
  import { getVikeConfigInternal, setVikeConfigContext } from '../shared/resolveVikeConfigInternal.js';
10
- import { assertViteRoot, getViteRoot, normalizeViteRoot } from '../../api/prepareViteApiCall.js';
10
+ import { assertViteRoot, getViteRoot, normalizeViteRoot } from '../../api/resolveViteConfigFromUser.js';
11
11
  import { temp_disablePrerenderAutoRun } from '../../prerender/context.js';
12
12
  const pluginName = 'vike:pluginCommon';
13
13
  globalThis.__VIKE__IS_PROCESS_SHARED_WITH_VITE = true;
@@ -20,12 +20,14 @@ function pluginCommon(vikeVitePluginOptions) {
20
20
  order: 'pre',
21
21
  async handler(configFromUser, env) {
22
22
  const isDev = isDevCheck(env);
23
- const operation = env.command === 'build' ? 'build' : env.isPreview ? 'preview' : 'dev';
23
+ const isBuild = env.command === 'build';
24
+ const isPreview = env.isPreview;
25
+ assert(isExactlyOneTruthy(isDev, isBuild, isPreview));
26
+ const viteContext = isBuild ? 'build' : isPreview ? 'preview' : 'dev';
24
27
  const rootResolvedEarly = configFromUser.root
25
28
  ? normalizeViteRoot(configFromUser.root)
26
- : await getViteRoot(operation);
29
+ : await getViteRoot(viteContext);
27
30
  assert(rootResolvedEarly);
28
- // TO-DO/next-major-release: we can remove setVikeConfigContext() call here since with Vike's CLI it's already called at vike/node/api/prepareViteApiCall.ts
29
31
  setVikeConfigContext({ userRootDir: rootResolvedEarly, isDev, vikeVitePluginOptions });
30
32
  const vikeConfig = await getVikeConfigInternal();
31
33
  return {
@@ -91,6 +93,11 @@ function pluginCommon(vikeVitePluginOptions) {
91
93
  // Set `--host` for Docker/Podman
92
94
  setDefault('host', true, configFromUser, configFromVike);
93
95
  }
96
+ // https://vike.dev/force
97
+ if (vikeConfig.config.force !== undefined && configFromUser.optimizeDeps?.force === undefined) {
98
+ configFromVike.optimizeDeps ?? (configFromVike.optimizeDeps = {});
99
+ configFromVike.optimizeDeps.force = vikeConfig.config.force;
100
+ }
94
101
  return configFromVike;
95
102
  },
96
103
  },
@@ -127,14 +134,20 @@ function assertSingleInstance(config) {
127
134
  function assertVikeCliOrApi(config) {
128
135
  if (isVikeCliOrApi())
129
136
  return;
130
- if (isViteCliCall()) {
137
+ if (isViteCli()) {
131
138
  assert(!isVitest());
132
139
  return;
133
140
  }
141
+ /* This warning is always shown: Vitest loads Vite *before* any Vike JavaScript API can be invoked.
134
142
  if (isVitest()) {
135
- assertWarning(false, `Unexpected Vitest setup: you seem to be using Vitest together with Vike's Vite plugin but without using Vike's JavaScript API which is unexpected, see ${pc.underline('https://vike.dev/vitest')}`, { onlyOnce: true });
136
- return;
143
+ assertWarning(
144
+ false,
145
+ `Unexpected Vitest setup: you seem to be using Vitest together with Vike's Vite plugin but without using Vike's JavaScript API which is unexpected, see ${pc.underline('https://vike.dev/vitest')}`,
146
+ { onlyOnce: true },
147
+ )
148
+ return
137
149
  }
150
+ */
138
151
  if (config.server.middlewareMode) {
139
152
  assertWarning(false, `${pc.cyan('vite.createServer()')} is deprecated ${pc.underline('https://vike.dev/migration/cli#api')}`, {
140
153
  onlyOnce: true,
@@ -3,7 +3,7 @@ import { assert, assertUsage, assertWarning, capitalizeFirstLetter, isFilePathAb
3
3
  import { extractAssetsRE } from './pluginExtractAssets.js';
4
4
  import { extractExportNamesRE } from './pluginExtractExportNames.js';
5
5
  import pc from '@brillout/picocolors';
6
- import { getModuleFilePathAbsolute } from '../shared/getFilePath.js';
6
+ import { getFilePathToShowToUserModule } from '../shared/getFilePath.js';
7
7
  import { getExportNames } from '../shared/parseEsModule.js';
8
8
  import { normalizeId } from '../shared/normalizeId.js';
9
9
  import { isV1Design } from '../shared/resolveVikeConfigInternal.js';
@@ -42,8 +42,10 @@ function pluginFileEnv() {
42
42
  if (id.endsWith('?direct'))
43
43
  id = id.slice(0, -1 * '?direct'.length);
44
44
  const moduleInfo = viteDevServer.moduleGraph.getModuleById(id);
45
- assert(moduleInfo);
46
- const importers = Array.from(moduleInfo.importers)
45
+ /* It can fail, no clue why — https://github.com/vikejs/vike/issues/2740
46
+ assert(moduleInfo, { moduleId })
47
+ */
48
+ const importers = (!moduleInfo ? [] : Array.from(moduleInfo.importers))
47
49
  .map((m) => m.id)
48
50
  .filter((id) => id !== null);
49
51
  assertFileEnv(id, isViteServerSide_extraSafe(config, this.environment, options), importers,
@@ -122,7 +124,7 @@ function pluginFileEnv() {
122
124
  const envActual = isServerSide ? 'server' : 'client';
123
125
  const envExpect = isServerSide ? 'client' : 'server';
124
126
  let errMsg;
125
- let modulePathPretty = getModuleFilePathAbsolute(modulePath, config);
127
+ let modulePathPretty = getFilePathToShowToUserModule(modulePath, config);
126
128
  if (!noColor) {
127
129
  const suffix = getSuffix(envExpect);
128
130
  modulePathPretty = modulePathPretty.replaceAll(suffix, pc.bold(suffix));
@@ -133,13 +135,14 @@ function pluginFileEnv() {
133
135
  .filter((importer) =>
134
136
  // Can be Vike's virtual module: https://github.com/vikejs/vike/issues/2483
135
137
  isFilePathAbsolute(importer))
136
- .map((importer) => getModuleFilePathAbsolute(importer, config));
138
+ .map((importer) => getFilePathToShowToUserModule(importer, config))
139
+ .map((importPath) => pc.cyan(importPath));
137
140
  if (importPaths.length > 0) {
138
141
  errMsg += ` by ${joinEnglish(importPaths, 'and')}`;
139
142
  }
140
143
  }
141
144
  if (onlyWarn) {
142
- errMsg += ' and, therefore, Vike will prevent building your app for production.';
145
+ errMsg += ". This is potentially a security issue and Vike won't allow you to build your app for production.";
143
146
  }
144
147
  return errMsg;
145
148
  }
@@ -0,0 +1,3 @@
1
+ export { pluginReplaceConstantsEnvVars };
2
+ import type { Plugin } from 'vite';
3
+ declare function pluginReplaceConstantsEnvVars(): Plugin[];
@@ -0,0 +1,129 @@
1
+ export { pluginReplaceConstantsEnvVars };
2
+ import { loadEnv } from 'vite';
3
+ import { assert, assertPosixPath, assertUsage, assertWarning, escapeRegex, isArray, isNotNullish, lowerFirst, } from '../utils.js';
4
+ import { getFilePathToShowToUserModule } from '../shared/getFilePath.js';
5
+ import { normalizeId } from '../shared/normalizeId.js';
6
+ import { isViteServerSide_extraSafe } from '../shared/isViteServerSide.js';
7
+ import { getMagicString } from '../shared/getMagicString.js';
8
+ const PUBLIC_ENV_PREFIX = 'PUBLIC_ENV__';
9
+ const PUBLIC_ENV_ALLOWLIST = [
10
+ // https://github.com/vikejs/vike/issues/1724
11
+ 'STORYBOOK',
12
+ ];
13
+ // TO-DO/eventually:
14
+ // - Make import.meta.env work inside +config.js
15
+ // - For it to work, we'll probably need the user to define the settings (e.g. `envDir`) for loadEnv() inside vike.config.js instead of vite.config.js
16
+ // - Or stop using Vite's `mode` implementation and have Vike implement its own `mode` feature? (So that the only dependencies are `$ vike build --mode staging` and `$ MODE=staging vike build`.)
17
+ const skipNodeModules = '/node_modules/';
18
+ const skipIrrelevant = 'import.meta.env.';
19
+ const filterRolldown = {
20
+ id: {
21
+ exclude: `**${skipNodeModules}**`,
22
+ },
23
+ code: {
24
+ include: skipIrrelevant,
25
+ },
26
+ };
27
+ const filterFunction = (id, code) => {
28
+ if (id.includes(skipNodeModules))
29
+ return false;
30
+ if (!code.includes(skipIrrelevant))
31
+ return false;
32
+ return true;
33
+ };
34
+ function pluginReplaceConstantsEnvVars() {
35
+ let envVarsAll;
36
+ let envPrefix;
37
+ let config;
38
+ return [
39
+ {
40
+ name: 'vike:pluginReplaceConstantsEnvVars',
41
+ enforce: 'post',
42
+ configResolved: {
43
+ handler(config_) {
44
+ config = config_;
45
+ envVarsAll = loadEnv(config.mode, config.envDir || config.root, '');
46
+ envPrefix = getEnvPrefix(config);
47
+ config.plugins.sort(lowerFirst((plugin) => (plugin.name === 'vite:define' ? 1 : 0)));
48
+ },
49
+ },
50
+ transform: {
51
+ filter: filterRolldown,
52
+ handler(code, id, options) {
53
+ id = normalizeId(id);
54
+ assertPosixPath(id);
55
+ assertPosixPath(config.root);
56
+ if (!id.startsWith(config.root))
57
+ return; // skip linked dependencies
58
+ assert(filterFunction(id, code));
59
+ const isBuild = config.command === 'build';
60
+ const isClientSide = !isViteServerSide_extraSafe(config, this.environment, options);
61
+ const { magicString, getMagicStringResult } = getMagicString(code, id);
62
+ // Get regex operations
63
+ const replacements = Object.entries(envVarsAll)
64
+ // Skip env vars that start with [`config.envPrefix`](https://vite.dev/config/shared-options.html#envprefix) — they are already handled by Vite
65
+ .filter(([envName]) => !envPrefix.some((prefix) => envName.startsWith(prefix)))
66
+ // Skip constants like import.meta.env.DEV which are already handled by Vite
67
+ .filter(([envName]) => !['DEV', 'PROD', 'SSR', 'MODE', 'BASE_URL'].includes(envName))
68
+ .map(([envName, envVal]) => {
69
+ const envStatement = `import.meta.env.${envName}`;
70
+ const envStatementRegExpStr = escapeRegex(envStatement) + '\\b';
71
+ // Show error (warning in dev) if client code contains a private environment variable (one that doesn't start with PUBLIC_ENV__ and that isn't included in `PUBLIC_ENV_ALLOWLIST`).
72
+ if (isClientSide) {
73
+ const skip = assertNoClientSideLeak({
74
+ envName,
75
+ envStatement,
76
+ envStatementRegExpStr,
77
+ code,
78
+ id,
79
+ config,
80
+ isBuild,
81
+ });
82
+ if (skip)
83
+ return null;
84
+ }
85
+ return { regExpStr: envStatementRegExpStr, replacement: envVal };
86
+ })
87
+ .filter(isNotNullish);
88
+ // Apply regex operations
89
+ replacements.forEach(({ regExpStr, replacement }) => {
90
+ magicString.replaceAll(new RegExp(regExpStr, 'g'), JSON.stringify(replacement));
91
+ });
92
+ return getMagicStringResult();
93
+ },
94
+ },
95
+ },
96
+ ];
97
+ }
98
+ function getEnvPrefix(config) {
99
+ const { envPrefix } = config;
100
+ if (!envPrefix)
101
+ return [];
102
+ if (!isArray(envPrefix))
103
+ return [envPrefix];
104
+ return envPrefix;
105
+ }
106
+ function assertNoClientSideLeak({ envName, envStatement, envStatementRegExpStr, code, id, config, isBuild, }) {
107
+ const isPrivate = !envName.startsWith(PUBLIC_ENV_PREFIX) && !PUBLIC_ENV_ALLOWLIST.includes(envName);
108
+ // ✅ All good
109
+ if (!isPrivate)
110
+ return;
111
+ if (!new RegExp(envStatementRegExpStr).test(code))
112
+ return true;
113
+ // ❌ Security leak!
114
+ // - Warning in dev
115
+ // - assertUsage() and abort when building for production
116
+ const modulePath = getFilePathToShowToUserModule(id, config);
117
+ const errMsgAddendum = isBuild ? '' : ' (Vike will prevent your app from building for production)';
118
+ const envNameFixed = `${PUBLIC_ENV_PREFIX}${envName}`;
119
+ const errMsg = `${envStatement} is used in client-side file ${modulePath} which means that the environment variable ${envName} will be included in client-side bundles and, therefore, ${envName} will be publicly exposed which can be a security leak${errMsgAddendum}. Use ${envStatement} only in server-side files, or rename ${envName} to ${envNameFixed}, see https://vike.dev/env`;
120
+ if (isBuild) {
121
+ assertUsage(false, errMsg);
122
+ }
123
+ else {
124
+ // - Only a warning for faster development DX (e.g. when user toggles `ssr: boolean` or `onBeforeRenderIsomorph: boolean`).
125
+ // - Although only showing a warning can be confusing: https://github.com/vikejs/vike/issues/1641
126
+ assertWarning(false, errMsg, { onlyOnce: true });
127
+ }
128
+ assert(!isBuild); // we should abort if building for production
129
+ }
@@ -0,0 +1,10 @@
1
+ export { pluginReplaceConstantsGlobalThis };
2
+ import type { Plugin } from 'vite';
3
+ declare global {
4
+ /** Like `import.meta.env.DEV` but works for `node_modules/` packages with `ssr.external` */
5
+ var __VIKE__IS_DEV: boolean;
6
+ /** Like `import.meta.env.SSR` but works for `node_modules/` packages with `ssr.external` */
7
+ var __VIKE__IS_CLIENT: boolean;
8
+ var __VIKE__IS_DEBUG: boolean;
9
+ }
10
+ declare function pluginReplaceConstantsGlobalThis(): Plugin[];
@@ -0,0 +1,77 @@
1
+ export { pluginReplaceConstantsGlobalThis };
2
+ import { assert, isDebug, addVirtualFileIdPrefix, escapeRegex } from '../utils.js';
3
+ import { isViteServerSide_applyToEnvironment, isViteServerSide_configEnvironment, isViteServerSide_extraSafe, } from '../shared/isViteServerSide.js';
4
+ const isDebugVal = isDebug();
5
+ globalThis.__VIKE__IS_CLIENT = false;
6
+ globalThis.__VIKE__IS_DEBUG = isDebugVal;
7
+ const VIRTUAL_FILE_ID = 'virtual:vike:server:globalThis-constants';
8
+ const filterRolldown = {
9
+ id: {
10
+ include: new RegExp(escapeRegex(VIRTUAL_FILE_ID)),
11
+ },
12
+ };
13
+ const filterFunction = (id) => id === VIRTUAL_FILE_ID || id === addVirtualFileIdPrefix(VIRTUAL_FILE_ID);
14
+ function pluginReplaceConstantsGlobalThis() {
15
+ let config;
16
+ let isDev;
17
+ return [
18
+ {
19
+ name: 'vike:pluginReplaceConstantsGlobalThis:define',
20
+ config: {
21
+ handler(config) {
22
+ assert(typeof config._isDev === 'boolean');
23
+ isDev = config._isDev;
24
+ globalThis.__VIKE__IS_DEV = isDev;
25
+ return {
26
+ define: {
27
+ 'globalThis.__VIKE__IS_DEV': JSON.stringify(isDev),
28
+ 'globalThis.__VIKE__IS_DEBUG': JSON.stringify(isDebugVal),
29
+ },
30
+ };
31
+ },
32
+ },
33
+ configEnvironment: {
34
+ handler(name, config) {
35
+ const isClientSide = !isViteServerSide_configEnvironment(name, config);
36
+ return {
37
+ define: {
38
+ 'globalThis.__VIKE__IS_CLIENT': JSON.stringify(isClientSide),
39
+ },
40
+ };
41
+ },
42
+ },
43
+ configResolved(config_) {
44
+ config = config_;
45
+ },
46
+ },
47
+ {
48
+ name: 'vike:pluginReplaceConstantsGlobalThis:virtual-file',
49
+ // We only need the virtual file for the server-side (for node_modules/ packages with ssr.external) — the `define` values above always apply to the client-side.
50
+ applyToEnvironment(env) {
51
+ return isViteServerSide_applyToEnvironment(env);
52
+ },
53
+ resolveId: {
54
+ filter: filterRolldown,
55
+ handler(id) {
56
+ assert(filterFunction(id));
57
+ assert(id === VIRTUAL_FILE_ID);
58
+ return addVirtualFileIdPrefix(id);
59
+ },
60
+ },
61
+ load: {
62
+ filter: filterRolldown,
63
+ handler(id, options) {
64
+ assert(filterFunction(id));
65
+ assert(isViteServerSide_extraSafe(config, this.environment, options));
66
+ assert(typeof isDev === 'boolean');
67
+ const code = [
68
+ `globalThis.__VIKE__IS_DEV = ${JSON.stringify(isDev)};`,
69
+ `globalThis.__VIKE__IS_CLIENT = false;`,
70
+ `globalThis.__VIKE__IS_DEBUG = ${JSON.stringify(isDebugVal)};`,
71
+ ].join('\n');
72
+ return code;
73
+ },
74
+ },
75
+ },
76
+ ];
77
+ }
@@ -0,0 +1,3 @@
1
+ export { pluginReplaceConstantsPageContext };
2
+ import type { Plugin } from 'vite';
3
+ declare function pluginReplaceConstantsPageContext(): Plugin[];
@@ -1,4 +1,4 @@
1
- export { pluginReplaceIsClientSide };
1
+ export { pluginReplaceConstantsPageContext };
2
2
  import { assert, assertPosixPath } from '../utils.js';
3
3
  import { normalizeId } from '../shared/normalizeId.js';
4
4
  import { isViteServerSide_extraSafe } from '../shared/isViteServerSide.js';
@@ -9,6 +9,8 @@ const constantsIsClientSide = [
9
9
  'globalContext.isClientSide',
10
10
  'pageContext.globalContext.isClientSide',
11
11
  ];
12
+ // - See https://vike.dev/pageContext#narrowing-down
13
+ // - We cannot use [`define`](https://vite.dev/config/shared-options.html#define) because of https://github.com/rolldown/rolldown/issues/4300
12
14
  const skipNodeModules = '/node_modules/';
13
15
  const skipIrrelevant = 'Context.isClientSide';
14
16
  assert(constantsIsClientSide.every((constant) => constant.endsWith(skipIrrelevant)));
@@ -27,11 +29,11 @@ const filterFunction = (id, code) => {
27
29
  return false;
28
30
  return true;
29
31
  };
30
- function pluginReplaceIsClientSide() {
32
+ function pluginReplaceConstantsPageContext() {
31
33
  let config;
32
34
  return [
33
35
  {
34
- name: 'vike:pluginReplaceIsClientSide',
36
+ name: 'vike:pluginReplaceConstantsPageContext',
35
37
  enforce: 'post',
36
38
  apply: 'build',
37
39
  configResolved: {
@@ -12,6 +12,9 @@ function getCode(pageConfigs, pageConfigGlobal, isForClientSide, isDev, id, isCl
12
12
  const lines = [];
13
13
  const importStatements = [];
14
14
  const filesEnv = new Map();
15
+ if (!isForClientSide) {
16
+ importStatements.push("import 'virtual:vike:server:globalThis-constants';");
17
+ }
15
18
  lines.push('export const pageConfigsSerialized = [');
16
19
  lines.push(getCodePageConfigsSerialized(pageConfigs, isForClientSide, isClientRouting, isDev, importStatements, filesEnv));
17
20
  lines.push('];');
@@ -22,7 +25,10 @@ function getCode(pageConfigs, pageConfigGlobal, isForClientSide, isDev, id, isCl
22
25
  // https://vite.dev/guide/api-environment-frameworks.html
23
26
  lines.push('if (import.meta.hot) import.meta.hot.accept();');
24
27
  }
25
- const code = [...importStatements, ...lines].join('\n');
28
+ let code = [...importStatements, ...lines].join('\n');
29
+ if (!isForClientSide) {
30
+ code = "import 'virtual:vike:server:globalThis-constants';\n" + code;
31
+ }
26
32
  debug(id, isForClientSide ? 'CLIENT-SIDE' : 'SERVER-SIDE', code);
27
33
  return code;
28
34
  }
@@ -23,6 +23,9 @@ async function getCode(config, isForClientSide, isClientRouting, isDev, id) {
23
23
  const isBuild = command === 'build';
24
24
  assert(isDev === !isBuild);
25
25
  let content = '';
26
+ if (!isForClientSide) {
27
+ content += "import 'virtual:vike:server:globalThis-constants';\n";
28
+ }
26
29
  {
27
30
  const globRoots = getGlobRoots(config);
28
31
  debugGlob('Glob roots: ', globRoots);