vike-lite 1.15.18 → 1.15.20

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.
@@ -5,26 +5,48 @@ declare function createLinkPrefetchHandler(onPrefetch: (url: URL) => void): (e:
5
5
  declare function finalizeNavigation(shouldScrollToTop: {
6
6
  current: boolean;
7
7
  }): void;
8
- interface ViewComponents {
9
- Page: any | null;
10
- Layout: any | null;
11
- Head: any | null;
8
+ interface ViewComponents<TComponent = unknown> {
9
+ Page: TComponent | null;
10
+ Layout: TComponent | null;
11
+ Head: TComponent | null;
12
+ }
13
+ /**
14
+ * Shape of a dynamically-imported `+Page`/`+Layout`/`+Head` module. The actual
15
+ * component type isn't statically known here (it's whatever the framework
16
+ * adapter's JSX/template runtime expects) — callers of `loadViewModules`
17
+ * specify it via the `TComponent` type param instead.
18
+ */
19
+ interface ViewModule {
20
+ default?: unknown;
21
+ Page?: unknown;
22
+ Layout?: unknown;
23
+ Head?: unknown;
12
24
  }
13
25
  interface RouteModuleLoaders {
14
- Page: () => Promise<any>;
15
- Layout?: () => Promise<any>;
16
- Head?: () => Promise<any>;
26
+ Page: () => Promise<ViewModule>;
27
+ Layout?: () => Promise<ViewModule>;
28
+ Head?: () => Promise<ViewModule>;
17
29
  }
18
30
  /**
19
31
  * Load a route's Page/Layout/Head modules in parallel and resolve each
20
32
  * module's export (named export first, falling back to the default export).
21
33
  */
22
- declare function loadViewModules(route: RouteModuleLoaders): Promise<ViewComponents>;
34
+ declare function loadViewModules<TComponent = unknown>(route: RouteModuleLoaders): Promise<ViewComponents<TComponent>>;
23
35
  /**
24
36
  * Build the URL of the `+data`/`+title` JSON endpoint for a given pathname
25
37
  * (e.g. base "/my-app" and path "/about" → "/my-app/about.pageContext.json").
26
38
  */
27
39
  declare function buildPageContextJsonUrl(pathname: string, search: string): string;
40
+ /** Shape of a `.pageContext.json` payload as produced by the server-side `+data`/`+title` hooks. */
41
+ interface PageContextJson {
42
+ data?: unknown;
43
+ title?: string;
44
+ is404?: boolean;
45
+ is500?: boolean;
46
+ isError?: boolean;
47
+ reason?: string;
48
+ _redirect?: string;
49
+ }
28
50
  /**
29
51
  * Fetch and parse a `.pageContext.json` endpoint, throwing a descriptive error
30
52
  * if a proxy/CDN intercepted the request with a non-JSON response.
@@ -32,14 +54,14 @@ declare function buildPageContextJsonUrl(pathname: string, search: string): stri
32
54
  declare function fetchPageContextJson(jsonUrl: string, options: {
33
55
  signal: AbortSignal;
34
56
  cache?: RequestCache;
35
- }): Promise<any>;
57
+ }): Promise<PageContextJson>;
36
58
  interface PrefetchableRoute {
37
59
  page?: string;
38
60
  layout?: string;
39
61
  head?: string;
40
- Page?: () => Promise<any>;
41
- Layout?: () => Promise<any>;
42
- Head?: () => Promise<any>;
62
+ Page?: () => Promise<unknown>;
63
+ Layout?: () => Promise<unknown>;
64
+ Head?: () => Promise<unknown>;
43
65
  }
44
66
  /**
45
67
  * Create a per-router-instance prefetcher that loads a route's modules at most once
@@ -57,7 +79,7 @@ declare function tryRecoverFromStaleModuleGraph(message: string, urlToReload: st
57
79
  * `isHydration`) onto the raw context blob the server injected via `window.__PAGE_CONTEXT__`.
58
80
  * Centralized so every adapter sets these consistently instead of some silently omitting them.
59
81
  */
60
- declare function buildInitialClientContext<T extends Record<string, any>>(rawContext: T | undefined, isHydration: boolean): T & {
82
+ declare function buildInitialClientContext<T extends object>(rawContext: T | undefined, isHydration: boolean): T & {
61
83
  isClientSide: true;
62
84
  isHydration: boolean;
63
85
  };
@@ -74,7 +96,7 @@ interface HydrationInitialContext {
74
96
  * initial pathname. Returns a null view when hydration isn't happening (client
75
97
  * takeover) — the router's own first-load effect performs the initial load instead.
76
98
  */
77
- declare function resolveHydrationView(initialContext: HydrationInitialContext, isHydration: boolean, routes: VikeState['routes'], errorRoute: VikeState['errorRoute']): Promise<ViewComponents>;
99
+ declare function resolveHydrationView<TComponent = unknown>(initialContext: HydrationInitialContext, isHydration: boolean, routes: VikeState['routes'], errorRoute: VikeState['errorRoute']): Promise<ViewComponents<TComponent>>;
78
100
  /**
79
101
  * Consume the server-injected initial context if it still matches the given pathname
80
102
  * (i.e. this is the very first client-side route load, right after SSR hydration/render).
@@ -85,4 +107,4 @@ declare function resolveHydrationView(initialContext: HydrationInitialContext, i
85
107
  */
86
108
  declare function consumeMatchingInitialContext(pathname: string): boolean;
87
109
  //#endregion
88
- export { ViewComponents, buildInitialClientContext, buildPageContextJsonUrl, consumeMatchingInitialContext, createLinkClickHandler, createLinkPrefetchHandler, createRoutePrefetcher, fetchPageContextJson, finalizeNavigation, loadViewModules, resolveHydrationView, tryRecoverFromStaleModuleGraph };
110
+ export { PageContextJson, ViewComponents, buildInitialClientContext, buildPageContextJsonUrl, consumeMatchingInitialContext, createLinkClickHandler, createLinkPrefetchHandler, createRoutePrefetcher, fetchPageContextJson, finalizeNavigation, loadViewModules, resolveHydrationView, tryRecoverFromStaleModuleGraph };
@@ -52,7 +52,7 @@ async function loadViewModules(route) {
52
52
  route.Head?.() ?? null
53
53
  ]);
54
54
  return {
55
- Page: PageMod.Page ?? PageMod.default,
55
+ Page: PageMod.Page ?? PageMod.default ?? null,
56
56
  Layout: LayoutMod?.Layout ?? LayoutMod?.default ?? null,
57
57
  Head: HeadMod?.Head ?? HeadMod?.default ?? null
58
58
  };
@@ -1,6 +1,7 @@
1
+ import { PageContextServer } from "../index.mjs";
1
2
  //#region src/__internal/shared.d.ts
2
3
  interface RenderContext {
3
- pageContext: any;
4
+ pageContext: PageContextServer;
4
5
  Page: unknown;
5
6
  Head?: unknown;
6
7
  Layout?: unknown;
package/dist/server.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  //#region src/server/renderPage.d.ts
2
2
  declare function renderPage(req: Request, { nonce }?: {
3
3
  nonce?: string;
4
- [key: string]: any;
4
+ [key: string]: unknown;
5
5
  }): Promise<Response>;
6
6
  //#endregion
7
7
  export { renderPage };
package/dist/server.mjs CHANGED
@@ -79,7 +79,8 @@ async function buildPageContext(urlPathname, urlOriginal, isJsonRequest) {
79
79
  const pageContext = {
80
80
  routeParams,
81
81
  urlOriginal,
82
- urlPathname
82
+ urlPathname,
83
+ isClientSide: false
83
84
  };
84
85
  const [dataMod, titleMod, PageModule, HeadModule, LayoutModule] = await Promise.all([
85
86
  route.Data?.() ?? null,
@@ -133,7 +134,8 @@ async function renderErrorPage(req, status, urlPathname, error, nonce) {
133
134
  routeParams: {},
134
135
  is404: status === 404,
135
136
  is500,
136
- errorMessage
137
+ errorMessage,
138
+ isClientSide: false
137
139
  };
138
140
  const html = await store.config.onRenderHtml({
139
141
  pageContext,
package/dist/vite.mjs CHANGED
@@ -141,6 +141,8 @@ function vikeLite({ pagesDir = "pages", apiPrefix = "/api", prerender = false, s
141
141
  viteConfigRoot = config.root ? path.resolve(config.root) : process.cwd();
142
142
  const { routes } = generateRoutes(viteConfigRoot, pagesDir);
143
143
  hasAnyPrerender = prerender || routes.some((r) => r.prerender);
144
+ const serverInput = { index: VIRTUAL.entryServer };
145
+ if (hasAnyPrerender) serverInput.prerender = VIRTUAL.entryPrerender;
144
146
  return {
145
147
  appType: "custom",
146
148
  ssr: { noExternal: [/^vike-lite(?:$|-)/] },
@@ -205,10 +207,7 @@ function vikeLite({ pagesDir = "pages", apiPrefix = "/api", prerender = false, s
205
207
  minify,
206
208
  sourcemap,
207
209
  rolldownOptions: {
208
- input: hasAnyPrerender ? {
209
- index: VIRTUAL.entryServer,
210
- prerender: VIRTUAL.entryPrerender
211
- } : { index: VIRTUAL.entryServer },
210
+ input: serverInput,
212
211
  output: {
213
212
  format: "esm",
214
213
  entryFileNames: "[name].mjs",
@@ -295,57 +294,64 @@ function vikeLite({ pagesDir = "pages", apiPrefix = "/api", prerender = false, s
295
294
  }
296
295
  if (id === RESOLVED.entryPrerender) return importSetup + `export{routes}from'${VIRTUAL.routes}';export{renderPage}from'vike-lite/server';`;
297
296
  },
298
- async closeBundle() {
299
- if (!isProd || !hasAnyPrerender || this.environment.name !== "ssr") return;
300
- const { pathToFileURL } = await import("node:url");
301
- const { routes, renderPage } = await import(pathToFileURL(path.join(viteConfigRoot, outDir, "server/prerender.mjs")).href);
302
- const urlsToPrerender = /* @__PURE__ */ new Set();
303
- for (const route of routes) {
304
- let shouldPrerender = prerender;
305
- let dynamicUrls = [];
306
- if (route.Prerender) {
307
- const mod = await route.Prerender();
308
- const prerenderFn = mod.default ?? mod.prerender;
309
- const result = typeof prerenderFn === "function" ? await prerenderFn() : prerenderFn;
310
- if (result === false) shouldPrerender = false;
311
- else if (result === true) shouldPrerender = true;
312
- else if (Array.isArray(result)) {
313
- shouldPrerender = true;
314
- dynamicUrls = result;
297
+ closeBundle: {
298
+ order: "pre",
299
+ async handler() {
300
+ if (!isProd || !hasAnyPrerender || this.environment.name !== "ssr") return;
301
+ const { pathToFileURL } = await import("node:url");
302
+ const prerenderPath = path.join(viteConfigRoot, outDir, "server/prerender.mjs");
303
+ const { routes, renderPage } = await import(pathToFileURL(prerenderPath).href);
304
+ try {
305
+ fs.unlinkSync(prerenderPath);
306
+ } catch {}
307
+ const urlsToPrerender = /* @__PURE__ */ new Set();
308
+ for (const route of routes) {
309
+ let shouldPrerender = prerender;
310
+ let dynamicUrls = [];
311
+ if (route.Prerender) {
312
+ const mod = await route.Prerender();
313
+ const prerenderFn = mod.default ?? mod.prerender;
314
+ const result = typeof prerenderFn === "function" ? await prerenderFn() : prerenderFn;
315
+ if (result === false) shouldPrerender = false;
316
+ else if (result === true) shouldPrerender = true;
317
+ else if (Array.isArray(result)) {
318
+ shouldPrerender = true;
319
+ dynamicUrls = result;
320
+ }
315
321
  }
316
- }
317
- if (shouldPrerender) {
318
- if (route.path.includes(":") && dynamicUrls.length === 0) {
319
- console.warn(`⚠️ Skipping dynamic route ${route.path}: no URLs provided by +prerender. Return an array of URLs to prerender it.`);
320
- continue;
322
+ if (shouldPrerender) {
323
+ if (route.path.includes(":") && dynamicUrls.length === 0) {
324
+ console.warn(`⚠️ Skipping dynamic route ${route.path}: no URLs provided by +prerender. Return an array of URLs to prerender it.`);
325
+ continue;
326
+ }
327
+ if (!route.path.includes(":")) urlsToPrerender.add(route.path);
328
+ for (const url of dynamicUrls) urlsToPrerender.add(url);
321
329
  }
322
- if (!route.path.includes(":")) urlsToPrerender.add(route.path);
323
- for (const url of dynamicUrls) urlsToPrerender.add(url);
324
330
  }
331
+ if (urlsToPrerender.size === 0) {
332
+ console.warn("⚠️ No static routes to generate: if you don't want to use SSG, in the 'vite.config' set the \"prerender\" option as \"false\" or remove it.");
333
+ return;
334
+ }
335
+ console.log("📦 Starting Static Site Generation (SSG)…");
336
+ const clientDir = path.join(viteConfigRoot, outDir, "client");
337
+ for (const urlPath of urlsToPrerender) {
338
+ const htmlRes = await renderPage(new Request(`http://localhost${baseUrl}${urlPath}`));
339
+ if (htmlRes.ok && htmlRes.headers.get("content-type")?.includes("text/html")) {
340
+ const outDirRoute = path.join(clientDir, urlPath === "/" ? "" : urlPath);
341
+ fs.mkdirSync(outDirRoute, { recursive: true });
342
+ fs.writeFileSync(path.join(outDirRoute, "index.html"), await htmlRes.text());
343
+ } else throw new Error(`❌ SSG HTML Error for "${urlPath}"`);
344
+ const jsonTarget = urlPath === "/" ? "/index" : urlPath;
345
+ const jsonRes = await renderPage(new Request(`http://localhost${baseUrl}${jsonTarget}.pageContext.json`));
346
+ if (jsonRes.ok) {
347
+ const jsonOutPath = path.join(clientDir, `${jsonTarget}.pageContext.json`);
348
+ fs.mkdirSync(path.dirname(jsonOutPath), { recursive: true });
349
+ fs.writeFileSync(jsonOutPath, await jsonRes.text());
350
+ } else throw new Error(`❌ SSG JSON Error for "${jsonTarget}"`);
351
+ console.log(` → route ${urlPath}`);
352
+ }
353
+ console.log(`✨ SSG Completed! Generated ${urlsToPrerender.size} static routes`);
325
354
  }
326
- if (urlsToPrerender.size === 0) {
327
- console.warn("⚠️ No static routes to generate: if you don't want to use SSG, in the 'vite.config' set the \"prerender\" option as \"false\" or remove it.");
328
- return;
329
- }
330
- console.log("📦 Starting Static Site Generation (SSG)…");
331
- const clientDir = path.join(viteConfigRoot, outDir, "client");
332
- for (const urlPath of urlsToPrerender) {
333
- const htmlRes = await renderPage(new Request(`http://localhost${baseUrl}${urlPath}`));
334
- if (htmlRes.ok && htmlRes.headers.get("content-type")?.includes("text/html")) {
335
- const outDirRoute = path.join(clientDir, urlPath === "/" ? "" : urlPath);
336
- fs.mkdirSync(outDirRoute, { recursive: true });
337
- fs.writeFileSync(path.join(outDirRoute, "index.html"), await htmlRes.text());
338
- } else throw new Error(`❌ SSG HTML Error for "${urlPath}"`);
339
- const jsonTarget = urlPath === "/" ? "/index" : urlPath;
340
- const jsonRes = await renderPage(new Request(`http://localhost${baseUrl}${jsonTarget}.pageContext.json`));
341
- if (jsonRes.ok) {
342
- const jsonOutPath = path.join(clientDir, `${jsonTarget}.pageContext.json`);
343
- fs.mkdirSync(path.dirname(jsonOutPath), { recursive: true });
344
- fs.writeFileSync(jsonOutPath, await jsonRes.text());
345
- } else throw new Error(`❌ SSG JSON Error for "${jsonTarget}"`);
346
- console.log(` → route ${urlPath}`);
347
- }
348
- console.log(`✨ SSG Completed! Generated ${urlsToPrerender.size} static routes`);
349
355
  },
350
356
  configureServer(server) {
351
357
  return () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vike-lite",
3
- "version": "1.15.18",
3
+ "version": "1.15.20",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -82,7 +82,7 @@
82
82
  },
83
83
  "devDependencies": {
84
84
  "@types/node": "^26.1.1",
85
- "tsdown": "^0.22.11",
85
+ "tsdown": "^0.22.12",
86
86
  "vite": "^8.1.5",
87
87
  "vitest": "^4.1.10"
88
88
  },