vinext 0.0.26 → 0.0.28
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 +89 -85
- package/dist/build/static-export.d.ts +1 -1
- package/dist/build/static-export.d.ts.map +1 -1
- package/dist/build/static-export.js +5 -9
- package/dist/build/static-export.js.map +1 -1
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +152 -48
- package/dist/check.js.map +1 -1
- package/dist/cli.js +10 -11
- package/dist/cli.js.map +1 -1
- package/dist/cloudflare/kv-cache-handler.d.ts +43 -1
- package/dist/cloudflare/kv-cache-handler.d.ts.map +1 -1
- package/dist/cloudflare/kv-cache-handler.js +135 -44
- package/dist/cloudflare/kv-cache-handler.js.map +1 -1
- package/dist/cloudflare/tpr.d.ts.map +1 -1
- package/dist/cloudflare/tpr.js +15 -4
- package/dist/cloudflare/tpr.js.map +1 -1
- package/dist/config/config-matchers.d.ts +28 -0
- package/dist/config/config-matchers.d.ts.map +1 -1
- package/dist/config/config-matchers.js +353 -79
- package/dist/config/config-matchers.js.map +1 -1
- package/dist/config/dotenv.d.ts.map +1 -1
- package/dist/config/dotenv.js +1 -6
- package/dist/config/dotenv.js.map +1 -1
- package/dist/config/next-config.d.ts +7 -0
- package/dist/config/next-config.d.ts.map +1 -1
- package/dist/config/next-config.js +44 -19
- package/dist/config/next-config.js.map +1 -1
- package/dist/deploy.d.ts +1 -1
- package/dist/deploy.d.ts.map +1 -1
- package/dist/deploy.js +81 -48
- package/dist/deploy.js.map +1 -1
- package/dist/entries/app-rsc-entry.d.ts +3 -1
- package/dist/entries/app-rsc-entry.d.ts.map +1 -1
- package/dist/entries/app-rsc-entry.js +584 -113
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/pages-client-entry.d.ts.map +1 -1
- package/dist/entries/pages-client-entry.js +5 -3
- package/dist/entries/pages-client-entry.js.map +1 -1
- package/dist/entries/pages-server-entry.d.ts.map +1 -1
- package/dist/entries/pages-server-entry.js +100 -32
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/index.d.ts +24 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +327 -154
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +6 -5
- package/dist/init.js.map +1 -1
- package/dist/plugins/client-reference-dedup.d.ts +19 -0
- package/dist/plugins/client-reference-dedup.d.ts.map +1 -0
- package/dist/plugins/client-reference-dedup.js +96 -0
- package/dist/plugins/client-reference-dedup.js.map +1 -0
- package/dist/routing/app-router.d.ts +2 -0
- package/dist/routing/app-router.d.ts.map +1 -1
- package/dist/routing/app-router.js +70 -107
- package/dist/routing/app-router.js.map +1 -1
- package/dist/routing/file-matcher.d.ts.map +1 -1
- package/dist/routing/file-matcher.js.map +1 -1
- package/dist/routing/pages-router.d.ts +3 -1
- package/dist/routing/pages-router.d.ts.map +1 -1
- package/dist/routing/pages-router.js +33 -18
- package/dist/routing/pages-router.js.map +1 -1
- package/dist/routing/route-validation.d.ts +8 -0
- package/dist/routing/route-validation.d.ts.map +1 -0
- package/dist/routing/route-validation.js +124 -0
- package/dist/routing/route-validation.js.map +1 -0
- package/dist/routing/utils.d.ts.map +1 -1
- package/dist/routing/utils.js.map +1 -1
- package/dist/server/api-handler.d.ts.map +1 -1
- package/dist/server/api-handler.js +31 -9
- package/dist/server/api-handler.js.map +1 -1
- package/dist/server/app-router-entry.d.ts +3 -2
- package/dist/server/app-router-entry.d.ts.map +1 -1
- package/dist/server/app-router-entry.js +8 -4
- package/dist/server/app-router-entry.js.map +1 -1
- package/dist/server/dev-module-runner.d.ts.map +1 -1
- package/dist/server/dev-module-runner.js +1 -1
- package/dist/server/dev-module-runner.js.map +1 -1
- package/dist/server/dev-origin-check.d.ts.map +1 -1
- package/dist/server/dev-origin-check.js.map +1 -1
- package/dist/server/dev-server.d.ts.map +1 -1
- package/dist/server/dev-server.js +39 -21
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/image-optimization.d.ts.map +1 -1
- package/dist/server/image-optimization.js.map +1 -1
- package/dist/server/instrumentation.js +1 -1
- package/dist/server/instrumentation.js.map +1 -1
- package/dist/server/isr-cache.d.ts +5 -1
- package/dist/server/isr-cache.d.ts.map +1 -1
- package/dist/server/isr-cache.js +13 -3
- package/dist/server/isr-cache.js.map +1 -1
- package/dist/server/metadata-routes.d.ts +8 -2
- package/dist/server/metadata-routes.d.ts.map +1 -1
- package/dist/server/metadata-routes.js +78 -45
- package/dist/server/metadata-routes.js.map +1 -1
- package/dist/server/middleware-codegen.d.ts +1 -1
- package/dist/server/middleware-codegen.d.ts.map +1 -1
- package/dist/server/middleware-codegen.js +177 -22
- package/dist/server/middleware-codegen.js.map +1 -1
- package/dist/server/middleware-request-headers.d.ts +9 -0
- package/dist/server/middleware-request-headers.d.ts.map +1 -0
- package/dist/server/middleware-request-headers.js +77 -0
- package/dist/server/middleware-request-headers.js.map +1 -0
- package/dist/server/middleware.d.ts +9 -8
- package/dist/server/middleware.d.ts.map +1 -1
- package/dist/server/middleware.js +112 -32
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/normalize-path.js.map +1 -1
- package/dist/server/prod-server.d.ts +1 -1
- package/dist/server/prod-server.d.ts.map +1 -1
- package/dist/server/prod-server.js +127 -82
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/request-pipeline.d.ts +2 -1
- package/dist/server/request-pipeline.d.ts.map +1 -1
- package/dist/server/request-pipeline.js +5 -7
- package/dist/server/request-pipeline.js.map +1 -1
- package/dist/shims/cache-runtime.d.ts.map +1 -1
- package/dist/shims/cache-runtime.js +21 -16
- package/dist/shims/cache-runtime.js.map +1 -1
- package/dist/shims/cache.d.ts +2 -0
- package/dist/shims/cache.d.ts.map +1 -1
- package/dist/shims/cache.js +38 -25
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/constants.d.ts.map +1 -1
- package/dist/shims/constants.js +1 -6
- package/dist/shims/constants.js.map +1 -1
- package/dist/shims/dynamic.d.ts.map +1 -1
- package/dist/shims/dynamic.js +1 -1
- package/dist/shims/dynamic.js.map +1 -1
- package/dist/shims/error-boundary.d.ts.map +1 -1
- package/dist/shims/error-boundary.js +2 -3
- package/dist/shims/error-boundary.js.map +1 -1
- package/dist/shims/error.d.ts.map +1 -1
- package/dist/shims/error.js +1 -3
- package/dist/shims/error.js.map +1 -1
- package/dist/shims/fetch-cache.d.ts.map +1 -1
- package/dist/shims/fetch-cache.js +57 -30
- package/dist/shims/fetch-cache.js.map +1 -1
- package/dist/shims/font-google-base.d.ts.map +1 -1
- package/dist/shims/font-google-base.js +16 -4
- package/dist/shims/font-google-base.js.map +1 -1
- package/dist/shims/font-google.d.ts +1 -1
- package/dist/shims/font-google.d.ts.map +1 -1
- package/dist/shims/font-google.generated.d.ts.map +1 -1
- package/dist/shims/font-google.generated.js +412 -206
- package/dist/shims/font-google.generated.js.map +1 -1
- package/dist/shims/font-google.js +1 -1
- package/dist/shims/font-google.js.map +1 -1
- package/dist/shims/font-local.d.ts.map +1 -1
- package/dist/shims/font-local.js +13 -3
- package/dist/shims/font-local.js.map +1 -1
- package/dist/shims/form.d.ts.map +1 -1
- package/dist/shims/form.js +105 -10
- package/dist/shims/form.js.map +1 -1
- package/dist/shims/head.d.ts.map +1 -1
- package/dist/shims/head.js +10 -8
- package/dist/shims/head.js.map +1 -1
- package/dist/shims/headers.d.ts +34 -8
- package/dist/shims/headers.d.ts.map +1 -1
- package/dist/shims/headers.js +268 -53
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/image.d.ts.map +1 -1
- package/dist/shims/image.js +35 -8
- package/dist/shims/image.js.map +1 -1
- package/dist/shims/internal/parse-cookie-header.d.ts +12 -0
- package/dist/shims/internal/parse-cookie-header.d.ts.map +1 -0
- package/dist/shims/internal/parse-cookie-header.js +32 -0
- package/dist/shims/internal/parse-cookie-header.js.map +1 -0
- package/dist/shims/legacy-image.d.ts.map +1 -1
- package/dist/shims/legacy-image.js +1 -1
- package/dist/shims/legacy-image.js.map +1 -1
- package/dist/shims/link.d.ts +2 -1
- package/dist/shims/link.d.ts.map +1 -1
- package/dist/shims/link.js +37 -17
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/metadata.d.ts +12 -2
- package/dist/shims/metadata.d.ts.map +1 -1
- package/dist/shims/metadata.js +10 -8
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation-state.d.ts.map +1 -1
- package/dist/shims/navigation-state.js +3 -2
- package/dist/shims/navigation-state.js.map +1 -1
- package/dist/shims/navigation.d.ts +3 -7
- package/dist/shims/navigation.d.ts.map +1 -1
- package/dist/shims/navigation.js +46 -29
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/readonly-url-search-params.d.ts +11 -0
- package/dist/shims/readonly-url-search-params.d.ts.map +1 -0
- package/dist/shims/readonly-url-search-params.js +24 -0
- package/dist/shims/readonly-url-search-params.js.map +1 -0
- package/dist/shims/request-context.d.ts +50 -0
- package/dist/shims/request-context.d.ts.map +1 -0
- package/dist/shims/request-context.js +59 -0
- package/dist/shims/request-context.js.map +1 -0
- package/dist/shims/router-state.d.ts.map +1 -1
- package/dist/shims/router-state.js +2 -1
- package/dist/shims/router-state.js.map +1 -1
- package/dist/shims/router.d.ts +4 -3
- package/dist/shims/router.d.ts.map +1 -1
- package/dist/shims/router.js +59 -53
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/script.d.ts.map +1 -1
- package/dist/shims/script.js.map +1 -1
- package/dist/shims/server.d.ts +14 -1
- package/dist/shims/server.d.ts.map +1 -1
- package/dist/shims/server.js +107 -47
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/url-utils.d.ts.map +1 -1
- package/dist/shims/url-utils.js +1 -3
- package/dist/shims/url-utils.js.map +1 -1
- package/dist/utils/base-path.d.ts +17 -0
- package/dist/utils/base-path.d.ts.map +1 -0
- package/dist/utils/base-path.js +25 -0
- package/dist/utils/base-path.js.map +1 -0
- package/dist/utils/manifest-paths.d.ts +4 -0
- package/dist/utils/manifest-paths.d.ts.map +1 -0
- package/dist/utils/manifest-paths.js +20 -0
- package/dist/utils/manifest-paths.js.map +1 -0
- package/dist/utils/project.d.ts.map +1 -1
- package/dist/utils/project.js +2 -4
- package/dist/utils/project.js.map +1 -1
- package/dist/utils/query.d.ts +9 -0
- package/dist/utils/query.d.ts.map +1 -1
- package/dist/utils/query.js +59 -7
- package/dist/utils/query.js.map +1 -1
- package/package.json +47 -33
|
@@ -23,10 +23,12 @@ import { pathToFileURL } from "node:url";
|
|
|
23
23
|
import fs from "node:fs";
|
|
24
24
|
import path from "node:path";
|
|
25
25
|
import zlib from "node:zlib";
|
|
26
|
-
import { matchRedirect, matchRewrite, matchHeaders, requestContextFromRequest, applyMiddlewareRequestHeaders, isExternalUrl, proxyExternalRequest, sanitizeDestination } from "../config/config-matchers.js";
|
|
27
|
-
import { IMAGE_OPTIMIZATION_PATH, IMAGE_CONTENT_SECURITY_POLICY, parseImageParams, isSafeImageContentType, DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES } from "./image-optimization.js";
|
|
26
|
+
import { matchRedirect, matchRewrite, matchHeaders, requestContextFromRequest, applyMiddlewareRequestHeaders, isExternalUrl, proxyExternalRequest, sanitizeDestination, } from "../config/config-matchers.js";
|
|
27
|
+
import { IMAGE_OPTIMIZATION_PATH, IMAGE_CONTENT_SECURITY_POLICY, parseImageParams, isSafeImageContentType, DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, } from "./image-optimization.js";
|
|
28
28
|
import { normalizePath } from "./normalize-path.js";
|
|
29
|
+
import { hasBasePath, stripBasePath } from "../utils/base-path.js";
|
|
29
30
|
import { computeLazyChunks } from "../index.js";
|
|
31
|
+
import { manifestFileWithBase } from "../utils/manifest-paths.js";
|
|
30
32
|
/** Convert a Node.js IncomingMessage into a ReadableStream for Web Request body. */
|
|
31
33
|
function readNodeStream(req) {
|
|
32
34
|
return new ReadableStream({
|
|
@@ -108,9 +110,7 @@ function mergeResponseHeaders(middlewareHeaders, response) {
|
|
|
108
110
|
const responseCookies = response.headers.getSetCookie?.() ?? [];
|
|
109
111
|
if (responseCookies.length > 0) {
|
|
110
112
|
const existing = merged["set-cookie"];
|
|
111
|
-
const mwCookies = existing
|
|
112
|
-
? (Array.isArray(existing) ? existing : [existing])
|
|
113
|
-
: [];
|
|
113
|
+
const mwCookies = existing ? (Array.isArray(existing) ? existing : [existing]) : [];
|
|
114
114
|
merged["set-cookie"] = [...mwCookies, ...responseCookies];
|
|
115
115
|
}
|
|
116
116
|
return merged;
|
|
@@ -133,7 +133,9 @@ function sendCompressed(req, res, body, contentType, statusCode, extraHeaders =
|
|
|
133
133
|
let varyValue;
|
|
134
134
|
if (existingVary) {
|
|
135
135
|
const existing = existingVary.toLowerCase();
|
|
136
|
-
varyValue = existing.includes("accept-encoding")
|
|
136
|
+
varyValue = existing.includes("accept-encoding")
|
|
137
|
+
? existingVary
|
|
138
|
+
: existingVary + ", Accept-Encoding";
|
|
137
139
|
}
|
|
138
140
|
else {
|
|
139
141
|
varyValue = "Accept-Encoding";
|
|
@@ -145,11 +147,16 @@ function sendCompressed(req, res, body, contentType, statusCode, extraHeaders =
|
|
|
145
147
|
Vary: varyValue,
|
|
146
148
|
});
|
|
147
149
|
compressor.end(buf);
|
|
148
|
-
pipeline(compressor, res, () => {
|
|
150
|
+
pipeline(compressor, res, () => {
|
|
151
|
+
/* ignore pipeline errors on closed connections */
|
|
152
|
+
});
|
|
149
153
|
}
|
|
150
154
|
else {
|
|
155
|
+
// Strip any pre-existing content-length (from the Web Response constructor)
|
|
156
|
+
// before setting our own — avoids duplicate Content-Length headers.
|
|
157
|
+
const { "content-length": _cl, "Content-Length": _CL, ...headersWithoutLength } = extraHeaders;
|
|
151
158
|
res.writeHead(statusCode, {
|
|
152
|
-
...
|
|
159
|
+
...headersWithoutLength,
|
|
153
160
|
"Content-Type": contentType,
|
|
154
161
|
"Content-Length": String(buf.length),
|
|
155
162
|
});
|
|
@@ -202,17 +209,13 @@ function tryServeStatic(req, res, clientDir, pathname, compress, extraHeaders) {
|
|
|
202
209
|
if (!staticFile.startsWith(resolvedClient + path.sep) && staticFile !== resolvedClient) {
|
|
203
210
|
return false;
|
|
204
211
|
}
|
|
205
|
-
if (pathname === "/" ||
|
|
206
|
-
!fs.existsSync(staticFile) ||
|
|
207
|
-
!fs.statSync(staticFile).isFile()) {
|
|
212
|
+
if (pathname === "/" || !fs.existsSync(staticFile) || !fs.statSync(staticFile).isFile()) {
|
|
208
213
|
return false;
|
|
209
214
|
}
|
|
210
215
|
const ext = path.extname(staticFile);
|
|
211
216
|
const ct = CONTENT_TYPES[ext] ?? "application/octet-stream";
|
|
212
217
|
const isHashed = pathname.startsWith("/assets/");
|
|
213
|
-
const cacheControl = isHashed
|
|
214
|
-
? "public, max-age=31536000, immutable"
|
|
215
|
-
: "public, max-age=3600";
|
|
218
|
+
const cacheControl = isHashed ? "public, max-age=31536000, immutable" : "public, max-age=3600";
|
|
216
219
|
const baseHeaders = {
|
|
217
220
|
"Content-Type": ct,
|
|
218
221
|
"Cache-Control": cacheControl,
|
|
@@ -229,7 +232,9 @@ function tryServeStatic(req, res, clientDir, pathname, compress, extraHeaders) {
|
|
|
229
232
|
"Content-Encoding": encoding,
|
|
230
233
|
Vary: "Accept-Encoding",
|
|
231
234
|
});
|
|
232
|
-
pipeline(fileStream, compressor, res, () => {
|
|
235
|
+
pipeline(fileStream, compressor, res, () => {
|
|
236
|
+
/* ignore */
|
|
237
|
+
});
|
|
233
238
|
return true;
|
|
234
239
|
}
|
|
235
240
|
}
|
|
@@ -321,9 +326,7 @@ async function sendWebResponse(webResponse, req, res, compress) {
|
|
|
321
326
|
webResponse.headers.forEach((value, key) => {
|
|
322
327
|
const existing = nodeHeaders[key];
|
|
323
328
|
if (existing !== undefined) {
|
|
324
|
-
nodeHeaders[key] = Array.isArray(existing)
|
|
325
|
-
? [...existing, value]
|
|
326
|
-
: [existing, value];
|
|
329
|
+
nodeHeaders[key] = Array.isArray(existing) ? [...existing, value] : [existing, value];
|
|
327
330
|
}
|
|
328
331
|
else {
|
|
329
332
|
nodeHeaders[key] = value;
|
|
@@ -339,7 +342,7 @@ async function sendWebResponse(webResponse, req, res, compress) {
|
|
|
339
342
|
const alreadyEncoded = webResponse.headers.has("content-encoding");
|
|
340
343
|
const contentType = webResponse.headers.get("content-type") ?? "";
|
|
341
344
|
const baseType = contentType.split(";")[0].trim();
|
|
342
|
-
const encoding =
|
|
345
|
+
const encoding = compress && !alreadyEncoded ? negotiateEncoding(req) : null;
|
|
343
346
|
const shouldCompress = !!(encoding && COMPRESSIBLE_TYPES.has(baseType));
|
|
344
347
|
if (shouldCompress) {
|
|
345
348
|
delete nodeHeaders["content-length"];
|
|
@@ -370,10 +373,14 @@ async function sendWebResponse(webResponse, req, res, compress) {
|
|
|
370
373
|
const nodeStream = Readable.fromWeb(webResponse.body);
|
|
371
374
|
if (shouldCompress) {
|
|
372
375
|
const compressor = createCompressor(encoding);
|
|
373
|
-
pipeline(nodeStream, compressor, res, () => {
|
|
376
|
+
pipeline(nodeStream, compressor, res, () => {
|
|
377
|
+
/* ignore pipeline errors on closed connections */
|
|
378
|
+
});
|
|
374
379
|
}
|
|
375
380
|
else {
|
|
376
|
-
pipeline(nodeStream, res, () => {
|
|
381
|
+
pipeline(nodeStream, res, () => {
|
|
382
|
+
/* ignore pipeline errors on closed connections */
|
|
383
|
+
});
|
|
377
384
|
}
|
|
378
385
|
}
|
|
379
386
|
/**
|
|
@@ -402,11 +409,36 @@ export async function startProdServer(options = {}) {
|
|
|
402
409
|
}
|
|
403
410
|
return startPagesRouterServer({ port, host, clientDir, serverEntryPath, compress });
|
|
404
411
|
}
|
|
412
|
+
function createNodeExecutionContext() {
|
|
413
|
+
return {
|
|
414
|
+
waitUntil(promise) {
|
|
415
|
+
// Node doesn't provide a Workers lifecycle, but we still attach a
|
|
416
|
+
// rejection handler so background waitUntil work doesn't surface as an
|
|
417
|
+
// unhandled rejection when a Worker-style entry is used with vinext start.
|
|
418
|
+
void Promise.resolve(promise).catch(() => { });
|
|
419
|
+
},
|
|
420
|
+
passThroughOnException() { },
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
function resolveAppRouterHandler(entry) {
|
|
424
|
+
if (typeof entry === "function") {
|
|
425
|
+
return (request) => Promise.resolve(entry(request));
|
|
426
|
+
}
|
|
427
|
+
if (entry && typeof entry === "object" && "fetch" in entry) {
|
|
428
|
+
const workerEntry = entry;
|
|
429
|
+
if (typeof workerEntry.fetch === "function") {
|
|
430
|
+
return (request) => Promise.resolve(workerEntry.fetch(request, undefined, createNodeExecutionContext()));
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
console.error("[vinext] App Router entry must export either a default handler function or a Worker-style default export with fetch()");
|
|
434
|
+
process.exit(1);
|
|
435
|
+
}
|
|
405
436
|
/**
|
|
406
437
|
* Start the App Router production server.
|
|
407
438
|
*
|
|
408
|
-
* The
|
|
409
|
-
* handler(request: Request) → Promise<Response>
|
|
439
|
+
* The App Router entry (dist/server/index.js) can export either:
|
|
440
|
+
* - a default handler function: handler(request: Request) → Promise<Response>
|
|
441
|
+
* - a Worker-style object: { fetch(request, env, ctx) → Promise<Response> }
|
|
410
442
|
*
|
|
411
443
|
* This handler already does everything: route matching, RSC rendering,
|
|
412
444
|
* SSR HTML generation (via import("./ssr/index.js")), route handlers,
|
|
@@ -428,15 +460,13 @@ async function startAppRouterServer(options) {
|
|
|
428
460
|
try {
|
|
429
461
|
imageConfig = JSON.parse(fs.readFileSync(imageConfigPath, "utf-8"));
|
|
430
462
|
}
|
|
431
|
-
catch {
|
|
463
|
+
catch {
|
|
464
|
+
/* ignore parse errors */
|
|
465
|
+
}
|
|
432
466
|
}
|
|
433
467
|
// Import the RSC handler (use file:// URL for reliable dynamic import)
|
|
434
468
|
const rscModule = await import(pathToFileURL(rscEntryPath).href);
|
|
435
|
-
const rscHandler = rscModule.default;
|
|
436
|
-
if (typeof rscHandler !== "function") {
|
|
437
|
-
console.error("[vinext] RSC entry does not export a default handler function");
|
|
438
|
-
process.exit(1);
|
|
439
|
-
}
|
|
469
|
+
const rscHandler = resolveAppRouterHandler(rscModule.default);
|
|
440
470
|
const server = createServer(async (req, res) => {
|
|
441
471
|
const url = req.url ?? "/";
|
|
442
472
|
// Normalize backslashes (browsers treat /\ as //), then decode and normalize path.
|
|
@@ -531,6 +561,33 @@ async function startAppRouterServer(options) {
|
|
|
531
561
|
*/
|
|
532
562
|
async function startPagesRouterServer(options) {
|
|
533
563
|
const { port, host, clientDir, serverEntryPath, compress } = options;
|
|
564
|
+
// Import the server entry module (use file:// URL for reliable dynamic import)
|
|
565
|
+
const serverEntry = await import(pathToFileURL(serverEntryPath).href);
|
|
566
|
+
const { renderPage, handleApiRoute: handleApi, runMiddleware, vinextConfig } = serverEntry;
|
|
567
|
+
// Extract config values (embedded at build time in the server entry)
|
|
568
|
+
const basePath = vinextConfig?.basePath ?? "";
|
|
569
|
+
const assetBase = basePath ? `${basePath}/` : "/";
|
|
570
|
+
const trailingSlash = vinextConfig?.trailingSlash ?? false;
|
|
571
|
+
const configRedirects = vinextConfig?.redirects ?? [];
|
|
572
|
+
const configRewrites = vinextConfig?.rewrites ?? {
|
|
573
|
+
beforeFiles: [],
|
|
574
|
+
afterFiles: [],
|
|
575
|
+
fallback: [],
|
|
576
|
+
};
|
|
577
|
+
const configHeaders = vinextConfig?.headers ?? [];
|
|
578
|
+
// Compute allowed image widths from config (union of deviceSizes + imageSizes)
|
|
579
|
+
const allowedImageWidths = [
|
|
580
|
+
...(vinextConfig?.images?.deviceSizes ?? DEFAULT_DEVICE_SIZES),
|
|
581
|
+
...(vinextConfig?.images?.imageSizes ?? DEFAULT_IMAGE_SIZES),
|
|
582
|
+
];
|
|
583
|
+
// Extract image security config for SVG handling and security headers
|
|
584
|
+
const pagesImageConfig = vinextConfig?.images
|
|
585
|
+
? {
|
|
586
|
+
dangerouslyAllowSVG: vinextConfig.images.dangerouslyAllowSVG,
|
|
587
|
+
contentDispositionType: vinextConfig.images.contentDispositionType,
|
|
588
|
+
contentSecurityPolicy: vinextConfig.images.contentSecurityPolicy,
|
|
589
|
+
}
|
|
590
|
+
: undefined;
|
|
534
591
|
// Load the SSR manifest (maps module URLs to client asset URLs)
|
|
535
592
|
let ssrManifest = {};
|
|
536
593
|
const manifestPath = path.join(clientDir, ".vite", "ssr-manifest.json");
|
|
@@ -544,33 +601,15 @@ async function startPagesRouterServer(options) {
|
|
|
544
601
|
if (fs.existsSync(buildManifestPath)) {
|
|
545
602
|
try {
|
|
546
603
|
const buildManifest = JSON.parse(fs.readFileSync(buildManifestPath, "utf-8"));
|
|
547
|
-
const lazyChunks = computeLazyChunks(buildManifest);
|
|
604
|
+
const lazyChunks = computeLazyChunks(buildManifest).map((file) => manifestFileWithBase(file, assetBase));
|
|
548
605
|
if (lazyChunks.length > 0) {
|
|
549
606
|
globalThis.__VINEXT_LAZY_CHUNKS__ = lazyChunks;
|
|
550
607
|
}
|
|
551
608
|
}
|
|
552
|
-
catch {
|
|
609
|
+
catch {
|
|
610
|
+
/* ignore parse errors */
|
|
611
|
+
}
|
|
553
612
|
}
|
|
554
|
-
// Import the server entry module (use file:// URL for reliable dynamic import)
|
|
555
|
-
const serverEntry = await import(pathToFileURL(serverEntryPath).href);
|
|
556
|
-
const { renderPage, handleApiRoute: handleApi, runMiddleware, vinextConfig } = serverEntry;
|
|
557
|
-
// Extract config values (embedded at build time in the server entry)
|
|
558
|
-
const basePath = vinextConfig?.basePath ?? "";
|
|
559
|
-
const trailingSlash = vinextConfig?.trailingSlash ?? false;
|
|
560
|
-
const configRedirects = vinextConfig?.redirects ?? [];
|
|
561
|
-
const configRewrites = vinextConfig?.rewrites ?? { beforeFiles: [], afterFiles: [], fallback: [] };
|
|
562
|
-
const configHeaders = vinextConfig?.headers ?? [];
|
|
563
|
-
// Compute allowed image widths from config (union of deviceSizes + imageSizes)
|
|
564
|
-
const allowedImageWidths = [
|
|
565
|
-
...(vinextConfig?.images?.deviceSizes ?? DEFAULT_DEVICE_SIZES),
|
|
566
|
-
...(vinextConfig?.images?.imageSizes ?? DEFAULT_IMAGE_SIZES),
|
|
567
|
-
];
|
|
568
|
-
// Extract image security config for SVG handling and security headers
|
|
569
|
-
const pagesImageConfig = vinextConfig?.images ? {
|
|
570
|
-
dangerouslyAllowSVG: vinextConfig.images.dangerouslyAllowSVG,
|
|
571
|
-
contentDispositionType: vinextConfig.images.contentDispositionType,
|
|
572
|
-
contentSecurityPolicy: vinextConfig.images.contentSecurityPolicy,
|
|
573
|
-
} : undefined;
|
|
574
613
|
const server = createServer(async (req, res) => {
|
|
575
614
|
const rawUrl = req.url ?? "/";
|
|
576
615
|
// Normalize backslashes (browsers treat /\ as //), then decode and normalize path.
|
|
@@ -601,9 +640,7 @@ async function startPagesRouterServer(options) {
|
|
|
601
640
|
// Serve static files from client build. When basePath is configured,
|
|
602
641
|
// Vite's `base` config ensures assets are under basePath/assets/.
|
|
603
642
|
// We check both with and without basePath.
|
|
604
|
-
const staticLookupPath =
|
|
605
|
-
? pathname.slice(basePath.length) || "/"
|
|
606
|
-
: pathname;
|
|
643
|
+
const staticLookupPath = stripBasePath(pathname, basePath);
|
|
607
644
|
if (staticLookupPath !== "/" &&
|
|
608
645
|
!staticLookupPath.startsWith("/api/") &&
|
|
609
646
|
tryServeStatic(req, res, clientDir, staticLookupPath, compress)) {
|
|
@@ -641,11 +678,13 @@ async function startPagesRouterServer(options) {
|
|
|
641
678
|
}
|
|
642
679
|
try {
|
|
643
680
|
// ── 2. Strip basePath ─────────────────────────────────────────
|
|
644
|
-
|
|
645
|
-
const stripped = pathname
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
681
|
+
{
|
|
682
|
+
const stripped = stripBasePath(pathname, basePath);
|
|
683
|
+
if (stripped !== pathname) {
|
|
684
|
+
const qs = url.includes("?") ? url.slice(url.indexOf("?")) : "";
|
|
685
|
+
url = stripped + qs;
|
|
686
|
+
pathname = stripped;
|
|
687
|
+
}
|
|
649
688
|
}
|
|
650
689
|
// ── 3. Trailing slash normalization ───────────────────────────
|
|
651
690
|
if (pathname !== "/" && pathname !== "/api" && !pathname.startsWith("/api/")) {
|
|
@@ -683,12 +722,31 @@ async function startPagesRouterServer(options) {
|
|
|
683
722
|
// @ts-expect-error — duplex needed for streaming request bodies
|
|
684
723
|
duplex: hasBody ? "half" : undefined,
|
|
685
724
|
});
|
|
686
|
-
// Build request context for
|
|
687
|
-
//
|
|
688
|
-
// snapshot
|
|
689
|
-
//
|
|
725
|
+
// Build request context for pre-middleware config matching. Redirects
|
|
726
|
+
// run before middleware in Next.js. Header match conditions also use the
|
|
727
|
+
// original request snapshot even though header merging happens later so
|
|
728
|
+
// middleware response headers can still take precedence.
|
|
729
|
+
// beforeFiles, afterFiles, and fallback all run after middleware per the
|
|
730
|
+
// Next.js execution order, so they use postMwReqCtx below.
|
|
690
731
|
const reqCtx = requestContextFromRequest(webRequest);
|
|
691
|
-
// ── 4.
|
|
732
|
+
// ── 4. Apply redirects from next.config.js ────────────────────
|
|
733
|
+
if (configRedirects.length) {
|
|
734
|
+
const redirect = matchRedirect(pathname, configRedirects, reqCtx);
|
|
735
|
+
if (redirect) {
|
|
736
|
+
// Guard against double-prefixing: only add basePath if destination
|
|
737
|
+
// doesn't already start with it.
|
|
738
|
+
// Sanitize the final destination to prevent protocol-relative URL open redirects.
|
|
739
|
+
const dest = sanitizeDestination(basePath &&
|
|
740
|
+
!isExternalUrl(redirect.destination) &&
|
|
741
|
+
!hasBasePath(redirect.destination, basePath)
|
|
742
|
+
? basePath + redirect.destination
|
|
743
|
+
: redirect.destination);
|
|
744
|
+
res.writeHead(redirect.permanent ? 308 : 307, { Location: dest });
|
|
745
|
+
res.end();
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
// ── 5. Run middleware ─────────────────────────────────────────
|
|
692
750
|
let resolvedUrl = url;
|
|
693
751
|
const middlewareHeaders = {};
|
|
694
752
|
let middlewareRewriteStatus;
|
|
@@ -771,15 +829,17 @@ async function startPagesRouterServer(options) {
|
|
|
771
829
|
// middleware per the Next.js execution order).
|
|
772
830
|
const { postMwReqCtx, request: postMwReq } = applyMiddlewareRequestHeaders(middlewareHeaders, webRequest);
|
|
773
831
|
webRequest = postMwReq;
|
|
832
|
+
// Config header matching must keep using the original normalized pathname
|
|
833
|
+
// even if middleware rewrites the downstream route/render target.
|
|
774
834
|
let resolvedPathname = resolvedUrl.split("?")[0];
|
|
775
|
-
// ──
|
|
835
|
+
// ── 6. Apply custom headers from next.config.js ───────────────
|
|
776
836
|
// Config headers are additive for multi-value headers (Vary,
|
|
777
837
|
// Set-Cookie) and override for everything else. Set-Cookie values
|
|
778
838
|
// are stored as arrays (RFC 6265 forbids comma-joining cookies).
|
|
779
839
|
// Middleware headers take precedence: skip config keys already set
|
|
780
840
|
// by middleware so middleware always wins for the same key.
|
|
781
841
|
if (configHeaders.length) {
|
|
782
|
-
const matched = matchHeaders(
|
|
842
|
+
const matched = matchHeaders(pathname, configHeaders, reqCtx);
|
|
783
843
|
for (const h of matched) {
|
|
784
844
|
const lk = h.key.toLowerCase();
|
|
785
845
|
if (lk === "set-cookie") {
|
|
@@ -804,21 +864,6 @@ async function startPagesRouterServer(options) {
|
|
|
804
864
|
}
|
|
805
865
|
}
|
|
806
866
|
}
|
|
807
|
-
// ── 6. Apply redirects from next.config.js ────────────────────
|
|
808
|
-
if (configRedirects.length) {
|
|
809
|
-
const redirect = matchRedirect(resolvedPathname, configRedirects, reqCtx);
|
|
810
|
-
if (redirect) {
|
|
811
|
-
// Guard against double-prefixing: only add basePath if destination
|
|
812
|
-
// doesn't already start with it.
|
|
813
|
-
// Sanitize the final destination to prevent protocol-relative URL open redirects.
|
|
814
|
-
const dest = sanitizeDestination(basePath && !redirect.destination.startsWith(basePath)
|
|
815
|
-
? basePath + redirect.destination
|
|
816
|
-
: redirect.destination);
|
|
817
|
-
res.writeHead(redirect.permanent ? 308 : 307, { Location: dest });
|
|
818
|
-
res.end();
|
|
819
|
-
return;
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
867
|
// ── 7. Apply beforeFiles rewrites from next.config.js ─────────
|
|
823
868
|
if (configRewrites.beforeFiles?.length) {
|
|
824
869
|
const rewritten = matchRewrite(resolvedPathname, configRewrites.beforeFiles, postMwReqCtx);
|
|
@@ -909,5 +954,5 @@ async function startPagesRouterServer(options) {
|
|
|
909
954
|
return server;
|
|
910
955
|
}
|
|
911
956
|
// Export helpers for testing
|
|
912
|
-
export { sendCompressed, negotiateEncoding, COMPRESSIBLE_TYPES, COMPRESS_THRESHOLD, resolveHost, trustedHosts, trustProxy, nodeToWebRequest, mergeResponseHeaders };
|
|
957
|
+
export { sendCompressed, negotiateEncoding, COMPRESSIBLE_TYPES, COMPRESS_THRESHOLD, resolveHost, trustedHosts, trustProxy, nodeToWebRequest, mergeResponseHeaders, };
|
|
913
958
|
//# sourceMappingURL=prod-server.js.map
|