vike-lite 1.2.2 → 1.3.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
@@ -4,7 +4,7 @@ Light version of [Vike](https://vike.dev)
4
4
 
5
5
  ### ✨ Features
6
6
  ❯ **Zero dependencies:**<br> _light_ with less dependencies and essential checks
7
- ❯ **Functionalities:**<br> [See documentation](doc/FUNCTIONALITIES)
7
+ ❯ **Functionalities:**<br> [See documentation](doc/FUNCTIONALITIES.md)
8
8
 
9
9
  ### ⚙️ Install
10
10
  | Package Manager | Command
@@ -65,6 +65,12 @@ app.onError((error, c) => {
65
65
  export default app
66
66
  ```
67
67
 
68
+ > Note: if you don't use a custom server (loaded by the `serverEntry` option), a default server is bundled. In PROD the server is started as follow:
69
+ ```ts
70
+ // startServer.mjs
71
+ import './dist/server/index.mjs'
72
+ ```
73
+
68
74
  ### 🫶 Contribution
69
75
  Clone
70
76
  ```sh
@@ -1,4 +1,3 @@
1
- import { r as Manifest } from "../index-B6dJFVs8.mjs";
2
1
  import { t as Config } from "../index-kftPCG4J.mjs";
3
2
 
4
3
  //#region src/server/store.d.ts
package/dist/index.d.mts CHANGED
@@ -1,2 +1,15 @@
1
- import { a as Route, i as PageContext, n as DataSync, r as Manifest, t as DataAsync } from "./index-B6dJFVs8.mjs";
2
- export { DataAsync, DataSync, Manifest, PageContext, Route };
1
+ //#region src/index.d.ts
2
+ type PageContext<Data = unknown> = {
3
+ routeParams: Record<string, string>;
4
+ urlOriginal: string;
5
+ urlPathname: string;
6
+ data?: Data;
7
+ title?: string;
8
+ is404?: boolean;
9
+ is500?: boolean;
10
+ errorMessage?: string;
11
+ };
12
+ type DataAsync<Data = unknown> = (pageContext: PageContext) => Promise<Data>;
13
+ type DataSync<Data = unknown> = (pageContext: PageContext) => Data;
14
+ //#endregion
15
+ export { DataAsync, DataSync, PageContext };
package/dist/server.mjs CHANGED
@@ -24,7 +24,7 @@ var AbortRender = class extends Error {
24
24
  }
25
25
  };
26
26
  //#endregion
27
- //#region src/server/renderPage.tsx
27
+ //#region src/server/renderPage.ts
28
28
  const isProd = process.env.NODE_ENV === "production";
29
29
  function getAssets(route) {
30
30
  if (!isProd) return {
package/dist/vite.mjs CHANGED
@@ -2,7 +2,8 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { Readable } from "node:stream";
4
4
  import { pipeline } from "node:stream/promises";
5
- //#region src/vite-plugin.ts
5
+ import { loadEnv } from "vite";
6
+ //#region src/utils/generateRoutes.ts
6
7
  function generateRoutes(viteRoot, pagesDir) {
7
8
  const pagesAbsPath = path.resolve(viteRoot, pagesDir);
8
9
  if (!fs.existsSync(pagesAbsPath)) return { routes: [] };
@@ -55,6 +56,8 @@ function generateRoutes(viteRoot, pagesDir) {
55
56
  errorRoute
56
57
  };
57
58
  }
59
+ //#endregion
60
+ //#region src/utils/injectFOUCStyles.ts
58
61
  /**
59
62
  * Anti-FOUC: Inspect all known SSR modules, ask the client environment
60
63
  * to translate them into plain text (thanks to ?direct) and return them.
@@ -77,13 +80,18 @@ async function injectFOUCStyles(server, html) {
77
80
  if (headEndIndex === -1) return html;
78
81
  return `${html.slice(0, headEndIndex)}<style type="text/css" data-vite-dev-fouc>${cssContent}</style>${html.slice(headEndIndex)}`;
79
82
  }
83
+ //#endregion
84
+ //#region src/config.ts
85
+ const SUPPORTED_RENDERERS = ["solid"];
86
+ //#endregion
87
+ //#region src/vite-plugin.ts
80
88
  function routerPlugin({ pagesDir = "pages", serverEntry = "server/index", apiPrefix = "/api" } = {}) {
81
89
  const isProd = process.env.NODE_ENV === "production";
82
90
  let viteConfigRoot;
83
91
  let outDir;
84
92
  const virtualModuleId = "virtual:routes";
85
93
  const virtualManifestId = "virtual:client-manifest";
86
- const virtualAdapterId = "virtual:vike-lite-solid";
94
+ const virtualRendererId = "virtual:vike-lite/renderer";
87
95
  const virtualEntryClientId = "virtual:entry-client";
88
96
  const virtualSetupId = "virtual:vike-lite/setup";
89
97
  const virtualEntryServerId = "virtual:entry-server";
@@ -94,7 +102,9 @@ function routerPlugin({ pagesDir = "pages", serverEntry = "server/index", apiPre
94
102
  const resolvedVirtualEntryServerId = "\0virtual:entry-server";
95
103
  return {
96
104
  name: "vike-lite",
97
- config(config) {
105
+ config(config, { mode }) {
106
+ const envVariables = loadEnv(mode, config.envDir || process.cwd());
107
+ for (const key in envVariables) if (process.env[key] === void 0) process.env[key] = envVariables[key];
98
108
  outDir = config.build?.outDir ?? "dist";
99
109
  const { emptyOutDir, minify = true, cssMinify = true, sourcemap } = config.build || {};
100
110
  return {
@@ -143,6 +153,7 @@ function routerPlugin({ pagesDir = "pages", serverEntry = "server/index", apiPre
143
153
  },
144
154
  configResolved(config) {
145
155
  viteConfigRoot = config.root;
156
+ if (!config.plugins.some((plugin) => plugin.name?.startsWith("vike-lite-") && SUPPORTED_RENDERERS.includes(plugin.name.replace("vike-lite-", "")))) throw new Error(`No UI renderer plugin found in 'vite.config': please install and configure one of ${SUPPORTED_RENDERERS.map((r) => `vike-lite-${r}`).join(", ")}`);
146
157
  },
147
158
  resolveId(id) {
148
159
  if (id === virtualModuleId) return resolvedVirtualModuleId;
@@ -155,7 +166,7 @@ function routerPlugin({ pagesDir = "pages", serverEntry = "server/index", apiPre
155
166
  if (id === resolvedVirtualModuleId) {
156
167
  const { routes, errorRoute } = generateRoutes(viteConfigRoot, pagesDir);
157
168
  const isSSR = options.ssr;
158
- let code = `import { onRenderHtml } from '${virtualAdapterId}';\nexport const config = { onRenderHtml };\nexport const routes = [\n`;
169
+ let code = `import { onRenderHtml } from '${virtualRendererId}';\nexport const config = { onRenderHtml };\nexport const routes = [\n`;
159
170
  for (const r of routes) {
160
171
  code += `{path:'${r.path}',page:'${r.page}',Page:()=>import('/${r.page}'),`;
161
172
  if (r.head) code += `head:'${r.head}',Head:()=>import('/${r.head}'),`;
@@ -183,7 +194,7 @@ function routerPlugin({ pagesDir = "pages", serverEntry = "server/index", apiPre
183
194
  return `export default ${fs.readFileSync(manifestPath, "utf8")}`;
184
195
  }
185
196
  if (id === resolvedVirtualEntryClientId) return `import { routes, errorRoute } from '${virtualModuleId}';
186
- import { onRenderClient } from '${virtualAdapterId}';
197
+ import { onRenderClient } from '${virtualRendererId}';
187
198
  const { default: render } = await onRenderClient();
188
199
  await render({ routes, errorRoute });`;
189
200
  if (id === resolvedVirtualSetupId) return `
@@ -196,10 +207,109 @@ function routerPlugin({ pagesDir = "pages", serverEntry = "server/index", apiPre
196
207
  setVikeState({ routes, errorRoute, config, manifest });
197
208
  `;
198
209
  if (id === resolvedVirtualEntryServerId) {
199
- const normalizedServerEntry = path.join(viteConfigRoot, serverEntry).replaceAll("\\", "/");
200
- return `import '${virtualSetupId}';
201
- export * from '${normalizedServerEntry}';
202
- export { default } from '${normalizedServerEntry}';`;
210
+ const extensions = [
211
+ ".ts",
212
+ ".js",
213
+ ".mjs"
214
+ ];
215
+ let hasCustomServer = false;
216
+ let customServerPath = "";
217
+ if (serverEntry) {
218
+ const basePath = path.resolve(viteConfigRoot, serverEntry);
219
+ for (const ext of ["", ...extensions]) if (fs.existsSync(basePath + ext)) {
220
+ hasCustomServer = true;
221
+ customServerPath = (basePath + ext).replaceAll("\\", "/");
222
+ break;
223
+ }
224
+ }
225
+ if (hasCustomServer) return `import '${virtualSetupId}';
226
+ export * from '${customServerPath}';
227
+ export { default } from '${customServerPath}';`;
228
+ return String.raw`import '${virtualSetupId}';
229
+ import { renderPage } from 'vike-lite/server';
230
+ export default {
231
+ async fetch(request) {
232
+ return renderPage(request);
233
+ }
234
+ };
235
+ if (process.env.NODE_ENV === 'production') {
236
+ const { createServer } = await import('node:http');
237
+ const { Readable } = await import('node:stream');
238
+ const { pipeline } = await import('node:stream/promises');
239
+ const fs = await import('node:fs');
240
+ const path = await import('node:path');
241
+ const { fileURLToPath } = await import('node:url');
242
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
243
+ const clientDir = path.resolve(__dirname, '../client');
244
+ const MIME_TYPES = {
245
+ '.html': 'text/html',
246
+ '.js': 'text/javascript',
247
+ '.mjs': 'text/javascript',
248
+ '.css': 'text/css',
249
+ '.json': 'application/json',
250
+ '.png': 'image/png',
251
+ '.jpg': 'image/jpeg',
252
+ '.jpeg': 'image/jpeg',
253
+ '.gif': 'image/gif',
254
+ '.svg': 'image/svg+xml',
255
+ '.ico': 'image/x-icon',
256
+ '.webmanifest': 'application/manifest+json',
257
+ '.xml': 'application/xml',
258
+ '.txt': 'text/plain',
259
+ '.woff': 'font/woff',
260
+ '.woff2': 'font/woff2'
261
+ };
262
+ const server = createServer(async (req, res) => {
263
+ try {
264
+ const urlObj = new URL(req.url || '/', 'http://' + (req.headers.host || 'localhost'));
265
+ const pathname = urlObj.pathname;
266
+ if (pathname !== '/') {
267
+ const filePath = path.join(clientDir, pathname);
268
+ if (filePath.startsWith(clientDir) && fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {
269
+ const ext = path.extname(filePath).toLowerCase();
270
+ const mimeType = MIME_TYPES[ext] || 'application/octet-stream';
271
+ res.setHeader('Content-Type', mimeType);
272
+ if (pathname.startsWith('/assets/')) {
273
+ res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
274
+ }
275
+ fs.createReadStream(filePath).pipe(res);
276
+ return;
277
+ }
278
+ }
279
+ const headers = new Headers();
280
+ for (const [key, val] of Object.entries(req.headers)) {
281
+ if (Array.isArray(val)) val.forEach(v => headers.append(key, v));
282
+ else if (val) headers.set(key, val);
283
+ }
284
+ const { method } = req;
285
+ const init = { method, headers };
286
+ if (method !== 'GET' && method !== 'HEAD') {
287
+ init.body = Readable.toWeb(req);
288
+ init.duplex = 'half';
289
+ }
290
+ const request = new Request(urlObj.href, init);
291
+ const response = await renderPage(request);
292
+ res.statusCode = response.status;
293
+ for (const [key, val] of response.headers) {
294
+ res.setHeader(key, val);
295
+ }
296
+ if (response.body) {
297
+ await pipeline(Readable.fromWeb(response.body), res);
298
+ } else {
299
+ res.end();
300
+ }
301
+ } catch (e) {
302
+ console.error(e);
303
+ res.statusCode = 500;
304
+ res.end('Internal Server Error');
305
+ }
306
+ });
307
+ const { PORT } = process.env;
308
+ const port = PORT ? Number.parseInt(PORT) : 3000;
309
+ server.listen(port, () => {
310
+ console.log('\n\x1b[32m🚀 Server is running at http://localhost:' + port + '\x1b[0m\n');
311
+ });
312
+ }`;
203
313
  }
204
314
  },
205
315
  configureServer(server) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vike-lite",
3
- "version": "1.2.2",
3
+ "version": "1.3.1",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "module": "./dist/index.mjs",
@@ -38,18 +38,11 @@
38
38
  "dist"
39
39
  ],
40
40
  "scripts": {
41
- "lint": "eslint src/**/*.{ts,tsx} *.ts",
42
- "build": "tsdown",
43
- "od": "yarn outdated"
41
+ "build": "tsdown"
44
42
  },
45
43
  "devDependencies": {
46
44
  "@types/node": "^26.0.1",
47
- "@yarnpkg/sdks": "^3.3.0",
48
- "eslint": "^10.6.0",
49
- "eslint-plugin-unicorn": "^69.0.0",
50
45
  "tsdown": "^0.22.3",
51
- "typescript": "^6.0.3",
52
- "typescript-eslint": "^8.62.0",
53
46
  "vite": "^8.1.0"
54
47
  },
55
48
  "peerDependencies": {
@@ -57,6 +50,5 @@
57
50
  },
58
51
  "engines": {
59
52
  "node": "^20.19.0 || >=22.12.0"
60
- },
61
- "packageManager": "yarn@4.17.0"
62
- }
53
+ }
54
+ }
@@ -1,29 +0,0 @@
1
- //#region src/index.d.ts
2
- type PageContext<Data = unknown> = {
3
- routeParams: Record<string, string>;
4
- urlOriginal: string;
5
- urlPathname: string;
6
- data?: Data;
7
- title?: string;
8
- is404?: boolean;
9
- is500?: boolean;
10
- errorMessage?: string;
11
- };
12
- type DataAsync<Data = unknown> = (pageContext: PageContext) => Promise<Data>;
13
- type DataSync<Data = unknown> = (pageContext: PageContext) => Data;
14
- type Route = {
15
- path: string;
16
- page: string;
17
- layout?: string;
18
- head?: string;
19
- hasData?: boolean;
20
- hasTitle?: boolean;
21
- };
22
- type Manifest = Record<string, {
23
- file: string;
24
- css?: string[];
25
- imports?: string[];
26
- isEntry?: boolean;
27
- }>;
28
- //#endregion
29
- export { Route as a, PageContext as i, DataSync as n, Manifest as r, DataAsync as t };