vike 0.4.240-commit-42b44bb → 0.4.241-commit-206146b

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 (30) hide show
  1. package/dist/esm/client/runtime-client-routing/getPageContextFromHooks.d.ts +1 -1
  2. package/dist/esm/client/runtime-client-routing/logErrorClient.d.ts +2 -0
  3. package/dist/esm/client/runtime-client-routing/logErrorClient.js +11 -0
  4. package/dist/esm/client/runtime-client-routing/renderPageClientSide.js +2 -10
  5. package/dist/esm/node/prerender/runPrerender.js +1 -1
  6. package/dist/esm/node/runtime/globalContext.d.ts +92 -0
  7. package/dist/esm/node/runtime/globalContext.js +7 -0
  8. package/dist/esm/node/runtime/logErrorServer.js +6 -4
  9. package/dist/esm/node/runtime/renderPage/execHookOnError.d.ts +2 -0
  10. package/dist/esm/node/runtime/renderPage/execHookOnError.js +26 -0
  11. package/dist/esm/node/runtime/renderPage/execHookServer.d.ts +1 -1
  12. package/dist/esm/node/runtime/renderPage.js +2 -2
  13. package/dist/esm/node/vite/onLoad.js +3 -8
  14. package/dist/esm/node/vite/shared/loggerNotProd/log.js +6 -2
  15. package/dist/esm/node/vite/shared/loggerNotProd.d.ts +1 -1
  16. package/dist/esm/node/vite/shared/loggerNotProd.js +11 -11
  17. package/dist/esm/node/vite/shared/loggerVite.js +4 -2
  18. package/dist/esm/node/vite/shared/resolveVikeConfigInternal/configDefinitionsBuiltIn.js +6 -0
  19. package/dist/esm/node/vite/shared/resolveVikeConfigInternal/transpileAndExecuteFile.js +1 -6
  20. package/dist/esm/shared/createGlobalContextShared.d.ts +2 -1
  21. package/dist/esm/shared/createGlobalContextShared.js +1 -1
  22. package/dist/esm/shared/hooks/execHook.d.ts +1 -1
  23. package/dist/esm/shared/hooks/getHook.d.ts +5 -4
  24. package/dist/esm/types/Config.d.ts +7 -2
  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/assertNodeVersion.js +1 -1
  28. package/dist/esm/utils/assertViteVersion.d.ts +2 -0
  29. package/dist/esm/utils/assertViteVersion.js +11 -0
  30. package/package.json +1 -1
@@ -445,7 +445,7 @@ declare function getPageContextFromClientHooks(pageContext: {
445
445
  }>;
446
446
  type PageContextExecHookClient = PageContextConfig & PageContextForPublicUsageClient;
447
447
  declare function execHookClient(hookName: HookName, pageContext: PageContextExecHookClient): Promise<(import("../../shared/hooks/getHook.js").HookLoc & {
448
- hookFn: (arg: import("../../shared/preparePageContextForPublicUsage.js").PageContextPrepareMinimum | import("../../shared/prepareGlobalContextForPublicUsage.js").GlobalContextPrepareMinimum) => unknown;
448
+ hookFn: (arg: import("../../shared/preparePageContextForPublicUsage.js").PageContextPrepareMinimum) => unknown;
449
449
  hookTimeout: import("../../shared/hooks/getHook.js").HookTimeout;
450
450
  } & {
451
451
  hookReturn: unknown;
@@ -0,0 +1,2 @@
1
+ export { logErrorClient };
2
+ declare function logErrorClient(err: unknown): void;
@@ -0,0 +1,11 @@
1
+ export { logErrorClient };
2
+ import { isObject } from './utils.js';
3
+ function logErrorClient(err) {
4
+ if (isObject(err) &&
5
+ // Set by vike-react
6
+ // https://github.com/vikejs/vike-react/blob/195a208c6b77e7f34496e1f637278a36c60fbe07/packages/vike-react/src/integration/onRenderClient.tsx#L109
7
+ err.isAlreadyLogged) {
8
+ return;
9
+ }
10
+ console.error(err);
11
+ }
@@ -3,7 +3,7 @@ export { getRenderCount };
3
3
  export { disableClientRouting };
4
4
  export { firstRenderStartPromise };
5
5
  export { getPageContextClient };
6
- import { assert, objectAssign, redirectHard, getGlobalObject, hasProp, updateType, genPromise, isCallable, catchInfiniteLoop, isObject, } from './utils.js';
6
+ import { assert, objectAssign, redirectHard, getGlobalObject, hasProp, updateType, genPromise, isCallable, catchInfiniteLoop, } from './utils.js';
7
7
  import { getPageContextFromClientHooks, getPageContextFromServerHooks, getPageContextFromHooks_isHydration, getPageContextFromHooks_serialized, setPageContextInitIsPassedToClient, } from './getPageContextFromHooks.js';
8
8
  import { createPageContextClientSide } from './createPageContextClientSide.js';
9
9
  import { addLinkPrefetchHandlers, addLinkPrefetchHandlers_unwatch, addLinkPrefetchHandlers_watch, getPageContextPrefetched, populatePageContextPrefetchCache, } from './prefetch.js';
@@ -24,6 +24,7 @@ import { execHookDirect, execHook } from '../../shared/hooks/execHook.js';
24
24
  import { preparePageContextForPublicUsageClient, } from './preparePageContextForPublicUsageClient.js';
25
25
  import { getHookFromPageContextNew } from '../../shared/hooks/getHook.js';
26
26
  import { preparePageContextForPublicUsageClientMinimal } from '../shared/preparePageContextForPublicUsageClientShared.js';
27
+ import { logErrorClient } from './logErrorClient.js';
27
28
  const globalObject = getGlobalObject('runtime-client-routing/renderPageClientSide.ts', (() => {
28
29
  const { promise: firstRenderStartPromise, resolve: firstRenderStartPromiseResolve } = genPromise();
29
30
  return {
@@ -665,12 +666,3 @@ if (import.meta.env.DEV && import.meta.hot)
665
666
  });
666
667
  }
667
668
  });
668
- function logErrorClient(err) {
669
- if (isObject(err) &&
670
- // Set by vike-react
671
- // https://github.com/vikejs/vike-react/blob/195a208c6b77e7f34496e1f637278a36c60fbe07/packages/vike-react/src/integration/onRenderClient.tsx#L109
672
- err.isAlreadyLogged) {
673
- return;
674
- }
675
- console.error(err);
676
- }
@@ -539,7 +539,7 @@ async function warnMissingPages(prerenderedPageContexts, globalContext, doNotPre
539
539
  .filter((pageId) => !isErrorPage(pageId, globalContext._pageConfigs))
540
540
  .forEach((pageId) => {
541
541
  const pageAt = isV1 ? pageId : `\`${pageId}.page.*\``;
542
- assertWarning(partial, `Cannot pre-render page ${pageAt} because it has a non-static route, while there isn't any ${hookName}() hook returning an URL matching the page's route. You must use a ${hookName}() hook (https://vike.dev/${hookName}) for providing the list of URLs to be pre-rendered for that page. If you want to skip pre-rendering that page, you can remove this warning by setting +prerender to false at ${pageAt} (https://vike.dev/prerender#toggle) or by setting +prerender.partial to true (https://vike.dev/prerender#partial).`, { onlyOnce: true });
542
+ assertWarning(partial, `Cannot pre-render page ${pageAt} because it has a non-static route, while there isn't any ${hookName}() hook returning an URL matching the page's route. You must use a ${hookName}() hook (https://vike.dev/${hookName}) for providing the list of URLs to be pre-rendered for that page. If you want to skip pre-rendering that page, you can remove this warning by setting +prerender to false at ${pageAt} (https://vike.dev/pre-rendering#partial) or by setting +prerender.partial to true (https://vike.dev/prerender#partial).`, { onlyOnce: true });
543
543
  });
544
544
  }
545
545
  async function writeFiles({ pageContext, htmlString, pageContextSerialized }, viteConfig, onPagePrerender, prerenderContext, logLevel) {
@@ -2,6 +2,7 @@ export { getGlobalContext };
2
2
  export { getGlobalContextSync };
3
3
  export { getGlobalContextAsync };
4
4
  export { getGlobalContextServerInternal };
5
+ export { getGlobalContextServerInternalOptional };
5
6
  export { getViteDevServer };
6
7
  export { getViteConfig };
7
8
  export { initGlobalContext_renderPage };
@@ -246,6 +247,97 @@ declare function getGlobalContextServerInternal(): Promise<{
246
247
  prerenderContext: PrerenderContext | undefined;
247
248
  });
248
249
  }>;
250
+ declare function getGlobalContextServerInternalOptional(): (Record<string, unknown> & (({
251
+ _globalConfigPublic: {
252
+ pages: {
253
+ [k: string]: {
254
+ config: import("../../types/index.js").ConfigResolved;
255
+ _source: import("../../shared/page-configs/resolveVikeConfigPublic.js").Source;
256
+ _sources: import("../../shared/page-configs/resolveVikeConfigPublic.js").Sources;
257
+ _from: import("../../shared/page-configs/resolveVikeConfigPublic.js").From;
258
+ } & ({
259
+ route: import("../../types/Config.js").Route;
260
+ isErrorPage?: undefined;
261
+ } | {
262
+ route?: undefined;
263
+ isErrorPage: true;
264
+ });
265
+ };
266
+ config: import("../../types/index.js").ConfigResolved;
267
+ _source: import("../../shared/page-configs/resolveVikeConfigPublic.js").Source;
268
+ _sources: import("../../shared/page-configs/resolveVikeConfigPublic.js").Sources;
269
+ _from: import("../../shared/page-configs/resolveVikeConfigPublic.js").From;
270
+ };
271
+ pages: {
272
+ [k: string]: {
273
+ config: import("../../types/index.js").ConfigResolved;
274
+ _source: import("../../shared/page-configs/resolveVikeConfigPublic.js").Source;
275
+ _sources: import("../../shared/page-configs/resolveVikeConfigPublic.js").Sources;
276
+ _from: import("../../shared/page-configs/resolveVikeConfigPublic.js").From;
277
+ } & ({
278
+ route: import("../../types/Config.js").Route;
279
+ isErrorPage?: undefined;
280
+ } | {
281
+ route?: undefined;
282
+ isErrorPage: true;
283
+ });
284
+ };
285
+ config: import("../../types/index.js").ConfigResolved;
286
+ _source: import("../../shared/page-configs/resolveVikeConfigPublic.js").Source;
287
+ _sources: import("../../shared/page-configs/resolveVikeConfigPublic.js").Sources;
288
+ _from: import("../../shared/page-configs/resolveVikeConfigPublic.js").From;
289
+ isGlobalContext: true;
290
+ _isOriginalObject: true;
291
+ _virtualFileExportsGlobalEntry: unknown;
292
+ _pageFilesAll: import("../../shared/getPageFiles.js").PageFile[];
293
+ _pageConfigs: import("../../types/PageConfig.js").PageConfigRuntime[];
294
+ _pageConfigGlobal: import("../../types/PageConfig.js").PageConfigGlobalRuntime;
295
+ _allPageIds: string[];
296
+ } & (({
297
+ _isProduction: false;
298
+ _isPrerendering: false;
299
+ assetsManifest: null;
300
+ _viteDevServer: ViteDevServer | undefined;
301
+ viteConfig: ResolvedConfig | undefined;
302
+ isClientSide: false;
303
+ _pageRoutes: PageRoutes;
304
+ _onBeforeRouteHook: Hook | null;
305
+ } | {
306
+ _isPrerendering: true;
307
+ viteConfig: ResolvedConfig;
308
+ _isProduction: true;
309
+ assetsManifest: ViteManifest;
310
+ _viteDevServer: null;
311
+ _usesClientRouter: boolean;
312
+ isClientSide: false;
313
+ _pageRoutes: PageRoutes;
314
+ _onBeforeRouteHook: Hook | null;
315
+ } | {
316
+ _isPrerendering: false;
317
+ viteConfig: null;
318
+ _isProduction: true;
319
+ assetsManifest: ViteManifest;
320
+ _viteDevServer: null;
321
+ _usesClientRouter: boolean;
322
+ isClientSide: false;
323
+ _pageRoutes: PageRoutes;
324
+ _onBeforeRouteHook: Hook | null;
325
+ }) & {
326
+ baseServer: string;
327
+ baseAssets: string;
328
+ viteConfigRuntime: {
329
+ root: string;
330
+ build: {
331
+ outDir: string;
332
+ };
333
+ _baseViteOriginal: string;
334
+ vitePluginServerEntry: {
335
+ inject: boolean | undefined;
336
+ };
337
+ };
338
+ })) & {
339
+ prerenderContext: PrerenderContext | undefined;
340
+ })) | null;
249
341
  /**
250
342
  * Get runtime information about your app.
251
343
  *
@@ -4,6 +4,7 @@ export { getGlobalContextSync };
4
4
  export { getGlobalContextAsync };
5
5
  // Internal use
6
6
  export { getGlobalContextServerInternal };
7
+ export { getGlobalContextServerInternalOptional };
7
8
  export { getViteDevServer };
8
9
  export { getViteConfig };
9
10
  export { initGlobalContext_renderPage };
@@ -58,6 +59,12 @@ async function getGlobalContextServerInternal() {
58
59
  assertIsDefined(globalContext);
59
60
  return { globalContext };
60
61
  }
62
+ function getGlobalContextServerInternalOptional() {
63
+ const { globalContext } = globalObjectTyped;
64
+ if (!globalContext)
65
+ return null;
66
+ return globalContext;
67
+ }
61
68
  function assertIsDefined(globalContext) {
62
69
  if (!globalContext) {
63
70
  debug('globalContext', globalContext);
@@ -1,15 +1,17 @@
1
1
  export { logErrorServer };
2
2
  import pc from '@brillout/picocolors';
3
3
  import { isCallable, isObject } from './utils.js';
4
+ import { execHookOnError } from './renderPage/execHookOnError.js';
4
5
  function logErrorServer(err) {
6
+ execHookOnError(err);
7
+ // TODO https://gist.github.com/brillout/066293a687ab7cf695e62ad867bc6a9c
5
8
  if (isObject(err) &&
6
9
  // Set by react-streaming
7
- // https://github.com/brillout/react-streaming/blob/0f93e09059a5936a1fb581bc1ce0bce473e0d5e0/src/server/renderToStream/common.ts#L36
8
- isCallable(err.prettifyThisError)) {
9
- err = err.prettifyThisError(err);
10
+ isCallable(err.getEnhancedError)) {
11
+ err = err.getEnhancedError(err);
10
12
  }
11
13
  // We ensure we print a string; Cloudflare Workers doesn't seem to properly stringify `Error` objects.
12
- // - TO-DO/eventuually: is that still true? Let's eventually remove it and see if it crashes Cloudflare.
14
+ // - TO-DO/eventually: is that still true? Let's eventually remove it and see if it crashes Cloudflare.
13
15
  const errStr = isObject(err) && 'stack' in err ? String(err.stack) : String(err);
14
16
  console.error(pc.red(errStr));
15
17
  }
@@ -0,0 +1,2 @@
1
+ export { execHookOnError };
2
+ declare function execHookOnError(err: unknown): void;
@@ -0,0 +1,26 @@
1
+ export { execHookOnError };
2
+ import { isObject, getGlobalObject } from '../utils.js';
3
+ import { getGlobalContextServerInternalOptional } from '../globalContext.js';
4
+ import { getHookFromPageConfigGlobalCumulative } from '../../../shared/hooks/getHook.js';
5
+ const globalObject = getGlobalObject('renderPage/execHookOnError.ts', {
6
+ seen: new WeakSet(),
7
+ });
8
+ function execHookOnError(err) {
9
+ if (isObject(err)) {
10
+ if (globalObject.seen.has(err))
11
+ return;
12
+ globalObject.seen.add(err);
13
+ }
14
+ const globalContext = getGlobalContextServerInternalOptional();
15
+ if (!globalContext)
16
+ return;
17
+ const hooks = getHookFromPageConfigGlobalCumulative(globalContext._pageConfigGlobal, 'onError');
18
+ for (const hook of hooks) {
19
+ try {
20
+ hook.hookFn(err);
21
+ }
22
+ catch (hookErr) {
23
+ console.error(hookErr);
24
+ }
25
+ }
26
+ }
@@ -5,7 +5,7 @@ import type { PageContextConfig } from '../../../shared/getPageFiles.js';
5
5
  import type { HookName } from '../../../types/Config.js';
6
6
  type PageContextExecHookServer = PageContextConfig & PageContextForPublicUsageServer;
7
7
  declare function execHookServer(hookName: HookName, pageContext: PageContextExecHookServer): Promise<(import("../../../shared/hooks/getHook.js").HookLoc & {
8
- hookFn: (arg: import("../../../shared/preparePageContextForPublicUsage.js").PageContextPrepareMinimum | import("../../../shared/prepareGlobalContextForPublicUsage.js").GlobalContextPrepareMinimum) => unknown;
8
+ hookFn: (arg: import("../../../shared/preparePageContextForPublicUsage.js").PageContextPrepareMinimum) => unknown;
9
9
  hookTimeout: import("../../../shared/hooks/getHook.js").HookTimeout;
10
10
  } & {
11
11
  hookReturn: unknown;
@@ -246,7 +246,7 @@ function logHttpResponse(urlOriginalPretty, httpRequestId, pageContextReturn) {
246
246
  msg = `HTTP ${type} ${prettyUrl(urlOriginalPretty)} ${color(statusCode ?? 'ERR')}`;
247
247
  }
248
248
  }
249
- logRuntimeInfo?.(msg, httpRequestId, isNominal ? 'info' : 'error');
249
+ logRuntimeInfo?.(msg, httpRequestId, isNominal ? 'info' : 'error-note');
250
250
  }
251
251
  function prettyUrl(url) {
252
252
  try {
@@ -486,7 +486,7 @@ function getPageContextSkipRequest(pageContextInit) {
486
486
  return pageContext;
487
487
  }
488
488
  function getPageContextInvalidVikeConfig(err, pageContextInit, httpRequestId) {
489
- logRuntimeInfo?.(pc.bold(pc.red('Error loading Vike config — see error above')), httpRequestId, 'error');
489
+ logRuntimeInfo?.(pc.bold(pc.red('Error loading Vike config — see error above')), httpRequestId, 'error-note');
490
490
  const pageContextWithError = getPageContextHttpResponseErrorWithoutGlobalContext(err, pageContextInit);
491
491
  return pageContextWithError;
492
492
  }
@@ -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
  }
@@ -40,7 +40,11 @@ function logDirectly(thing, logType) {
40
40
  console.warn(thing);
41
41
  return;
42
42
  }
43
- if (logType === 'error') {
43
+ if (logType === 'error-note') {
44
+ console.error(thing);
45
+ return;
46
+ }
47
+ if (logType === 'error-thrown') {
44
48
  // console.error()
45
49
  logErrorServer(thing);
46
50
  return;
@@ -65,7 +69,7 @@ function applyViteSourceMapToStackTrace(thing) {
65
69
  }
66
70
  function prependTags(msg, projectTag, category, logType) {
67
71
  const color = (s) => {
68
- if (logType === 'error' && !hasRed(msg))
72
+ if (logType === 'error-thrown' && !hasRed(msg))
69
73
  return pc.bold(pc.red(s));
70
74
  if (logType === 'error-recover' && !hasGreen(msg))
71
75
  return pc.bold(pc.green(s));
@@ -10,7 +10,7 @@ export type { LogError };
10
10
  export type { LogErrorArgs };
11
11
  export type { LogType };
12
12
  export type { LogCategory };
13
- type LogType = 'info' | 'warn' | 'error' | 'error-recover';
13
+ type LogType = 'info' | 'warn' | 'error-thrown' | 'error-recover' | 'error-note';
14
14
  type LogCategory = 'config' | `request(${number})`;
15
15
  type LogInfo = (...args: LogInfoArgs) => void;
16
16
  type LogInfoArgs = Parameters<typeof logRuntimeInfo>;
@@ -89,7 +89,7 @@ function logErr(err, httpRequestId = null, errorComesFromVite) {
89
89
  assert(viteConfig);
90
90
  const prettyErr = getPrettyErrorWithCodeSnippet(err, viteConfig.root);
91
91
  assert(stripAnsi(prettyErr).startsWith('Failed to transpile'));
92
- logWithViteTag(prettyErr, 'error', category);
92
+ logWithViteTag(prettyErr, 'error-thrown', category);
93
93
  logErrorDebugNote();
94
94
  return;
95
95
  }
@@ -103,12 +103,12 @@ function logErr(err, httpRequestId = null, errorComesFromVite) {
103
103
  const hook = isUserHookError(err);
104
104
  if (hook) {
105
105
  const { hookName, hookFilePath } = hook;
106
- logWithVikeTag(pc.red(`Following error was thrown by the ${hookName}() hook defined at ${hookFilePath}`), 'error', category);
106
+ logWithVikeTag(pc.red(`Following error was thrown by the ${hookName}() hook defined at ${hookFilePath}`), 'error-note', category);
107
107
  }
108
108
  else if (category) {
109
109
  logFallbackErrIntro(category, errorComesFromVite);
110
110
  }
111
- logDirectly(err, 'error');
111
+ logDirectly(err, 'error-thrown');
112
112
  // Needs to be called after logging the error.
113
113
  onRuntimeError(err);
114
114
  }
@@ -119,8 +119,8 @@ function logConfigError(err) {
119
119
  const errIntroMsg = getConfigExecutionErrorIntroMsg(err);
120
120
  if (errIntroMsg) {
121
121
  assert(stripAnsi(errIntroMsg).startsWith('Failed to execute'));
122
- logWithVikeTag(errIntroMsg, 'error', category);
123
- logDirectly(err, 'error');
122
+ logWithVikeTag(errIntroMsg, 'error-note', category);
123
+ logDirectly(err, 'error-thrown');
124
124
  return;
125
125
  }
126
126
  }
@@ -129,10 +129,10 @@ function logConfigError(err) {
129
129
  if (errMsgFormatted) {
130
130
  assert(stripAnsi(errMsgFormatted).startsWith('Failed to transpile'));
131
131
  if (!isErrorDebug()) {
132
- logWithVikeTag(errMsgFormatted, 'error', category);
132
+ logWithVikeTag(errMsgFormatted, 'error-thrown', category);
133
133
  }
134
134
  else {
135
- logDirectly(err, 'error');
135
+ logDirectly(err, 'error-thrown');
136
136
  }
137
137
  return;
138
138
  }
@@ -144,11 +144,11 @@ function logConfigError(err) {
144
144
  }
145
145
  if (category)
146
146
  logFallbackErrIntro(category, false);
147
- logDirectly(err, 'error');
147
+ logDirectly(err, 'error-thrown');
148
148
  }
149
149
  function logFallbackErrIntro(category, errorComesFromVite) {
150
150
  const msg = errorComesFromVite ? 'Transpilation error' : 'An error was thrown';
151
- logWithVikeTag(pc.bold(pc.red(`[Error] ${msg}:`)), 'error', category);
151
+ logWithVikeTag(pc.bold(pc.red(`[Error] ${msg}:`)), 'error-note', category);
152
152
  }
153
153
  function getConfigCategory() {
154
154
  const category = getCategory() ?? 'config';
@@ -159,7 +159,7 @@ function handleAssertMsg(err, category) {
159
159
  if (!res)
160
160
  return false;
161
161
  const { assertMsg, showVikeVersion } = res;
162
- logWithVikeTag(assertMsg, 'error', category, showVikeVersion);
162
+ logWithVikeTag(assertMsg, 'error-thrown', category, showVikeVersion);
163
163
  return true;
164
164
  }
165
165
  function assertLogger(thing, logType) {
@@ -189,7 +189,7 @@ function logErrorDebugNote() {
189
189
  store.errorDebugNoteAlreadyShown = true;
190
190
  }
191
191
  const msg = pc.dim(formatHintLog("Error isn't helpful? See https://vike.dev/debug#verbose-errors"));
192
- logDirectly(msg, 'error');
192
+ logDirectly(msg, 'error-note');
193
193
  }
194
194
  function getCategory(httpRequestId = null) {
195
195
  const store = getHttpRequestAsyncStore();
@@ -9,8 +9,8 @@ function improveViteLogs(config) {
9
9
  intercept('warn', config);
10
10
  intercept('error', config);
11
11
  }
12
- function intercept(logType, config) {
13
- config.logger[logType] = (msg, options = {}) => {
12
+ function intercept(loggerType, config) {
13
+ config.logger[loggerType] = (msg, options = {}) => {
14
14
  assert(!isErrorDebug());
15
15
  if (removeSuperfluousViteLog(msg))
16
16
  return;
@@ -38,6 +38,8 @@ function intercept(logType, config) {
38
38
  }
39
39
  // Vite's default logger preprends the "[vite]" tag if and only if options.timestamp is true
40
40
  const prependViteTag = options.timestamp || !!store?.httpRequestId;
41
+ // If it's an actual error => options.error is set => it's handled with logViteError() above
42
+ const logType = loggerType === 'error' ? 'error-note' : loggerType;
41
43
  logViteAny(msg, logType, store?.httpRequestId ?? null, prependViteTag);
42
44
  };
43
45
  }
@@ -27,6 +27,11 @@ const configDefinitionsBuiltIn = {
27
27
  global: true,
28
28
  cumulative: true,
29
29
  },
30
+ onError: {
31
+ env: { server: true },
32
+ global: true,
33
+ cumulative: true,
34
+ },
30
35
  onBeforeRender: {
31
36
  env: { server: true },
32
37
  },
@@ -211,6 +216,7 @@ const configDefinitionsBuiltIn = {
211
216
  env: { config: true },
212
217
  global: true,
213
218
  },
219
+ // This is deprecated (since Summer 2025). But don't remove this (yet) — otherwise it will break older Vike extensions that still use it.
214
220
  vite6BuilderApp: {
215
221
  env: { config: true },
216
222
  global: true,
@@ -382,12 +382,7 @@ function triggerPrepareStackTrace(err) {
382
382
  }
383
383
  function getErrIntroMsg(operation, filePath) {
384
384
  const { filePathToShowToUserResolved } = filePath;
385
- const msg = [
386
- // prettier ignore
387
- pc.red(`Failed to ${operation}`),
388
- pc.bold(pc.red(filePathToShowToUserResolved)),
389
- pc.red(`because:`),
390
- ].join(' ');
385
+ const msg = `${pc.red(`Failed to ${operation}`)} ${pc.bold(pc.red(filePathToShowToUserResolved))} ${pc.red(`because:`)}`;
391
386
  return msg;
392
387
  }
393
388
  function cleanEsbuildErrors(errors) {
@@ -5,13 +5,14 @@ export type { GlobalContextBasePublic };
5
5
  export type GlobalContextInternal = GlobalContextServerInternal | GlobalContextClientInternal;
6
6
  import type { PageFile } from './getPageFiles.js';
7
7
  import type { PageConfigRuntime } from '../types/PageConfig.js';
8
+ import { type GlobalContextPrepareMinimum } from './prepareGlobalContextForPublicUsage.js';
8
9
  import type { GlobalContextServerInternal } from '../node/runtime/globalContext.js';
9
10
  import type { GlobalContextClientInternal } from '../client/runtime-client-routing/getGlobalContextClientInternal.js';
10
11
  import { type Hook } from './hooks/getHook.js';
11
12
  declare const getGlobalContextSyncErrMsg = "The global context isn't set yet, call getGlobalContextSync() later or use getGlobalContext() instead.";
12
13
  declare function createGlobalContextShared<GlobalContextAdded extends {}, GlobalContextAddedAsync extends {}>(virtualFileExportsGlobalEntry: unknown, globalObject: {
13
14
  globalContext?: {};
14
- onCreateGlobalContextHooks?: Hook[];
15
+ onCreateGlobalContextHooks?: Hook<GlobalContextPrepareMinimum>[];
15
16
  previousCreateGlobalContextPromise?: Promise<void>;
16
17
  }, addGlobalContext?: (globalContext: GlobalContextBase) => GlobalContextAdded, addGlobalContextTmp?: (globalContext: GlobalContextBase) => Promise<GlobalContextAdded>, addGlobalContextAsync?: (globalContext: GlobalContextBase) => Promise<GlobalContextAddedAsync>): Promise<{
17
18
  _globalConfigPublic: {
@@ -4,7 +4,7 @@ import { assert, changeEnumerable, genPromise, objectAssign, objectReplace, uniq
4
4
  import { parseVirtualFileExportsGlobalEntry } from './getPageFiles/parseVirtualFileExportsGlobalEntry.js';
5
5
  import { resolveGlobalContextConfig } from './page-configs/resolveVikeConfigPublic.js';
6
6
  import { execHookGlobal } from './hooks/execHook.js';
7
- import { prepareGlobalContextForPublicUsage } from './prepareGlobalContextForPublicUsage.js';
7
+ import { prepareGlobalContextForPublicUsage, } from './prepareGlobalContextForPublicUsage.js';
8
8
  import { getHookFromPageConfigGlobalCumulative } from './hooks/getHook.js';
9
9
  const getGlobalContextSyncErrMsg = "The global context isn't set yet, call getGlobalContextSync() later or use getGlobalContext() instead.";
10
10
  // TO-DO/eventually use flat globalContext — like flat pageContext
@@ -24,7 +24,7 @@ type HookWithResult = Hook & {
24
24
  hookReturn: unknown;
25
25
  };
26
26
  declare function execHook<PageContext extends PageContextExecHook>(hookName: HookName, pageContext: PageContext, preparePageContextForPublicUsage: (pageContext: PageContext) => PageContext): Promise<HookWithResult[]>;
27
- declare function execHookGlobal<HookArg extends PageContextPrepareMinimum | GlobalContextPrepareMinimum>(hookName: HookNameGlobal, pageConfigGlobal: PageConfigGlobalRuntime, pageContext: PageContextPrepareMinimum | null, hookArg: HookArg, prepareForPublicUsage: (hookArg: HookArg) => HookArg): Promise<void>;
27
+ declare function execHookGlobal<HookArg extends GlobalContextPrepareMinimum>(hookName: HookNameGlobal, pageConfigGlobal: PageConfigGlobalRuntime, pageContext: PageContextPrepareMinimum | null, hookArg: HookArg, prepareForPublicUsage: (hookArg: HookArg) => HookArg): Promise<void>;
28
28
  declare function execHookDirect<PageContext extends PageContextPrepareMinimum>(hooks: Hook[], pageContext: PageContext, preparePageContextForPublicUsage: (pageContext: PageContext) => PageContext): Promise<HookWithResult[]>;
29
29
  declare function execHookDirectSingle<PageContext extends PageContextExecHook>(hook: Hook, pageContext: PageContext, preparePageContextForPublicUsage: (pageContext: PageContext) => PageContext): Promise<void>;
30
30
  declare function execHookDirectSingleWithReturn<PageContext extends PageContextExecHook>(hook: Hook, pageContext: PageContext, preparePageContextForPublicUsage: (pageContext: PageContext) => PageContext): Promise<{
@@ -14,15 +14,16 @@ import type { HookNameOld, HookNamePage, HookNameGlobal, HookName } from '../../
14
14
  import type { PageConfigGlobalRuntime, PageConfigRuntime } from '../../types/PageConfig.js';
15
15
  import type { GlobalContextPrepareMinimum } from '../prepareGlobalContextForPublicUsage.js';
16
16
  import type { PageContextPrepareMinimum } from '../preparePageContextForPublicUsage.js';
17
- type Hook = HookLoc & {
18
- hookFn: HookFn;
17
+ type HookArgDefault = PageContextPrepareMinimum;
18
+ type Hook<HookArg = HookArgDefault> = HookLoc & {
19
+ hookFn: HookFn<HookArg>;
19
20
  hookTimeout: HookTimeout;
20
21
  };
21
22
  type HookLoc = {
22
23
  hookName: HookNameOld;
23
24
  hookFilePath: string;
24
25
  };
25
- type HookFn = (arg: PageContextPrepareMinimum | GlobalContextPrepareMinimum) => unknown;
26
+ type HookFn<HookArg = HookArgDefault> = (arg: HookArg) => unknown;
26
27
  type HookTimeout = {
27
28
  error: number | false;
28
29
  warning: number | false;
@@ -32,6 +33,6 @@ declare function getHookFromPageContext(pageContext: PageContextConfig, hookName
32
33
  declare function getHookFromPageContextNew(hookName: HookName, pageContext: PageContextConfig): Hook[];
33
34
  declare function getHookFromPageConfig(pageConfig: PageConfigRuntime, hookName: HookNamePage): null | Hook;
34
35
  declare function getHookFromPageConfigGlobal(pageConfigGlobal: PageConfigGlobalRuntime, hookName: HookNameGlobal): null | Hook;
35
- declare function getHookFromPageConfigGlobalCumulative(pageConfigGlobal: PageConfigGlobalRuntime, hookName: HookNameGlobal): Hook[];
36
+ declare function getHookFromPageConfigGlobalCumulative<HookArg = GlobalContextPrepareMinimum>(pageConfigGlobal: PageConfigGlobalRuntime, hookName: HookNameGlobal): Hook<HookArg>[];
36
37
  declare function getHookTimeoutDefault(hookName: HookNameOld): HookTimeout;
37
38
  declare function getHook_setIsPrerenderering(): void;
@@ -48,7 +48,7 @@ import type { PassToClientPublic } from '../node/runtime/renderPage/html/seriali
48
48
  type HookNameOld = HookName | HookNameOldDesign;
49
49
  type HookName = HookNamePage | HookNameGlobal;
50
50
  type HookNamePage = 'onHydrationEnd' | 'onBeforePrerenderStart' | 'onBeforeRender' | 'onPageTransitionStart' | 'onPageTransitionEnd' | 'onRenderHtml' | 'onRenderClient' | 'guard' | 'data' | 'onData' | 'route';
51
- type HookNameGlobal = 'onBeforeRoute' | 'onPrerenderStart' | 'onCreatePageContext' | 'onCreateGlobalContext';
51
+ type HookNameGlobal = 'onBeforeRoute' | 'onPrerenderStart' | 'onCreatePageContext' | 'onCreateGlobalContext' | 'onError';
52
52
  type HookNameOldDesign = 'render' | 'prerender' | 'onBeforePrerender';
53
53
  type ConfigNameBuiltIn = Exclude<keyof ConfigBuiltIn, keyof VikeVitePluginOptions | 'onBeforeRoute' | 'onPrerenderStart' | 'vite' | 'redirects'> | 'prerender' | 'hasServerOnlyHook' | 'isClientRuntimeLoaded' | 'onBeforeRenderEnv' | 'dataEnv' | 'hooksTimeout' | 'clientHooks' | 'middleware';
54
54
  type ConfigNameGlobal = 'onPrerenderStart' | 'onBeforeRoute' | 'prerender' | 'disableAutoFullBuild' | 'includeAssetsImportedByServer' | 'baseAssets' | 'baseServer' | 'redirects' | 'trailingSlash' | 'disableUrlNormalization' | 'vite';
@@ -268,7 +268,7 @@ type ConfigBuiltIn = {
268
268
  *
269
269
  * https://vike.dev/extends
270
270
  */
271
- extends?: Config | Config[] | ImportString | ImportString[];
271
+ extends?: Config | ImportString | (Config | ImportString)[];
272
272
  /** Hook called before the page is rendered.
273
273
  *
274
274
  * https://vike.dev/onBeforeRender
@@ -279,6 +279,11 @@ type ConfigBuiltIn = {
279
279
  * https://vike.dev/onCreatePageContext
280
280
  */
281
281
  onCreatePageContext?: ((pageContext: PageContextServer) => void) | ImportString | null;
282
+ /** Hook called when an error occurs during server-side rendering.
283
+ *
284
+ * https://vike.dev/onError
285
+ */
286
+ onError?: ((error: unknown) => void) | ImportString | null;
282
287
  /** Hook called when the `globalContext` object is created.
283
288
  *
284
289
  * https://vike.dev/onCreateGlobalContext
@@ -1 +1 @@
1
- export declare const PROJECT_VERSION: "0.4.240-commit-42b44bb";
1
+ export declare const PROJECT_VERSION: "0.4.241-commit-206146b";
@@ -1,2 +1,2 @@
1
1
  // Automatically updated by @brillout/release-me
2
- export const PROJECT_VERSION = '0.4.240-commit-42b44bb';
2
+ export const PROJECT_VERSION = '0.4.241-commit-206146b';
@@ -1,7 +1,7 @@
1
1
  export { assertNodeVersion };
2
2
  import { isNodeJS } from './isNodeJS.js';
3
3
  import { assertVersion } from './assertVersion.js';
4
- // node_modules/vike/package.json#engines.node isn't enough as users can ignore it
4
+ // node_modules/vike/package.json#engines.node isn't enough, as users often ignore it
5
5
  function assertNodeVersion() {
6
6
  if (!isNodeJS())
7
7
  return;
@@ -0,0 +1,2 @@
1
+ export { assertViteVersion };
2
+ declare function assertViteVersion(viteVersion: string): void;
@@ -0,0 +1,11 @@
1
+ export { assertViteVersion };
2
+ import { assertVersion } from './assertVersion.js';
3
+ // node_modules/vike/package.json#peerDependencies isn't enough, as users often ignore it
4
+ function assertViteVersion(viteVersion) {
5
+ // - 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
6
+ // - TO-DO/eventually: let's also use this.meta.viteVersion
7
+ // - this.meta.viteVersion was released in vite@7.0.0 => let's use it only after Vike requires a Vite version above 7.0.0
8
+ // - https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md#700-2025-06-24
9
+ // - https://github.com/vitejs/vite/pull/20088
10
+ assertVersion('Vite', viteVersion, ['6.3.0']);
11
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vike",
3
- "version": "0.4.240-commit-42b44bb",
3
+ "version": "0.4.241-commit-206146b",
4
4
  "repository": "https://github.com/vikejs/vike",
5
5
  "exports": {
6
6
  "./server": {