vike-lite 1.5.0 → 1.6.0
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/dist/__internal/server.d.mts +2 -2
- package/dist/server.mjs +16 -7
- package/dist/vite.d.mts +18 -3
- package/dist/vite.mjs +53 -34
- package/package.json +1 -1
|
@@ -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:
|
|
6
|
-
errorRoute:
|
|
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
|
@@ -26,11 +26,15 @@ var AbortRender = class extends Error {
|
|
|
26
26
|
//#endregion
|
|
27
27
|
//#region src/server/renderPage.ts
|
|
28
28
|
const isProd = process.env.NODE_ENV === "production";
|
|
29
|
+
const { BASE_URL } = import.meta.env;
|
|
30
|
+
function withBase(file) {
|
|
31
|
+
return `${BASE_URL.replace(/\/$/, "")}/${file.replace(/^\//, "")}`;
|
|
32
|
+
}
|
|
29
33
|
function getAssets(route) {
|
|
30
34
|
if (!isProd) return {
|
|
31
35
|
cssLinks: "",
|
|
32
36
|
jsPreloads: "",
|
|
33
|
-
entryClient: "
|
|
37
|
+
entryClient: withBase("@id/virtual:entry-client")
|
|
34
38
|
};
|
|
35
39
|
const cssFiles = /* @__PURE__ */ new Set();
|
|
36
40
|
const jsFiles = /* @__PURE__ */ new Set();
|
|
@@ -55,9 +59,9 @@ function getAssets(route) {
|
|
|
55
59
|
if (head) collectAssets(head);
|
|
56
60
|
if (layout) collectAssets(layout);
|
|
57
61
|
return {
|
|
58
|
-
cssLinks: [...cssFiles].map((href) => `<link rel="stylesheet" href="
|
|
59
|
-
jsPreloads: [...jsFiles].map((href) => `<link rel="modulepreload" href="
|
|
60
|
-
entryClient:
|
|
62
|
+
cssLinks: [...cssFiles].map((href) => `<link rel="stylesheet" href="${withBase(href)}">`).join(""),
|
|
63
|
+
jsPreloads: [...jsFiles].map((href) => `<link rel="modulepreload" href="${withBase(href)}">`).join(""),
|
|
64
|
+
entryClient: withBase(manifest[virtualEntryClientKey].file)
|
|
61
65
|
};
|
|
62
66
|
}
|
|
63
67
|
async function buildPageContext(urlPathname, urlOriginal, isJsonRequest) {
|
|
@@ -70,8 +74,8 @@ async function buildPageContext(urlPathname, urlOriginal, isJsonRequest) {
|
|
|
70
74
|
urlPathname
|
|
71
75
|
};
|
|
72
76
|
const [dataMod, titleMod, PageModule, HeadModule, LayoutModule] = await Promise.all([
|
|
73
|
-
route.
|
|
74
|
-
route.
|
|
77
|
+
route.Data?.() ?? null,
|
|
78
|
+
route.Title?.() ?? null,
|
|
75
79
|
isJsonRequest ? null : route.Page(),
|
|
76
80
|
isJsonRequest ? null : route.Head?.() ?? null,
|
|
77
81
|
isJsonRequest ? null : route.Layout?.() ?? null
|
|
@@ -133,7 +137,12 @@ async function renderErrorPage(req, status, urlPathname, error) {
|
|
|
133
137
|
}
|
|
134
138
|
}
|
|
135
139
|
async function renderPage(req) {
|
|
136
|
-
|
|
140
|
+
let pathname = new URL(req.url).pathname;
|
|
141
|
+
if (BASE_URL !== "/") {
|
|
142
|
+
const baseSlashed = BASE_URL.endsWith("/") ? BASE_URL : BASE_URL + "/";
|
|
143
|
+
const baseNoSlash = baseSlashed.slice(0, -1);
|
|
144
|
+
pathname = pathname === baseNoSlash ? "/" : pathname.slice(baseSlashed.length - 1);
|
|
145
|
+
}
|
|
137
146
|
const isJsonRequest = pathname.endsWith(".pageContext.json");
|
|
138
147
|
let targetPathname = pathname;
|
|
139
148
|
if (isJsonRequest) {
|
package/dist/vite.d.mts
CHANGED
|
@@ -6,9 +6,24 @@ declare function routerPlugin({
|
|
|
6
6
|
serverEntry,
|
|
7
7
|
apiPrefix
|
|
8
8
|
}?: {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
/**
|
|
10
|
+
* The directory where your page components are located.
|
|
11
|
+
* This is where the plugin will look for your page files to generate routes.
|
|
12
|
+
* @default 'pages'
|
|
13
|
+
*/
|
|
14
|
+
pagesDir?: string;
|
|
15
|
+
/**
|
|
16
|
+
* The entry point for your server application code.
|
|
17
|
+
* This is where you can define custom server logic, such as API routes or middleware.
|
|
18
|
+
* The build will produce dist/server/index.mjs, which is the entry point for your server application.
|
|
19
|
+
* @default 'server/index'
|
|
20
|
+
*/
|
|
21
|
+
serverEntry?: string;
|
|
22
|
+
/**
|
|
23
|
+
* The prefix for your API routes.
|
|
24
|
+
* @default '/api'
|
|
25
|
+
*/
|
|
26
|
+
apiPrefix?: string;
|
|
12
27
|
}): Plugin;
|
|
13
28
|
//#endregion
|
|
14
29
|
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,20 @@ 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
|
|
16
|
-
const
|
|
17
|
-
|
|
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}
|
|
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
|
+
if (dataFile) route.data = `${importPath}/${dataFile}`;
|
|
32
|
+
const titleFile = findFile(files, "+title", pageExtensions);
|
|
33
|
+
if (titleFile) route.title = `${importPath}/${titleFile}`;
|
|
24
34
|
if (currentLayout) route.layout = currentLayout;
|
|
25
35
|
if (currentHead) route.head = currentHead;
|
|
26
36
|
routes.push(route);
|
|
@@ -29,9 +39,10 @@ function generateRoutes(viteRoot, pagesDir) {
|
|
|
29
39
|
const fullPath = path.join(dir, file);
|
|
30
40
|
if (!fs.statSync(fullPath).isDirectory()) continue;
|
|
31
41
|
if (file === "_error") {
|
|
32
|
-
|
|
42
|
+
const errorPageFile = findFile(fs.readdirSync(fullPath), "+Page", pageExtensionsX);
|
|
43
|
+
if (errorPageFile) errorRoute = {
|
|
33
44
|
path: "_error",
|
|
34
|
-
page: `${importPath}/_error
|
|
45
|
+
page: `${importPath}/_error/${errorPageFile}`,
|
|
35
46
|
layout: currentLayout,
|
|
36
47
|
head: currentHead
|
|
37
48
|
};
|
|
@@ -172,10 +183,11 @@ function routerPlugin({ pagesDir = "pages", serverEntry = "server/index", apiPre
|
|
|
172
183
|
code += `{path:'${r.path}',page:'${r.page}',Page:()=>import('/${r.page}'),`;
|
|
173
184
|
if (r.head) code += `head:'${r.head}',Head:()=>import('/${r.head}'),`;
|
|
174
185
|
if (r.layout) code += `layout:'${r.layout}',Layout:()=>import('/${r.layout}'),`;
|
|
175
|
-
code += `
|
|
186
|
+
if (r.data) code += `data:'${r.data}',`;
|
|
187
|
+
if (r.title) code += `title:'${r.title}',`;
|
|
176
188
|
if (isSSR) {
|
|
177
|
-
if (r.
|
|
178
|
-
if (r.
|
|
189
|
+
if (r.data) code += `Data:()=>import('/${r.data}'),`;
|
|
190
|
+
if (r.title) code += `Title:()=>import('/${r.title}'),`;
|
|
179
191
|
}
|
|
180
192
|
code += "},";
|
|
181
193
|
}
|
|
@@ -206,16 +218,15 @@ function routerPlugin({ pagesDir = "pages", serverEntry = "server/index", apiPre
|
|
|
206
218
|
}
|
|
207
219
|
setVikeState({ routes, errorRoute, config, manifest });`;
|
|
208
220
|
if (id === resolvedVirtualEntryServerId) {
|
|
209
|
-
const extensions = [
|
|
210
|
-
".ts",
|
|
211
|
-
".js",
|
|
212
|
-
".mjs"
|
|
213
|
-
];
|
|
214
221
|
let hasCustomServer = false;
|
|
215
222
|
let customServerPath = "";
|
|
216
223
|
if (serverEntry) {
|
|
217
224
|
const basePath = path.resolve(viteConfigRoot, serverEntry);
|
|
218
|
-
for (const ext of [
|
|
225
|
+
for (const ext of [
|
|
226
|
+
".ts",
|
|
227
|
+
".js",
|
|
228
|
+
".mjs"
|
|
229
|
+
]) if (fs.existsSync(basePath + ext)) {
|
|
219
230
|
hasCustomServer = true;
|
|
220
231
|
customServerPath = (basePath + ext).replaceAll("\\", "/");
|
|
221
232
|
break;
|
|
@@ -241,11 +252,11 @@ if (process.env.NODE_ENV === 'production') {
|
|
|
241
252
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
242
253
|
const clientDir = path.resolve(__dirname, '../client');
|
|
243
254
|
const MIME_TYPES = {
|
|
244
|
-
'.html': 'text/html',
|
|
245
|
-
'.js': 'text/javascript',
|
|
246
|
-
'.mjs': 'text/javascript',
|
|
247
|
-
'.css': 'text/css',
|
|
248
|
-
'.json': 'application/json',
|
|
255
|
+
'.html': 'text/html; charset=utf-8',
|
|
256
|
+
'.js': 'text/javascript; charset=utf-8',
|
|
257
|
+
'.mjs': 'text/javascript; charset=utf-8',
|
|
258
|
+
'.css': 'text/css; charset=utf-8',
|
|
259
|
+
'.json': 'application/json; charset=utf-8',
|
|
249
260
|
'.png': 'image/png',
|
|
250
261
|
'.jpg': 'image/jpeg',
|
|
251
262
|
'.jpeg': 'image/jpeg',
|
|
@@ -254,23 +265,30 @@ if (process.env.NODE_ENV === 'production') {
|
|
|
254
265
|
'.ico': 'image/x-icon',
|
|
255
266
|
'.webmanifest': 'application/manifest+json',
|
|
256
267
|
'.xml': 'application/xml',
|
|
257
|
-
'.txt': 'text/plain',
|
|
268
|
+
'.txt': 'text/plain; charset=utf-8',
|
|
258
269
|
'.woff': 'font/woff',
|
|
259
|
-
'.woff2': 'font/woff2'
|
|
270
|
+
'.woff2': 'font/woff2',
|
|
271
|
+
'.wasm': 'application/wasm'
|
|
260
272
|
};
|
|
273
|
+
const base = import.meta.env.BASE_URL;
|
|
261
274
|
const server = createServer(async (req, res) => {
|
|
262
275
|
try {
|
|
263
276
|
const urlObj = new URL(req.url || '/', 'http://' + (req.headers.host || 'localhost'));
|
|
264
277
|
const pathname = urlObj.pathname;
|
|
265
|
-
|
|
266
|
-
|
|
278
|
+
let fileUrl = pathname;
|
|
279
|
+
if (base !== '/' && pathname.startsWith(base)) fileUrl = '/' + pathname.slice(base.length);
|
|
280
|
+
if (fileUrl !== '/') {
|
|
281
|
+
const filePath = path.resolve(clientDir, '.' + fileUrl)
|
|
282
|
+
if (!filePath.startsWith(clientDir + path.sep)) {
|
|
283
|
+
res.statusCode = 403
|
|
284
|
+
res.end('Forbidden')
|
|
285
|
+
return
|
|
286
|
+
}
|
|
267
287
|
if (filePath.startsWith(clientDir) && fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {
|
|
268
288
|
const ext = path.extname(filePath).toLowerCase();
|
|
269
289
|
const mimeType = MIME_TYPES[ext] || 'application/octet-stream';
|
|
270
290
|
res.setHeader('Content-Type', mimeType);
|
|
271
|
-
|
|
272
|
-
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
|
|
273
|
-
}
|
|
291
|
+
res.setHeader('Cache-Control', fileUrl.startsWith('/assets/') ? 'public, max-age=31536000, immutable' : 'public, max-age=0, must-revalidate')
|
|
274
292
|
fs.createReadStream(filePath).pipe(res);
|
|
275
293
|
return;
|
|
276
294
|
}
|
|
@@ -282,6 +300,10 @@ if (process.env.NODE_ENV === 'production') {
|
|
|
282
300
|
}
|
|
283
301
|
const { method } = req;
|
|
284
302
|
const init = { method, headers };
|
|
303
|
+
if (req.method === 'HEAD') {
|
|
304
|
+
res.end()
|
|
305
|
+
return
|
|
306
|
+
}
|
|
285
307
|
if (method !== 'GET' && method !== 'HEAD') {
|
|
286
308
|
init.body = Readable.toWeb(req);
|
|
287
309
|
init.duplex = 'half';
|
|
@@ -292,11 +314,8 @@ if (process.env.NODE_ENV === 'production') {
|
|
|
292
314
|
for (const [key, val] of response.headers) {
|
|
293
315
|
res.setHeader(key, val);
|
|
294
316
|
}
|
|
295
|
-
if (response.body)
|
|
296
|
-
|
|
297
|
-
} else {
|
|
298
|
-
res.end();
|
|
299
|
-
}
|
|
317
|
+
if (response.body) await pipeline(Readable.fromWeb(response.body), res);
|
|
318
|
+
else res.end();
|
|
300
319
|
} catch (e) {
|
|
301
320
|
console.error(e);
|
|
302
321
|
res.statusCode = 500;
|