vike-lite 1.6.2 → 1.7.1

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.
package/README.md CHANGED
@@ -18,9 +18,10 @@ import vikeLite from 'vike-lite/vite'
18
18
  export default {
19
19
  plugins: [
20
20
  vikeLite({
21
- pagesDir = 'pages', // default
22
- serverEntry = 'server/index', // default
23
- apiPrefix = '/api' // default
21
+ pagesDir = 'pages', // Default
22
+ serverEntry = 'server/index', // Default
23
+ apiPrefix = '/api', // Default
24
+ prerender = false // Default
24
25
  })
25
26
  ]
26
27
  } satisfies UserConfig
@@ -2,8 +2,8 @@ import { t as Config } from "../index-Dt5n1zWh.mjs";
2
2
 
3
3
  //#region src/server/store.d.ts
4
4
  interface VikeState {
5
- routes: any[];
6
- errorRoute: any | null;
5
+ routes: typeof import('virtual:routes')['routes'];
6
+ errorRoute: typeof import('virtual:routes')['errorRoute'] | null;
7
7
  config: Config | null;
8
8
  manifest: Manifest | undefined;
9
9
  }
package/dist/server.mjs CHANGED
@@ -74,8 +74,8 @@ async function buildPageContext(urlPathname, urlOriginal, isJsonRequest) {
74
74
  urlPathname
75
75
  };
76
76
  const [dataMod, titleMod, PageModule, HeadModule, LayoutModule] = await Promise.all([
77
- route.data?.() ?? null,
78
- route.title?.() ?? null,
77
+ route.Data?.() ?? null,
78
+ route.Title?.() ?? null,
79
79
  isJsonRequest ? null : route.Page(),
80
80
  isJsonRequest ? null : route.Head?.() ?? null,
81
81
  isJsonRequest ? null : route.Layout?.() ?? null
@@ -137,7 +137,7 @@ async function renderErrorPage(req, status, urlPathname, error) {
137
137
  }
138
138
  }
139
139
  async function renderPage(req) {
140
- let pathname = new URL(req.url).pathname;
140
+ let { pathname } = new URL(req.url);
141
141
  if (BASE_URL !== "/") {
142
142
  const baseSlashed = BASE_URL.endsWith("/") ? BASE_URL : BASE_URL + "/";
143
143
  const baseNoSlash = baseSlashed.slice(0, -1);
package/dist/vite.d.mts CHANGED
@@ -4,7 +4,8 @@ import { Plugin } from "vite";
4
4
  declare function routerPlugin({
5
5
  pagesDir,
6
6
  serverEntry,
7
- apiPrefix
7
+ apiPrefix,
8
+ prerender
8
9
  }?: {
9
10
  /**
10
11
  * The directory where your page components are located.
@@ -24,6 +25,11 @@ declare function routerPlugin({
24
25
  * @default '/api'
25
26
  */
26
27
  apiPrefix?: string;
28
+ /**
29
+ * Whether to prerender the pages.
30
+ * @default false
31
+ */
32
+ prerender?: boolean;
27
33
  }): Plugin;
28
34
  //#endregion
29
35
  export { routerPlugin as default };
package/dist/vite.mjs CHANGED
@@ -4,6 +4,11 @@ import { Readable } from "node:stream";
4
4
  import { pipeline } from "node:stream/promises";
5
5
  import { loadEnv } from "vite";
6
6
  //#region src/utils/generateRoutes.ts
7
+ const pageExtensions = [".ts", ".js"];
8
+ const pageExtensionsX = [".tsx", ".jsx"];
9
+ function findFile(files, basename, extensions) {
10
+ return files.find((file) => extensions.some((ext) => file === `${basename}${ext}`));
11
+ }
7
12
  function generateRoutes(viteRoot, pagesDir) {
8
13
  const pagesAbsPath = path.resolve(viteRoot, pagesDir);
9
14
  if (!fs.existsSync(pagesAbsPath)) return { routes: [] };
@@ -12,15 +17,22 @@ function generateRoutes(viteRoot, pagesDir) {
12
17
  function walk(dir, routePath, parentLayout, parentHead) {
13
18
  const files = fs.readdirSync(dir);
14
19
  const importPath = path.relative(viteRoot, dir).replaceAll("\\", "/");
15
- const currentLayout = files.includes("+Layout.tsx") ? `${importPath}/+Layout.tsx` : parentLayout;
16
- const currentHead = files.includes("+Head.tsx") ? `${importPath}/+Head.tsx` : parentHead;
17
- if (files.includes("+Page.tsx")) {
20
+ const layoutFile = findFile(files, "+Layout", pageExtensionsX);
21
+ const currentLayout = layoutFile ? `${importPath}/${layoutFile}` : parentLayout;
22
+ const headFile = findFile(files, "+Head", pageExtensionsX);
23
+ const currentHead = headFile ? `${importPath}/${headFile}` : parentHead;
24
+ const pageFile = findFile(files, "+Page", pageExtensionsX);
25
+ if (pageFile) {
18
26
  const route = {
19
27
  path: routePath || "/",
20
- page: `${importPath}/+Page.tsx`,
21
- hasData: files.includes("+data.ts"),
22
- hasTitle: files.includes("+title.ts")
28
+ page: `${importPath}/${pageFile}`
23
29
  };
30
+ const dataFile = findFile(files, "+data", pageExtensions);
31
+ const titleFile = findFile(files, "+title", pageExtensions);
32
+ const prerenderFile = findFile(files, "+prerender", pageExtensions);
33
+ if (dataFile) route.data = `${importPath}/${dataFile}`;
34
+ if (titleFile) route.title = `${importPath}/${titleFile}`;
35
+ if (prerenderFile) route.prerender = `${importPath}/${prerenderFile}`;
24
36
  if (currentLayout) route.layout = currentLayout;
25
37
  if (currentHead) route.head = currentHead;
26
38
  routes.push(route);
@@ -29,9 +41,10 @@ function generateRoutes(viteRoot, pagesDir) {
29
41
  const fullPath = path.join(dir, file);
30
42
  if (!fs.statSync(fullPath).isDirectory()) continue;
31
43
  if (file === "_error") {
32
- if (fs.readdirSync(fullPath).includes("+Page.tsx")) errorRoute = {
44
+ const errorPageFile = findFile(fs.readdirSync(fullPath), "+Page", pageExtensionsX);
45
+ if (errorPageFile) errorRoute = {
33
46
  path: "_error",
34
- page: `${importPath}/_error/+Page.tsx`,
47
+ page: `${importPath}/_error/${errorPageFile}`,
35
48
  layout: currentLayout,
36
49
  head: currentHead
37
50
  };
@@ -85,7 +98,7 @@ async function injectFOUCStyles(server, html) {
85
98
  const SUPPORTED_RENDERERS = ["solid"];
86
99
  //#endregion
87
100
  //#region src/vite-plugin.ts
88
- function routerPlugin({ pagesDir = "pages", serverEntry = "server/index", apiPrefix = "/api" } = {}) {
101
+ function routerPlugin({ pagesDir = "pages", serverEntry = "server/index", apiPrefix = "/api", prerender = false } = {}) {
89
102
  const isProd = process.env.NODE_ENV === "production";
90
103
  let viteConfigRoot;
91
104
  let outDir;
@@ -172,10 +185,13 @@ function routerPlugin({ pagesDir = "pages", serverEntry = "server/index", apiPre
172
185
  code += `{path:'${r.path}',page:'${r.page}',Page:()=>import('/${r.page}'),`;
173
186
  if (r.head) code += `head:'${r.head}',Head:()=>import('/${r.head}'),`;
174
187
  if (r.layout) code += `layout:'${r.layout}',Layout:()=>import('/${r.layout}'),`;
175
- code += `hasData:${r.hasData},hasTitle:${r.hasTitle},`;
188
+ if (r.data) code += `data:'${r.data}',`;
189
+ if (r.title) code += `title:'${r.title}',`;
190
+ if (r.prerender) code += `prerender:'${r.prerender}',`;
176
191
  if (isSSR) {
177
- if (r.hasData) code += `data:()=>import('/${r.page.replace("+Page.tsx", "+data.ts")}'),`;
178
- if (r.hasTitle) code += `title:()=>import('/${r.page.replace("+Page.tsx", "+title.ts")}'),`;
192
+ if (r.data) code += `Data:()=>import('/${r.data}'),`;
193
+ if (r.title) code += `Title:()=>import('/${r.title}'),`;
194
+ if (r.prerender) code += `Prerender:()=>import('/${r.prerender}'),`;
179
195
  }
180
196
  code += "},";
181
197
  }
@@ -220,11 +236,8 @@ function routerPlugin({ pagesDir = "pages", serverEntry = "server/index", apiPre
220
236
  break;
221
237
  }
222
238
  }
223
- if (hasCustomServer) return `import '${virtualSetupId}';
224
- export * from '${customServerPath}';
225
- export { default } from '${customServerPath}';`;
226
- return String.raw`import '${virtualSetupId}';
227
- import { renderPage } from 'vike-lite/server';
239
+ if (hasCustomServer) return `import '${virtualSetupId}';` + (prerender ? `export{routes}from'${virtualModuleId}';` : "") + `export * from'${customServerPath}';export{default}from'${customServerPath}';`;
240
+ return `import '${virtualSetupId}';` + (prerender ? `export{routes}from'${virtualModuleId}';` : "") + `import { renderPage } from 'vike-lite/server';
228
241
  export default {
229
242
  async fetch(request) {
230
243
  return renderPage(request);
@@ -313,11 +326,67 @@ if (process.env.NODE_ENV === 'production') {
313
326
  const { PORT } = process.env;
314
327
  const port = PORT ? Number.parseInt(PORT) : 3000;
315
328
  server.listen(port, () => {
316
- console.log('\n\x1b[32m🚀 Server is running at http://localhost:' + port + '\x1b[0m\n');
329
+ console.log('\n\u{1B}[32m🚀 Server is running at http://localhost:' + port + '\u{1B}[0m\n');
317
330
  });
318
331
  }`;
319
332
  }
320
333
  },
334
+ async closeBundle() {
335
+ if (!prerender || !isProd || !import.meta.env.SSR) return;
336
+ await new Promise((resolve) => setTimeout(resolve, 500));
337
+ const { pathToFileURL } = await import("node:url");
338
+ const serverEntryPath = path.resolve(viteConfigRoot, outDir, "server/index.mjs");
339
+ if (!fs.existsSync(serverEntryPath)) return;
340
+ const serverModule = await import(pathToFileURL(serverEntryPath).href);
341
+ const app = serverModule.default;
342
+ const routes = serverModule.routes || [];
343
+ const urlsToPrerender = /* @__PURE__ */ new Set();
344
+ for (const route of routes) {
345
+ let shouldPrerender = true;
346
+ let dynamicUrls = [];
347
+ if (route.Prerender) {
348
+ const mod = await route.Prerender();
349
+ const prerenderFn = mod.default ?? mod.prerender;
350
+ const result = typeof prerenderFn === "function" ? await prerenderFn() : prerenderFn;
351
+ if (result === false) shouldPrerender = false;
352
+ else if (result === true) shouldPrerender = true;
353
+ else if (Array.isArray(result)) {
354
+ shouldPrerender = true;
355
+ dynamicUrls = result;
356
+ }
357
+ }
358
+ if (shouldPrerender) {
359
+ if (!route.path.includes(":")) urlsToPrerender.add(route.path === "/" ? "/" : route.path);
360
+ for (const url of dynamicUrls) urlsToPrerender.add(url);
361
+ }
362
+ }
363
+ if (urlsToPrerender.size === 0) return;
364
+ console.log("\n\x1B[36m📦 Starting Static Site Generation (SSG)...\x1B[0m");
365
+ const base = process.env.BASE_URL || "/";
366
+ const baseNoSlash = base.endsWith("/") ? base.slice(0, -1) : base;
367
+ let generatedCount = 0;
368
+ const clientDir = path.resolve(viteConfigRoot, outDir, "client");
369
+ for (const urlPath of urlsToPrerender) {
370
+ const htmlReq = new Request(`http://localhost${baseNoSlash}${urlPath}`);
371
+ const htmlRes = await app.fetch(htmlReq);
372
+ if (htmlRes.ok && htmlRes.headers.get("content-type")?.includes("text/html")) {
373
+ const outDirRoute = path.join(clientDir, urlPath === "/" ? "" : urlPath);
374
+ fs.mkdirSync(outDirRoute, { recursive: true });
375
+ fs.writeFileSync(path.join(outDirRoute, "index.html"), await htmlRes.text());
376
+ } else console.error(`\u{1B}[31m✖ SSG HTML Error for ${urlPath}\u{1B}[0m`);
377
+ const jsonTarget = urlPath === "/" ? "/index" : urlPath;
378
+ const jsonReq = new Request(`http://localhost${baseNoSlash}${jsonTarget}.pageContext.json`);
379
+ const jsonRes = await app.fetch(jsonReq);
380
+ if (jsonRes.ok) {
381
+ const jsonOutPath = path.join(clientDir, `${jsonTarget}.pageContext.json`);
382
+ fs.mkdirSync(path.dirname(jsonOutPath), { recursive: true });
383
+ fs.writeFileSync(jsonOutPath, await jsonRes.text());
384
+ } else console.error(`\u{1B}[31m✖ SSG JSON Error for ${jsonTarget}\u{1B}[0m`);
385
+ console.log(`\u{1B}[32m✓\u{1B}[0m Pre-rendered: ${urlPath}`);
386
+ generatedCount++;
387
+ }
388
+ console.log(`\n\u{1B}[32m✨ SSG Completed! Generated ${generatedCount} static routes.\u{1B}[0m\n`);
389
+ },
321
390
  configureServer(server) {
322
391
  return () => {
323
392
  const pagesPath = path.resolve(viteConfigRoot, pagesDir);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vike-lite",
3
- "version": "1.6.2",
3
+ "version": "1.7.1",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "module": "./dist/index.mjs",
@@ -41,9 +41,9 @@
41
41
  "build": "tsdown"
42
42
  },
43
43
  "devDependencies": {
44
- "@types/node": "^26.0.1",
44
+ "@types/node": "^26.1.0",
45
45
  "tsdown": "^0.22.3",
46
- "vite": "^8.1.0"
46
+ "vite": "^8.1.3"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "vite": ">=8"