vike-lite 1.11.1 → 1.13.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 -4
- package/dist/__internal/server.mjs +1 -1
- package/dist/__internal/shared.d.mts +23 -2
- package/dist/client/router.d.mts +0 -1
- package/dist/client/router.mjs +4 -2
- package/dist/server-Cm1ZA_Dp.mjs +220 -0
- package/dist/server.d.mts +1 -3
- package/dist/server.mjs +1 -195
- package/dist/{store-CfUB1COP.mjs → store-DPJQje-K.mjs} +1 -1
- package/dist/vite.d.mts +3 -8
- package/dist/vite.mjs +78 -84
- package/package.json +5 -4
- package/dist/index-ZDN-jKX_.d.mts +0 -34
- package/dist/shared-DEpJkq09.mjs +0 -4
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { t as Config } from "../index-ZDN-jKX_.mjs";
|
|
2
|
-
|
|
3
1
|
//#region src/server/store.d.ts
|
|
4
2
|
interface VikeState {
|
|
5
3
|
routes: typeof import('virtual:routes')['routes'];
|
|
6
4
|
errorRoute: typeof import('virtual:routes')['errorRoute'] | null;
|
|
7
|
-
config:
|
|
8
|
-
manifest:
|
|
5
|
+
config: typeof import('virtual:routes')['config'] | null;
|
|
6
|
+
manifest: typeof import('virtual:client-manifest')['default'] | null;
|
|
9
7
|
}
|
|
10
8
|
declare const store: VikeState;
|
|
11
9
|
declare function setVikeState(newState: Partial<VikeState>): void;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as store, t as setVikeState } from "../store-
|
|
1
|
+
import { n as store, t as setVikeState } from "../store-DPJQje-K.mjs";
|
|
2
2
|
export { setVikeState, store };
|
|
@@ -1,2 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
//#region src/__internal/shared/matchRoute.d.ts
|
|
2
|
+
declare function matchRoute(urlPathname: string, routes: typeof import('virtual:routes').routes): {
|
|
3
|
+
route: any;
|
|
4
|
+
routeParams: Record<string, string>;
|
|
5
|
+
} | null;
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/__internal/shared/index.d.ts
|
|
8
|
+
interface RenderContext {
|
|
9
|
+
pageContext: any;
|
|
10
|
+
Page: unknown;
|
|
11
|
+
Head?: unknown;
|
|
12
|
+
Layout?: unknown;
|
|
13
|
+
pageTitleTag: string;
|
|
14
|
+
serializedContext: string;
|
|
15
|
+
assets: {
|
|
16
|
+
cssLinks: string;
|
|
17
|
+
jsPreloads: string;
|
|
18
|
+
entryClient: string;
|
|
19
|
+
};
|
|
20
|
+
nonce?: string;
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { RenderContext, matchRoute };
|
package/dist/client/router.d.mts
CHANGED
package/dist/client/router.mjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { t as BASE_URL } from "../shared-DEpJkq09.mjs";
|
|
2
1
|
//#region src/client/router.ts
|
|
3
2
|
/**
|
|
4
3
|
* Change page programmatically on the client without reloading the browser.
|
|
@@ -8,7 +7,10 @@ import { t as BASE_URL } from "../shared-DEpJkq09.mjs";
|
|
|
8
7
|
function navigate(url, options) {
|
|
9
8
|
if (typeof globalThis === "undefined") throw new Error("navigate() can only be called on the client side.");
|
|
10
9
|
let finalUrl = url;
|
|
11
|
-
if (finalUrl.startsWith("/"))
|
|
10
|
+
if (finalUrl.startsWith("/")) {
|
|
11
|
+
const { BASE_URL } = import.meta.env;
|
|
12
|
+
finalUrl = (BASE_URL.endsWith("/") ? BASE_URL.slice(0, -1) : BASE_URL) + (finalUrl === "/" ? "" : finalUrl);
|
|
13
|
+
}
|
|
12
14
|
globalThis.history.pushState({ triggeredBy: "vike-lite" }, "", finalUrl);
|
|
13
15
|
globalThis.dispatchEvent(new CustomEvent("vike-navigate", { detail: {
|
|
14
16
|
keepScrollPosition: options?.keepScrollPosition,
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { t as matchRoute } from "./matchRoute-nTNPxoMq.mjs";
|
|
2
|
+
import { AbortRedirect, AbortRender } from "./server/abort.mjs";
|
|
3
|
+
import { n as store } from "./store-DPJQje-K.mjs";
|
|
4
|
+
//#region src/utils/serializeContext.ts
|
|
5
|
+
const ESCAPE_LOOKUP = {
|
|
6
|
+
"&": String.raw`\u0026`,
|
|
7
|
+
">": String.raw`\u003e`,
|
|
8
|
+
"<": String.raw`\u003c`,
|
|
9
|
+
"\u2028": String.raw`\u2028`,
|
|
10
|
+
"\u2029": String.raw`\u2029`
|
|
11
|
+
};
|
|
12
|
+
const ESCAPE_REGEX = /[&><\u{2028}\u{2029}]/gu;
|
|
13
|
+
function serializeContext(data) {
|
|
14
|
+
return JSON.stringify(data).replaceAll(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]);
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/server/renderPage.ts
|
|
18
|
+
const isProd = process.env.NODE_ENV === "production";
|
|
19
|
+
function withBase(file) {
|
|
20
|
+
const { BASE_URL } = import.meta.env;
|
|
21
|
+
return `${BASE_URL === "/" ? "" : BASE_URL.endsWith("/") ? BASE_URL.slice(0, -1) : BASE_URL}${file.startsWith("/") ? file : `/${file}`}`;
|
|
22
|
+
}
|
|
23
|
+
const assetsCache = /* @__PURE__ */ new WeakMap();
|
|
24
|
+
function getAssets(route, nonce) {
|
|
25
|
+
if (!isProd) return computeAssets(route, nonce);
|
|
26
|
+
const nonceKey = nonce || "";
|
|
27
|
+
let routeCache = assetsCache.get(route);
|
|
28
|
+
if (!routeCache) {
|
|
29
|
+
routeCache = /* @__PURE__ */ new Map();
|
|
30
|
+
assetsCache.set(route, routeCache);
|
|
31
|
+
}
|
|
32
|
+
let assets = routeCache.get(nonceKey);
|
|
33
|
+
if (!assets) {
|
|
34
|
+
assets = computeAssets(route, nonce);
|
|
35
|
+
routeCache.set(nonceKey, assets);
|
|
36
|
+
}
|
|
37
|
+
return assets;
|
|
38
|
+
}
|
|
39
|
+
function computeAssets(route, nonce) {
|
|
40
|
+
if (!isProd) return {
|
|
41
|
+
cssLinks: "",
|
|
42
|
+
jsPreloads: "",
|
|
43
|
+
entryClient: withBase("@id/virtual:entry-client")
|
|
44
|
+
};
|
|
45
|
+
const cssFiles = /* @__PURE__ */ new Set();
|
|
46
|
+
const jsFiles = /* @__PURE__ */ new Map();
|
|
47
|
+
const { manifest } = store;
|
|
48
|
+
function getVirtualEntryClientKey() {
|
|
49
|
+
for (const key in manifest) if (manifest[key].isEntry) return key;
|
|
50
|
+
throw new Error("entry-client not found in manifest");
|
|
51
|
+
}
|
|
52
|
+
function collectAssets(key, isCritical) {
|
|
53
|
+
const chunk = manifest[key];
|
|
54
|
+
if (!chunk) return;
|
|
55
|
+
const current = jsFiles.get(chunk.file);
|
|
56
|
+
if (current === true) return;
|
|
57
|
+
if (current === false && !isCritical) return;
|
|
58
|
+
jsFiles.set(chunk.file, isCritical);
|
|
59
|
+
if (chunk.css) for (const css of chunk.css) cssFiles.add(css);
|
|
60
|
+
if (chunk.imports) for (const imp of chunk.imports) collectAssets(imp, false);
|
|
61
|
+
}
|
|
62
|
+
const virtualEntryClientKey = getVirtualEntryClientKey();
|
|
63
|
+
collectAssets(virtualEntryClientKey, true);
|
|
64
|
+
const { page, layout, head } = route;
|
|
65
|
+
collectAssets(page, true);
|
|
66
|
+
if (head) collectAssets(head, true);
|
|
67
|
+
if (layout) collectAssets(layout, true);
|
|
68
|
+
const criticalJs = [];
|
|
69
|
+
const sharedJs = [];
|
|
70
|
+
for (const [file, isCritical] of jsFiles) (isCritical ? criticalJs : sharedJs).push(file);
|
|
71
|
+
const nonceAttr = nonce ? ` nonce="${nonce}"` : "";
|
|
72
|
+
return {
|
|
73
|
+
cssLinks: [...cssFiles].map((href) => `<link rel="stylesheet" href="${withBase(href)}"${nonceAttr}>`).join(""),
|
|
74
|
+
jsPreloads: [...criticalJs.map((href) => `<link rel="modulepreload" href="${withBase(href)}" crossorigin fetchpriority="high"${nonceAttr}>`), ...sharedJs.map((href) => `<link rel="modulepreload" href="${withBase(href)}" crossorigin${nonceAttr}>`)].join(""),
|
|
75
|
+
entryClient: withBase(manifest[virtualEntryClientKey].file)
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
async function buildPageContext(urlPathname, urlOriginal, isJsonRequest) {
|
|
79
|
+
const matched = matchRoute(urlPathname, store.routes);
|
|
80
|
+
if (!matched) return null;
|
|
81
|
+
const { route, routeParams } = matched;
|
|
82
|
+
const pageContext = {
|
|
83
|
+
routeParams,
|
|
84
|
+
urlOriginal,
|
|
85
|
+
urlPathname
|
|
86
|
+
};
|
|
87
|
+
const [dataMod, titleMod, PageModule, HeadModule, LayoutModule] = await Promise.all([
|
|
88
|
+
route.Data?.() ?? null,
|
|
89
|
+
route.Title?.() ?? null,
|
|
90
|
+
isJsonRequest ? null : route.Page(),
|
|
91
|
+
isJsonRequest ? null : route.Head?.() ?? null,
|
|
92
|
+
isJsonRequest ? null : route.Layout?.() ?? null
|
|
93
|
+
]);
|
|
94
|
+
if (dataMod) try {
|
|
95
|
+
pageContext.data = await (dataMod.data ?? dataMod.default)(pageContext);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.error("+data hook failed at:", urlPathname);
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
if (titleMod) try {
|
|
101
|
+
const titleFn = titleMod.title ?? titleMod.default;
|
|
102
|
+
pageContext.title = typeof titleFn === "function" ? titleFn(pageContext) : titleFn;
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error("+title hook failed at:", urlPathname);
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
pageContext,
|
|
109
|
+
route,
|
|
110
|
+
PageModule,
|
|
111
|
+
HeadModule,
|
|
112
|
+
LayoutModule
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
async function renderErrorPage(req, status, urlPathname, error, nonce) {
|
|
116
|
+
let errorMessage;
|
|
117
|
+
let is500;
|
|
118
|
+
if (status === 500) {
|
|
119
|
+
console.error(`[vike-lite] Server Error:`, error);
|
|
120
|
+
errorMessage = isProd ? "Internal Server Error" : error instanceof Error ? error.message : "Unknown error";
|
|
121
|
+
is500 = true;
|
|
122
|
+
} else is500 = false;
|
|
123
|
+
if (!store.errorRoute) return new Response(status === 404 ? "Not Found" : "Internal Server Error", { status });
|
|
124
|
+
try {
|
|
125
|
+
const { default: onRenderHtml } = await store.config.onRenderHtml();
|
|
126
|
+
const [PageModule, HeadModule, LayoutModule] = await Promise.all([
|
|
127
|
+
store.errorRoute.Page(),
|
|
128
|
+
store.errorRoute.Head?.() ?? null,
|
|
129
|
+
store.errorRoute.Layout?.() ?? null
|
|
130
|
+
]);
|
|
131
|
+
const pageContext = {
|
|
132
|
+
urlOriginal: req.url,
|
|
133
|
+
urlPathname,
|
|
134
|
+
routeParams: {},
|
|
135
|
+
is404: status === 404,
|
|
136
|
+
is500,
|
|
137
|
+
errorMessage
|
|
138
|
+
};
|
|
139
|
+
const html = await onRenderHtml({
|
|
140
|
+
pageContext,
|
|
141
|
+
Page: PageModule.Page ?? PageModule.default,
|
|
142
|
+
Layout: LayoutModule ? LayoutModule.Layout ?? LayoutModule.default : void 0,
|
|
143
|
+
Head: HeadModule ? HeadModule.Head ?? HeadModule.default : void 0,
|
|
144
|
+
pageTitleTag: `<title>${status === 404 ? "Page Not Found" : "Server Error"}</title>`,
|
|
145
|
+
serializedContext: serializeContext(pageContext),
|
|
146
|
+
assets: getAssets(store.errorRoute, nonce),
|
|
147
|
+
nonce
|
|
148
|
+
});
|
|
149
|
+
return new Response(html, {
|
|
150
|
+
status,
|
|
151
|
+
headers: { "Content-Type": "text/html" }
|
|
152
|
+
});
|
|
153
|
+
} catch (renderError) {
|
|
154
|
+
console.error("[vike-lite] Error page render failed:", renderError);
|
|
155
|
+
return new Response(status === 404 ? "Not Found" : "Internal Server Error", { status });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async function renderPage(req, { nonce } = {}) {
|
|
159
|
+
let { pathname } = new URL(req.url);
|
|
160
|
+
const { BASE_URL } = import.meta.env;
|
|
161
|
+
if (BASE_URL !== "/") {
|
|
162
|
+
const baseSlashed = BASE_URL.endsWith("/") ? BASE_URL : BASE_URL + "/";
|
|
163
|
+
const baseNoSlash = baseSlashed.slice(0, -1);
|
|
164
|
+
pathname = pathname === baseNoSlash ? "/" : pathname.slice(baseSlashed.length - 1);
|
|
165
|
+
}
|
|
166
|
+
const isJsonRequest = pathname.endsWith(".pageContext.json");
|
|
167
|
+
let targetPathname = pathname;
|
|
168
|
+
if (isJsonRequest) {
|
|
169
|
+
targetPathname = targetPathname.replace(/\.pageContext\.json$/, "");
|
|
170
|
+
if (targetPathname === "/index") targetPathname = "/";
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
const resolved = await buildPageContext(targetPathname, req.url, isJsonRequest);
|
|
174
|
+
if (!resolved) {
|
|
175
|
+
if (isJsonRequest) return Response.json({ is404: true }, { status: 404 });
|
|
176
|
+
return renderErrorPage(req, 404, targetPathname, nonce);
|
|
177
|
+
}
|
|
178
|
+
const { pageContext, route, PageModule, HeadModule, LayoutModule } = resolved;
|
|
179
|
+
if (isJsonRequest) return Response.json(pageContext);
|
|
180
|
+
const { default: onRenderHtml } = await store.config.onRenderHtml();
|
|
181
|
+
const html = await onRenderHtml({
|
|
182
|
+
pageContext,
|
|
183
|
+
Page: PageModule.Page ?? PageModule.default,
|
|
184
|
+
Head: HeadModule ? HeadModule.Head ?? HeadModule.default : void 0,
|
|
185
|
+
Layout: LayoutModule ? LayoutModule.Layout ?? LayoutModule.default : void 0,
|
|
186
|
+
pageTitleTag: pageContext.title ? `<title>${pageContext.title}</title>` : "",
|
|
187
|
+
serializedContext: serializeContext(pageContext),
|
|
188
|
+
assets: getAssets(route, nonce),
|
|
189
|
+
nonce
|
|
190
|
+
});
|
|
191
|
+
return new Response(html, {
|
|
192
|
+
status: 200,
|
|
193
|
+
headers: { "Content-Type": "text/html" }
|
|
194
|
+
});
|
|
195
|
+
} catch (error) {
|
|
196
|
+
if (error instanceof AbortRedirect) {
|
|
197
|
+
let redirectUrl = error.url;
|
|
198
|
+
if (redirectUrl.startsWith("/")) redirectUrl = (BASE_URL.endsWith("/") ? BASE_URL.slice(0, -1) : BASE_URL) + (redirectUrl === "/" ? "" : redirectUrl);
|
|
199
|
+
if (isJsonRequest) return Response.json({ _redirect: redirectUrl }, { status: 200 });
|
|
200
|
+
return new Response(null, {
|
|
201
|
+
status: error.statusCode,
|
|
202
|
+
headers: { Location: redirectUrl }
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
if (error instanceof AbortRender) {
|
|
206
|
+
if (isJsonRequest) return Response.json({
|
|
207
|
+
is404: error.statusCode === 404,
|
|
208
|
+
is500: error.statusCode >= 500,
|
|
209
|
+
isError: true,
|
|
210
|
+
reason: error.reason
|
|
211
|
+
}, { status: error.statusCode });
|
|
212
|
+
return renderErrorPage(req, error.statusCode, targetPathname, error.reason, nonce);
|
|
213
|
+
}
|
|
214
|
+
console.error("Render Error:", error);
|
|
215
|
+
if (isJsonRequest) return Response.json({ is500: true }, { status: 500 });
|
|
216
|
+
return renderErrorPage(req, 500, targetPathname, error, nonce);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
//#endregion
|
|
220
|
+
export { renderPage as t };
|
package/dist/server.d.mts
CHANGED
package/dist/server.mjs
CHANGED
|
@@ -1,196 +1,2 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
import { t as matchRoute } from "./matchRoute-nTNPxoMq.mjs";
|
|
3
|
-
import { AbortRedirect, AbortRender } from "./server/abort.mjs";
|
|
4
|
-
import { n as store } from "./store-CfUB1COP.mjs";
|
|
5
|
-
//#region src/utils/serializeContext.ts
|
|
6
|
-
const ESCAPE_LOOKUP = {
|
|
7
|
-
"&": String.raw`\u0026`,
|
|
8
|
-
">": String.raw`\u003e`,
|
|
9
|
-
"<": String.raw`\u003c`,
|
|
10
|
-
"\u2028": String.raw`\u2028`,
|
|
11
|
-
"\u2029": String.raw`\u2029`
|
|
12
|
-
};
|
|
13
|
-
const ESCAPE_REGEX = /[&><\u{2028}\u{2029}]/gu;
|
|
14
|
-
function serializeContext(data) {
|
|
15
|
-
return JSON.stringify(data).replaceAll(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]);
|
|
16
|
-
}
|
|
17
|
-
//#endregion
|
|
18
|
-
//#region src/server/renderPage.ts
|
|
19
|
-
const isProd = process.env.NODE_ENV === "production";
|
|
20
|
-
function withBase(file) {
|
|
21
|
-
return `${BASE_URL.replace(/\/$/, "")}/${file.replace(/^\//, "")}`;
|
|
22
|
-
}
|
|
23
|
-
function getAssets(route, nonce) {
|
|
24
|
-
if (!isProd) return {
|
|
25
|
-
cssLinks: "",
|
|
26
|
-
jsPreloads: "",
|
|
27
|
-
entryClient: withBase("@id/virtual:entry-client")
|
|
28
|
-
};
|
|
29
|
-
const cssFiles = /* @__PURE__ */ new Set();
|
|
30
|
-
const jsFiles = /* @__PURE__ */ new Map();
|
|
31
|
-
const { manifest } = store;
|
|
32
|
-
function getVirtualEntryClientKey() {
|
|
33
|
-
for (const key in manifest) if (manifest[key].isEntry) return key;
|
|
34
|
-
throw new Error("entry-client not found in manifest");
|
|
35
|
-
}
|
|
36
|
-
function collectAssets(key, isCritical) {
|
|
37
|
-
const chunk = manifest[key];
|
|
38
|
-
if (!chunk) return;
|
|
39
|
-
const current = jsFiles.get(chunk.file);
|
|
40
|
-
if (current === true) return;
|
|
41
|
-
if (current === false && !isCritical) return;
|
|
42
|
-
jsFiles.set(chunk.file, isCritical);
|
|
43
|
-
if (chunk.css) for (const css of chunk.css) cssFiles.add(css);
|
|
44
|
-
if (chunk.imports) for (const imp of chunk.imports) collectAssets(imp, false);
|
|
45
|
-
}
|
|
46
|
-
const virtualEntryClientKey = getVirtualEntryClientKey();
|
|
47
|
-
collectAssets(virtualEntryClientKey, true);
|
|
48
|
-
const { page, layout, head } = route;
|
|
49
|
-
collectAssets(page, true);
|
|
50
|
-
if (head) collectAssets(head, true);
|
|
51
|
-
if (layout) collectAssets(layout, true);
|
|
52
|
-
const criticalJs = [];
|
|
53
|
-
const sharedJs = [];
|
|
54
|
-
for (const [file, isCritical] of jsFiles) (isCritical ? criticalJs : sharedJs).push(file);
|
|
55
|
-
const nonceAttr = nonce ? ` nonce="${nonce}"` : "";
|
|
56
|
-
return {
|
|
57
|
-
cssLinks: [...cssFiles].map((href) => `<link rel="stylesheet" href="${withBase(href)}"${nonceAttr}>`).join(""),
|
|
58
|
-
jsPreloads: [...criticalJs.map((href) => `<link rel="modulepreload" href="${withBase(href)}" crossorigin fetchpriority="high"${nonceAttr}>`), ...sharedJs.map((href) => `<link rel="modulepreload" href="${withBase(href)}" crossorigin${nonceAttr}>`)].join(""),
|
|
59
|
-
entryClient: withBase(manifest[virtualEntryClientKey].file)
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
async function buildPageContext(urlPathname, urlOriginal, isJsonRequest) {
|
|
63
|
-
const matched = matchRoute(urlPathname, store.routes);
|
|
64
|
-
if (!matched) return null;
|
|
65
|
-
const { route, routeParams } = matched;
|
|
66
|
-
const pageContext = {
|
|
67
|
-
routeParams,
|
|
68
|
-
urlOriginal,
|
|
69
|
-
urlPathname
|
|
70
|
-
};
|
|
71
|
-
const [dataMod, titleMod, PageModule, HeadModule, LayoutModule] = await Promise.all([
|
|
72
|
-
route.Data?.() ?? null,
|
|
73
|
-
route.Title?.() ?? null,
|
|
74
|
-
isJsonRequest ? null : route.Page(),
|
|
75
|
-
isJsonRequest ? null : route.Head?.() ?? null,
|
|
76
|
-
isJsonRequest ? null : route.Layout?.() ?? null
|
|
77
|
-
]);
|
|
78
|
-
if (dataMod) try {
|
|
79
|
-
pageContext.data = await (dataMod.data ?? dataMod.default)(pageContext);
|
|
80
|
-
} catch (error) {
|
|
81
|
-
console.error("+data hook failed at:", urlPathname);
|
|
82
|
-
throw error;
|
|
83
|
-
}
|
|
84
|
-
if (titleMod) try {
|
|
85
|
-
const titleFn = titleMod.title ?? titleMod.default;
|
|
86
|
-
pageContext.title = typeof titleFn === "function" ? titleFn(pageContext) : titleFn;
|
|
87
|
-
} catch (error) {
|
|
88
|
-
console.error("+title hook failed at:", urlPathname);
|
|
89
|
-
throw error;
|
|
90
|
-
}
|
|
91
|
-
return {
|
|
92
|
-
pageContext,
|
|
93
|
-
route,
|
|
94
|
-
PageModule,
|
|
95
|
-
HeadModule,
|
|
96
|
-
LayoutModule
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
async function renderErrorPage(req, status, urlPathname, error, nonce) {
|
|
100
|
-
if (!store.errorRoute) return new Response(status === 404 ? "Not Found" : "Internal Server Error", { status });
|
|
101
|
-
try {
|
|
102
|
-
const { default: onRenderHtml } = await store.config.onRenderHtml();
|
|
103
|
-
const [PageModule, HeadModule, LayoutModule] = await Promise.all([
|
|
104
|
-
store.errorRoute.Page(),
|
|
105
|
-
store.errorRoute.Head?.() ?? null,
|
|
106
|
-
store.errorRoute.Layout?.() ?? null
|
|
107
|
-
]);
|
|
108
|
-
const pageContext = {
|
|
109
|
-
urlOriginal: req.url,
|
|
110
|
-
urlPathname,
|
|
111
|
-
routeParams: {},
|
|
112
|
-
is404: status === 404,
|
|
113
|
-
is500: status === 500,
|
|
114
|
-
errorMessage: status === 500 && error instanceof Error ? error.message : void 0
|
|
115
|
-
};
|
|
116
|
-
const html = await onRenderHtml({
|
|
117
|
-
pageContext,
|
|
118
|
-
Page: PageModule.Page ?? PageModule.default,
|
|
119
|
-
Layout: LayoutModule ? LayoutModule.Layout ?? LayoutModule.default : void 0,
|
|
120
|
-
Head: HeadModule ? HeadModule.Head ?? HeadModule.default : void 0,
|
|
121
|
-
pageTitleTag: `<title>${status === 404 ? "Page Not Found" : "Server Error"}</title>`,
|
|
122
|
-
serializedContext: serializeContext(pageContext),
|
|
123
|
-
assets: getAssets(store.errorRoute, nonce),
|
|
124
|
-
nonce
|
|
125
|
-
});
|
|
126
|
-
return new Response(html, {
|
|
127
|
-
status,
|
|
128
|
-
headers: { "Content-Type": "text/html" }
|
|
129
|
-
});
|
|
130
|
-
} catch (renderError) {
|
|
131
|
-
console.error("Error page render failed:", renderError);
|
|
132
|
-
return new Response(status === 404 ? "Not Found" : "Internal Server Error", { status });
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
async function renderPage(req, { nonce } = {}) {
|
|
136
|
-
let { pathname } = new URL(req.url);
|
|
137
|
-
if (BASE_URL !== "/") {
|
|
138
|
-
const baseSlashed = BASE_URL.endsWith("/") ? BASE_URL : BASE_URL + "/";
|
|
139
|
-
const baseNoSlash = baseSlashed.slice(0, -1);
|
|
140
|
-
pathname = pathname === baseNoSlash ? "/" : pathname.slice(baseSlashed.length - 1);
|
|
141
|
-
}
|
|
142
|
-
const isJsonRequest = pathname.endsWith(".pageContext.json");
|
|
143
|
-
let targetPathname = pathname;
|
|
144
|
-
if (isJsonRequest) {
|
|
145
|
-
targetPathname = targetPathname.replace(/\.pageContext\.json$/, "");
|
|
146
|
-
if (targetPathname === "/index") targetPathname = "/";
|
|
147
|
-
}
|
|
148
|
-
try {
|
|
149
|
-
const resolved = await buildPageContext(targetPathname, req.url, isJsonRequest);
|
|
150
|
-
if (!resolved) {
|
|
151
|
-
if (isJsonRequest) return Response.json({ is404: true }, { status: 404 });
|
|
152
|
-
return renderErrorPage(req, 404, targetPathname, nonce);
|
|
153
|
-
}
|
|
154
|
-
const { pageContext, route, PageModule, HeadModule, LayoutModule } = resolved;
|
|
155
|
-
if (isJsonRequest) return Response.json(pageContext);
|
|
156
|
-
const { default: onRenderHtml } = await store.config.onRenderHtml();
|
|
157
|
-
const html = await onRenderHtml({
|
|
158
|
-
pageContext,
|
|
159
|
-
Page: PageModule.Page ?? PageModule.default,
|
|
160
|
-
Head: HeadModule ? HeadModule.Head ?? HeadModule.default : void 0,
|
|
161
|
-
Layout: LayoutModule ? LayoutModule.Layout ?? LayoutModule.default : void 0,
|
|
162
|
-
pageTitleTag: pageContext.title ? `<title>${pageContext.title}</title>` : "",
|
|
163
|
-
serializedContext: serializeContext(pageContext),
|
|
164
|
-
assets: getAssets(route, nonce),
|
|
165
|
-
nonce
|
|
166
|
-
});
|
|
167
|
-
return new Response(html, {
|
|
168
|
-
status: 200,
|
|
169
|
-
headers: { "Content-Type": "text/html" }
|
|
170
|
-
});
|
|
171
|
-
} catch (error) {
|
|
172
|
-
if (error instanceof AbortRedirect) {
|
|
173
|
-
let redirectUrl = error.url;
|
|
174
|
-
if (redirectUrl.startsWith("/")) redirectUrl = (BASE_URL.endsWith("/") ? BASE_URL.slice(0, -1) : BASE_URL) + (redirectUrl === "/" ? "" : redirectUrl);
|
|
175
|
-
if (isJsonRequest) return Response.json({ _redirect: redirectUrl }, { status: 200 });
|
|
176
|
-
return new Response(null, {
|
|
177
|
-
status: error.statusCode,
|
|
178
|
-
headers: { Location: redirectUrl }
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
if (error instanceof AbortRender) {
|
|
182
|
-
if (isJsonRequest) return Response.json({
|
|
183
|
-
is404: error.statusCode === 404,
|
|
184
|
-
is500: error.statusCode >= 500,
|
|
185
|
-
isError: true,
|
|
186
|
-
reason: error.reason
|
|
187
|
-
}, { status: error.statusCode });
|
|
188
|
-
return renderErrorPage(req, error.statusCode, targetPathname, error.reason, nonce);
|
|
189
|
-
}
|
|
190
|
-
console.error("Render Error:", error);
|
|
191
|
-
if (isJsonRequest) return Response.json({ is500: true }, { status: 500 });
|
|
192
|
-
return renderErrorPage(req, 500, targetPathname, error, nonce);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
//#endregion
|
|
1
|
+
import { t as renderPage } from "./server-Cm1ZA_Dp.mjs";
|
|
196
2
|
export { renderPage };
|
package/dist/vite.d.mts
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import { Plugin } from "vite";
|
|
2
|
-
|
|
3
2
|
//#region src/vite-plugin.d.ts
|
|
4
|
-
declare function routerPlugin({
|
|
5
|
-
pagesDir,
|
|
6
|
-
serverEntry,
|
|
7
|
-
apiPrefix,
|
|
8
|
-
prerender
|
|
9
|
-
}?: {
|
|
3
|
+
declare function routerPlugin({ pagesDir, serverEntry, apiPrefix, prerender }?: {
|
|
10
4
|
/**
|
|
11
5
|
* The directory where your page components are located.
|
|
12
6
|
* This is where the plugin will look for your page files to generate routes.
|
|
@@ -26,7 +20,8 @@ declare function routerPlugin({
|
|
|
26
20
|
*/
|
|
27
21
|
apiPrefix?: string;
|
|
28
22
|
/**
|
|
29
|
-
* Whether to prerender the pages.
|
|
23
|
+
* Whether to prerender the pages by default.
|
|
24
|
+
* Individual pages can override this via +prerender.ts.
|
|
30
25
|
* @default false
|
|
31
26
|
*/
|
|
32
27
|
prerender?: boolean;
|
package/dist/vite.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as renderPage } from "./server-Cm1ZA_Dp.mjs";
|
|
1
2
|
import fs from "node:fs";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { Readable } from "node:stream";
|
|
@@ -102,17 +103,18 @@ function routerPlugin({ pagesDir = "pages", serverEntry = "server/index", apiPre
|
|
|
102
103
|
const isProd = process.env.NODE_ENV === "production";
|
|
103
104
|
let viteConfigRoot;
|
|
104
105
|
let outDir;
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const
|
|
106
|
+
let hasAnyPrerender;
|
|
107
|
+
const VIRTUAL = {
|
|
108
|
+
routes: "virtual:routes",
|
|
109
|
+
manifest: "virtual:client-manifest",
|
|
110
|
+
renderer: "virtual:vike-lite/renderer",
|
|
111
|
+
entryClient: "virtual:entry-client",
|
|
112
|
+
setup: "virtual:vike-lite/setup",
|
|
113
|
+
entryServer: "virtual:entry-server",
|
|
114
|
+
entryPrerender: "virtual:entry-prerender"
|
|
115
|
+
};
|
|
116
|
+
const VIRTUAL_VALUES = new Set(Object.values(VIRTUAL));
|
|
117
|
+
const RESOLVED = Object.fromEntries(Object.entries(VIRTUAL).map(([k, v]) => [k, `\0${v}`]));
|
|
116
118
|
return {
|
|
117
119
|
name: "vike-lite",
|
|
118
120
|
config(config, { mode }) {
|
|
@@ -120,6 +122,9 @@ function routerPlugin({ pagesDir = "pages", serverEntry = "server/index", apiPre
|
|
|
120
122
|
for (const key in envVariables) if (process.env[key] === void 0) process.env[key] = envVariables[key];
|
|
121
123
|
outDir = config.build?.outDir ?? "dist";
|
|
122
124
|
const { emptyOutDir, minify = true, cssMinify = true, sourcemap } = config.build || {};
|
|
125
|
+
viteConfigRoot = config.root ? path.resolve(config.root) : process.cwd();
|
|
126
|
+
const { routes } = generateRoutes(viteConfigRoot, pagesDir);
|
|
127
|
+
hasAnyPrerender = prerender || routes.some((r) => r.prerender);
|
|
123
128
|
return {
|
|
124
129
|
appType: "custom",
|
|
125
130
|
ssr: { noExternal: [/^vike-lite(?:$|-)/] },
|
|
@@ -132,7 +137,7 @@ function routerPlugin({ pagesDir = "pages", serverEntry = "server/index", apiPre
|
|
|
132
137
|
sourcemap,
|
|
133
138
|
manifest: true,
|
|
134
139
|
rolldownOptions: {
|
|
135
|
-
input:
|
|
140
|
+
input: VIRTUAL.entryClient,
|
|
136
141
|
output: {
|
|
137
142
|
format: "esm",
|
|
138
143
|
hoistTransitiveImports: false,
|
|
@@ -184,7 +189,10 @@ function routerPlugin({ pagesDir = "pages", serverEntry = "server/index", apiPre
|
|
|
184
189
|
minify,
|
|
185
190
|
sourcemap,
|
|
186
191
|
rolldownOptions: {
|
|
187
|
-
input:
|
|
192
|
+
input: hasAnyPrerender ? {
|
|
193
|
+
index: VIRTUAL.entryServer,
|
|
194
|
+
prerender: VIRTUAL.entryPrerender
|
|
195
|
+
} : VIRTUAL.entryServer,
|
|
188
196
|
output: {
|
|
189
197
|
format: "esm",
|
|
190
198
|
entryFileNames: "index.mjs",
|
|
@@ -199,21 +207,16 @@ function routerPlugin({ pagesDir = "pages", serverEntry = "server/index", apiPre
|
|
|
199
207
|
};
|
|
200
208
|
},
|
|
201
209
|
configResolved(config) {
|
|
202
|
-
viteConfigRoot = config.root;
|
|
203
210
|
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(", ")}`);
|
|
204
211
|
},
|
|
205
212
|
resolveId(id) {
|
|
206
|
-
if (id
|
|
207
|
-
if (id === virtualManifestId) return resolvedVirtualManifestId;
|
|
208
|
-
if (id === virtualEntryClientId) return resolvedVirtualEntryClientId;
|
|
209
|
-
if (id === virtualSetupId) return resolvedVirtualSetupId;
|
|
210
|
-
if (id === virtualEntryServerId) return resolvedVirtualEntryServerId;
|
|
213
|
+
if (VIRTUAL_VALUES.has(id)) return "\0" + id;
|
|
211
214
|
},
|
|
212
215
|
async load(id, options) {
|
|
213
|
-
if (id ===
|
|
216
|
+
if (id === RESOLVED.routes) {
|
|
214
217
|
const { routes, errorRoute } = generateRoutes(viteConfigRoot, pagesDir);
|
|
215
218
|
const isSSR = options.ssr;
|
|
216
|
-
let code = `import { onRenderHtml } from '${
|
|
219
|
+
let code = `import { onRenderHtml } from '${VIRTUAL.renderer}';\nexport const config = { onRenderHtml };\nexport const routes = [\n`;
|
|
217
220
|
for (const r of routes) {
|
|
218
221
|
code += `{path:'${r.path}',page:'${r.page}',Page:()=>import('/${r.page}'),`;
|
|
219
222
|
if (r.head) code += `head:'${r.head}',Head:()=>import('/${r.head}'),`;
|
|
@@ -238,44 +241,30 @@ function routerPlugin({ pagesDir = "pages", serverEntry = "server/index", apiPre
|
|
|
238
241
|
} else code += "export const errorRoute=null;\n";
|
|
239
242
|
return code;
|
|
240
243
|
}
|
|
241
|
-
if (id ===
|
|
244
|
+
if (id === RESOLVED.manifest) {
|
|
242
245
|
if (!isProd || !options?.ssr) return "export default {}";
|
|
243
246
|
const manifestPath = path.join(viteConfigRoot, outDir, "client/.vite/manifest.json");
|
|
244
247
|
return `export default ${fs.readFileSync(manifestPath, "utf8")}`;
|
|
245
248
|
}
|
|
246
|
-
if (id ===
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
await render({ routes, errorRoute });`;
|
|
250
|
-
if (id === resolvedVirtualSetupId) return `import { routes, errorRoute, config } from '${virtualModuleId}';
|
|
251
|
-
import { setVikeState } from 'vike-lite/__internal/server';
|
|
252
|
-
let manifest;
|
|
253
|
-
if (process.env.NODE_ENV === 'production') {
|
|
254
|
-
manifest = (await import('${virtualManifestId}')).default;
|
|
255
|
-
}
|
|
256
|
-
setVikeState({ routes, errorRoute, config, manifest });`;
|
|
257
|
-
if (id === resolvedVirtualEntryServerId) {
|
|
258
|
-
let hasCustomServer = false;
|
|
259
|
-
let customServerPath = "";
|
|
249
|
+
if (id === RESOLVED.entryClient) return `import{routes,errorRoute}from'${VIRTUAL.routes}';import{onRenderClient}from'${VIRTUAL.renderer}';const{default:render}=await onRenderClient();await render({routes,errorRoute});`;
|
|
250
|
+
if (id === RESOLVED.setup) return `import{routes,errorRoute,config}from'${VIRTUAL.routes}';import{setVikeState}from'vike-lite/__internal/server';const manifest=process.env.NODE_ENV==='production'?(await import('${VIRTUAL.manifest}')).default:null;setVikeState({routes,errorRoute,config,manifest});`;
|
|
251
|
+
if (id === RESOLVED.entryServer) {
|
|
260
252
|
if (serverEntry) {
|
|
261
253
|
const basePath = path.resolve(viteConfigRoot, serverEntry);
|
|
254
|
+
let serverEntryPath = "";
|
|
262
255
|
for (const ext of [
|
|
263
256
|
".ts",
|
|
264
257
|
".js",
|
|
265
258
|
".mjs"
|
|
266
259
|
]) if (fs.existsSync(basePath + ext)) {
|
|
267
|
-
|
|
268
|
-
customServerPath = (basePath + ext).replaceAll("\\", "/");
|
|
260
|
+
serverEntryPath = (basePath + ext).replaceAll("\\", "/");
|
|
269
261
|
break;
|
|
270
262
|
}
|
|
263
|
+
if (!serverEntryPath) throw new Error(`[vike-lite] serverEntry ${serverEntry} file not found!`);
|
|
264
|
+
return `import '${VIRTUAL.setup}';export * from'${serverEntryPath}';export{default}from'${serverEntryPath}';`;
|
|
271
265
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
export default {
|
|
275
|
-
async fetch(request) {
|
|
276
|
-
return renderPage(request);
|
|
277
|
-
}
|
|
278
|
-
};
|
|
266
|
+
return `import '${VIRTUAL.setup}';import{renderPage}from'vike-lite/server';
|
|
267
|
+
export default{async fetch(request){return renderPage(request);}};
|
|
279
268
|
if (process.env.NODE_ENV === 'production') {
|
|
280
269
|
const { createServer } = await import('node:http');
|
|
281
270
|
const { Readable } = await import('node:stream');
|
|
@@ -291,18 +280,27 @@ if (process.env.NODE_ENV === 'production') {
|
|
|
291
280
|
'.mjs': 'text/javascript; charset=utf-8',
|
|
292
281
|
'.css': 'text/css; charset=utf-8',
|
|
293
282
|
'.json': 'application/json; charset=utf-8',
|
|
283
|
+
'.xml': 'application/xml',
|
|
284
|
+
'.txt': 'text/plain; charset=utf-8',
|
|
285
|
+
'.map': 'application/json; charset=utf-8',
|
|
294
286
|
'.png': 'image/png',
|
|
295
287
|
'.jpg': 'image/jpeg',
|
|
296
288
|
'.jpeg': 'image/jpeg',
|
|
297
289
|
'.gif': 'image/gif',
|
|
298
290
|
'.svg': 'image/svg+xml',
|
|
299
291
|
'.ico': 'image/x-icon',
|
|
300
|
-
'.
|
|
301
|
-
'.
|
|
302
|
-
'.txt': 'text/plain; charset=utf-8',
|
|
292
|
+
'.webp': 'image/webp',
|
|
293
|
+
'.avif': 'image/avif',
|
|
303
294
|
'.woff': 'font/woff',
|
|
304
295
|
'.woff2': 'font/woff2',
|
|
305
|
-
'.
|
|
296
|
+
'.ttf': 'font/ttf',
|
|
297
|
+
'.otf': 'font/otf',
|
|
298
|
+
'.mp4': 'video/mp4',
|
|
299
|
+
'.webm': 'video/webm',
|
|
300
|
+
'.mp3': 'audio/mpeg',
|
|
301
|
+
'.pdf': 'application/pdf',
|
|
302
|
+
'.wasm': 'application/wasm',
|
|
303
|
+
'.webmanifest': 'application/manifest+json'
|
|
306
304
|
};
|
|
307
305
|
const { BASE_URL } = import.meta.env;
|
|
308
306
|
const server = createServer(async (req, res) => {
|
|
@@ -334,22 +332,13 @@ if (process.env.NODE_ENV === 'production') {
|
|
|
334
332
|
}
|
|
335
333
|
const { method } = req;
|
|
336
334
|
const init = { method, headers };
|
|
337
|
-
if (
|
|
338
|
-
res.end()
|
|
339
|
-
return
|
|
340
|
-
}
|
|
341
|
-
if (method !== 'GET' && method !== 'HEAD') {
|
|
342
|
-
init.body = Readable.toWeb(req);
|
|
343
|
-
init.duplex = 'half';
|
|
344
|
-
}
|
|
335
|
+
if (method !== 'GET' && method !== 'HEAD') { init.body = Readable.toWeb(req); init.duplex = 'half'; }
|
|
345
336
|
const request = new Request(urlObj.href, init);
|
|
346
337
|
const response = await renderPage(request);
|
|
347
338
|
res.statusCode = response.status;
|
|
348
|
-
for (const [key, val] of response.headers)
|
|
349
|
-
|
|
350
|
-
}
|
|
351
|
-
if (response.body) await pipeline(Readable.fromWeb(response.body), res);
|
|
352
|
-
else res.end();
|
|
339
|
+
for (const [key, val] of response.headers) res.setHeader(key, val);
|
|
340
|
+
if (method === 'HEAD' || !response.body) { await response.body?.cancel(); res.end(); return; }
|
|
341
|
+
try { await pipeline(Readable.fromWeb(response.body), res); } catch {}
|
|
353
342
|
} catch (e) {
|
|
354
343
|
console.error(e);
|
|
355
344
|
res.statusCode = 500;
|
|
@@ -363,19 +352,18 @@ if (process.env.NODE_ENV === 'production') {
|
|
|
363
352
|
});
|
|
364
353
|
}`;
|
|
365
354
|
}
|
|
355
|
+
if (id === RESOLVED.entryPrerender) return `import'${VIRTUAL.setup}';export{routes}from'${VIRTUAL.routes}';`;
|
|
366
356
|
},
|
|
367
357
|
async closeBundle() {
|
|
368
|
-
if (!
|
|
369
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
358
|
+
if (!isProd || this.environment.name !== "ssr") return;
|
|
370
359
|
const { pathToFileURL } = await import("node:url");
|
|
371
|
-
const
|
|
372
|
-
if (!fs.existsSync(
|
|
373
|
-
const
|
|
374
|
-
|
|
375
|
-
const routes = serverModule.routes || [];
|
|
360
|
+
const prerenderPath = path.resolve(viteConfigRoot, outDir, "server/prerender.mjs");
|
|
361
|
+
if (!fs.existsSync(prerenderPath)) return;
|
|
362
|
+
const { routes } = await import(pathToFileURL(prerenderPath).href);
|
|
363
|
+
if (!routes) return;
|
|
376
364
|
const urlsToPrerender = /* @__PURE__ */ new Set();
|
|
377
365
|
for (const route of routes) {
|
|
378
|
-
let shouldPrerender =
|
|
366
|
+
let shouldPrerender = prerender;
|
|
379
367
|
let dynamicUrls = [];
|
|
380
368
|
if (route.Prerender) {
|
|
381
369
|
const mod = await route.Prerender();
|
|
@@ -389,7 +377,11 @@ if (process.env.NODE_ENV === 'production') {
|
|
|
389
377
|
}
|
|
390
378
|
}
|
|
391
379
|
if (shouldPrerender) {
|
|
392
|
-
if (
|
|
380
|
+
if (route.path.includes(":") && dynamicUrls.length === 0) {
|
|
381
|
+
console.warn(`[vike-lite] ⚠️ Skipping dynamic route "${route.path}": no URLs provided by +prerender. Return an array of URLs to prerender it.`);
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
if (!route.path.includes(":")) urlsToPrerender.add(route.path);
|
|
393
385
|
for (const url of dynamicUrls) urlsToPrerender.add(url);
|
|
394
386
|
}
|
|
395
387
|
}
|
|
@@ -400,21 +392,19 @@ if (process.env.NODE_ENV === 'production') {
|
|
|
400
392
|
let generatedCount = 0;
|
|
401
393
|
const clientDir = path.resolve(viteConfigRoot, outDir, "client");
|
|
402
394
|
for (const urlPath of urlsToPrerender) {
|
|
403
|
-
const
|
|
404
|
-
|
|
405
|
-
if (htmlRes.ok && htmlRes.headers.get("content-type")?.includes("text/html")) {
|
|
395
|
+
const htmlRes = await renderPage(new Request(`http://localhost${baseNoSlash}${urlPath}`));
|
|
396
|
+
if (htmlRes && htmlRes.ok && htmlRes.headers.get("content-type")?.includes("text/html")) {
|
|
406
397
|
const outDirRoute = path.join(clientDir, urlPath === "/" ? "" : urlPath);
|
|
407
398
|
fs.mkdirSync(outDirRoute, { recursive: true });
|
|
408
399
|
fs.writeFileSync(path.join(outDirRoute, "index.html"), await htmlRes.text());
|
|
409
|
-
} else
|
|
400
|
+
} else throw new Error(`\u{1B}[31m✖ SSG HTML Error for ${urlPath}\u{1B}[0m`);
|
|
410
401
|
const jsonTarget = urlPath === "/" ? "/index" : urlPath;
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
if (jsonRes.ok) {
|
|
402
|
+
const jsonRes = await renderPage(new Request(`http://localhost${baseNoSlash}${jsonTarget}.pageContext.json`));
|
|
403
|
+
if (jsonRes && jsonRes.ok) {
|
|
414
404
|
const jsonOutPath = path.join(clientDir, `${jsonTarget}.pageContext.json`);
|
|
415
405
|
fs.mkdirSync(path.dirname(jsonOutPath), { recursive: true });
|
|
416
406
|
fs.writeFileSync(jsonOutPath, await jsonRes.text());
|
|
417
|
-
} else
|
|
407
|
+
} else throw new Error(`\u{1B}[31m✖ SSG JSON Error for ${jsonTarget}\u{1B}[0m`);
|
|
418
408
|
console.log(`\u{1B}[32m✓\u{1B}[0m Pre-rendered: ${urlPath}`);
|
|
419
409
|
generatedCount++;
|
|
420
410
|
}
|
|
@@ -426,14 +416,14 @@ if (process.env.NODE_ENV === 'production') {
|
|
|
426
416
|
server.watcher.on("all", (event, file) => {
|
|
427
417
|
if (!((event === "add" || event === "unlink") && file.startsWith(pagesPath))) return;
|
|
428
418
|
for (const env of Object.values(server.environments)) {
|
|
429
|
-
const mod = env.moduleGraph.getModuleById(
|
|
419
|
+
const mod = env.moduleGraph.getModuleById(RESOLVED.routes);
|
|
430
420
|
if (mod) env.moduleGraph.invalidateModule(mod);
|
|
431
421
|
}
|
|
432
422
|
server.ws.send({ type: "full-reload" });
|
|
433
423
|
});
|
|
434
424
|
server.middlewares.use(async (req, res, next) => {
|
|
435
425
|
try {
|
|
436
|
-
const { default: app } = await server.environments.ssr.runner.import(
|
|
426
|
+
const { default: app } = await server.environments.ssr.runner.import(RESOLVED.entryServer);
|
|
437
427
|
const headers = new Headers();
|
|
438
428
|
for (const [key, value] of Object.entries(req.headers)) {
|
|
439
429
|
if (key.startsWith(":")) continue;
|
|
@@ -461,11 +451,15 @@ if (process.env.NODE_ENV === 'production') {
|
|
|
461
451
|
return;
|
|
462
452
|
}
|
|
463
453
|
for (const [key, value] of response.headers) res.setHeader(key, value);
|
|
464
|
-
if (!response.body) {
|
|
465
|
-
|
|
454
|
+
if (req.method === "HEAD" || !response.body) {
|
|
455
|
+
await response.body?.cancel();
|
|
456
|
+
if (!res.destroyed && !res.closed) res.end();
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
if (res.destroyed || res.closed) {
|
|
460
|
+
await response.body.cancel();
|
|
466
461
|
return;
|
|
467
462
|
}
|
|
468
|
-
if (res.destroyed || res.closed) return;
|
|
469
463
|
try {
|
|
470
464
|
await pipeline(Readable.fromWeb(response.body), res);
|
|
471
465
|
} catch {}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vike-lite",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -46,12 +46,13 @@
|
|
|
46
46
|
"dist"
|
|
47
47
|
],
|
|
48
48
|
"scripts": {
|
|
49
|
+
"tsc": "tsc --noEmit",
|
|
49
50
|
"build": "tsdown"
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|
|
52
|
-
"@types/node": "^26.1.
|
|
53
|
-
"tsdown": "^0.22.
|
|
54
|
-
"vite": "^8.1.
|
|
53
|
+
"@types/node": "^26.1.1",
|
|
54
|
+
"tsdown": "^0.22.4",
|
|
55
|
+
"vite": "^8.1.4"
|
|
55
56
|
},
|
|
56
57
|
"peerDependencies": {
|
|
57
58
|
"vite": ">=8"
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
//#region src/__internal/shared/matchRoute.d.ts
|
|
2
|
-
declare function matchRoute(urlPathname: string, routes: typeof import('virtual:routes').routes): {
|
|
3
|
-
route: any;
|
|
4
|
-
routeParams: Record<string, string>;
|
|
5
|
-
} | null;
|
|
6
|
-
//#endregion
|
|
7
|
-
//#region src/__internal/shared/index.d.ts
|
|
8
|
-
interface RenderContext {
|
|
9
|
-
pageContext: any;
|
|
10
|
-
Page: unknown;
|
|
11
|
-
Head?: unknown;
|
|
12
|
-
Layout?: unknown;
|
|
13
|
-
pageTitleTag: string;
|
|
14
|
-
serializedContext: string;
|
|
15
|
-
assets: {
|
|
16
|
-
cssLinks: string;
|
|
17
|
-
jsPreloads: string;
|
|
18
|
-
entryClient: string;
|
|
19
|
-
};
|
|
20
|
-
nonce?: string;
|
|
21
|
-
}
|
|
22
|
-
type Config = {
|
|
23
|
-
onRenderHtml: () => Promise<{
|
|
24
|
-
default: (ctx: RenderContext) => Promise<string>;
|
|
25
|
-
}>;
|
|
26
|
-
onRenderClient: () => Promise<{
|
|
27
|
-
default: (opts: {
|
|
28
|
-
routes: any[];
|
|
29
|
-
errorRoute: any;
|
|
30
|
-
}) => void;
|
|
31
|
-
}>;
|
|
32
|
-
};
|
|
33
|
-
//#endregion
|
|
34
|
-
export { RenderContext as n, matchRoute as r, Config as t };
|
package/dist/shared-DEpJkq09.mjs
DELETED