vinext 0.0.22 → 0.0.23
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/build/static-export.d.ts.map +1 -1
- package/dist/build/static-export.js +9 -7
- package/dist/build/static-export.js.map +1 -1
- package/dist/config/next-config.d.ts +4 -1
- package/dist/config/next-config.d.ts.map +1 -1
- package/dist/config/next-config.js +10 -5
- package/dist/config/next-config.js.map +1 -1
- package/dist/deploy.d.ts.map +1 -1
- package/dist/deploy.js +11 -1
- package/dist/deploy.js.map +1 -1
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +202 -28
- package/dist/index.js.map +1 -1
- package/dist/routing/app-router.d.ts +2 -1
- package/dist/routing/app-router.d.ts.map +1 -1
- package/dist/routing/app-router.js +73 -66
- package/dist/routing/app-router.js.map +1 -1
- package/dist/routing/file-matcher.d.ts +24 -0
- package/dist/routing/file-matcher.d.ts.map +1 -0
- package/dist/routing/file-matcher.js +75 -0
- package/dist/routing/file-matcher.js.map +1 -0
- package/dist/routing/pages-router.d.ts +3 -2
- package/dist/routing/pages-router.d.ts.map +1 -1
- package/dist/routing/pages-router.js +24 -17
- package/dist/routing/pages-router.js.map +1 -1
- package/dist/server/app-dev-server.d.ts.map +1 -1
- package/dist/server/app-dev-server.js +54 -45
- package/dist/server/app-dev-server.js.map +1 -1
- package/dist/server/dev-server.d.ts +2 -1
- package/dist/server/dev-server.d.ts.map +1 -1
- package/dist/server/dev-server.js +16 -14
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/prod-server.d.ts.map +1 -1
- package/dist/server/prod-server.js +26 -2
- package/dist/server/prod-server.js.map +1 -1
- package/dist/shims/cache.d.ts +1 -1
- package/dist/shims/cache.d.ts.map +1 -1
- package/dist/shims/cache.js +8 -3
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/metadata.d.ts +1 -0
- package/dist/shims/metadata.d.ts.map +1 -1
- package/dist/shims/metadata.js +5 -1
- package/dist/shims/metadata.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { loadEnv, parseAst } from "vite";
|
|
2
2
|
import { pagesRouter, apiRouter, invalidateRouteCache, matchRoute, patternToNextFormat as pagesPatternToNextFormat } from "./routing/pages-router.js";
|
|
3
3
|
import { appRouter, invalidateAppRouteCache } from "./routing/app-router.js";
|
|
4
|
+
import { createValidFileMatcher } from "./routing/file-matcher.js";
|
|
4
5
|
import { createSSRHandler } from "./server/dev-server.js";
|
|
5
6
|
import { handleApiRoute } from "./server/api-handler.js";
|
|
6
7
|
import { generateRscEntry, generateSsrEntry, generateBrowserEntry, } from "./server/app-dev-server.js";
|
|
@@ -10,6 +11,7 @@ import { logRequest, now } from "./server/request-log.js";
|
|
|
10
11
|
import { generateSafeRegExpCode, generateMiddlewareMatcherCode, generateNormalizePathCode } from "./server/middleware-codegen.js";
|
|
11
12
|
import { normalizePath } from "./server/normalize-path.js";
|
|
12
13
|
import { findInstrumentationFile, runInstrumentation } from "./server/instrumentation.js";
|
|
14
|
+
import { PHASE_PRODUCTION_BUILD, PHASE_DEVELOPMENT_SERVER } from "./shims/constants.js";
|
|
13
15
|
import { validateDevRequest } from "./server/dev-origin-check.js";
|
|
14
16
|
import { safeRegExp, isExternalUrl, proxyExternalRequest, parseCookies, matchHeaders, matchRedirect, matchRewrite, } from "./config/config-matchers.js";
|
|
15
17
|
import { scanMetadataFiles } from "./server/metadata-routes.js";
|
|
@@ -493,6 +495,7 @@ export default function vinext(options = {}) {
|
|
|
493
495
|
let hasAppDir = false;
|
|
494
496
|
let hasPagesDir = false;
|
|
495
497
|
let nextConfig;
|
|
498
|
+
let fileMatcher;
|
|
496
499
|
let middlewarePath = null;
|
|
497
500
|
let instrumentationPath = null;
|
|
498
501
|
let hasCloudflarePlugin = false;
|
|
@@ -506,8 +509,8 @@ export default function vinext(options = {}) {
|
|
|
506
509
|
* This is the entry point for `vite build --ssr`.
|
|
507
510
|
*/
|
|
508
511
|
async function generateServerEntry() {
|
|
509
|
-
const pageRoutes = await pagesRouter(pagesDir);
|
|
510
|
-
const apiRoutes = await apiRouter(pagesDir);
|
|
512
|
+
const pageRoutes = await pagesRouter(pagesDir, nextConfig?.pageExtensions, fileMatcher);
|
|
513
|
+
const apiRoutes = await apiRouter(pagesDir, nextConfig?.pageExtensions, fileMatcher);
|
|
511
514
|
// Generate import statements using absolute paths since virtual
|
|
512
515
|
// modules don't have a real file location for relative resolution.
|
|
513
516
|
const pageImports = pageRoutes.map((r, i) => {
|
|
@@ -527,16 +530,15 @@ export default function vinext(options = {}) {
|
|
|
527
530
|
return ` { pattern: ${JSON.stringify(r.pattern)}, isDynamic: ${r.isDynamic}, params: ${JSON.stringify(r.params)}, module: api_${i} }`;
|
|
528
531
|
});
|
|
529
532
|
// Check for _app and _document
|
|
530
|
-
const
|
|
531
|
-
const
|
|
532
|
-
|
|
533
|
-
const
|
|
534
|
-
const docFileBase = path.join(pagesDir, "_document").replace(/\\/g, "/");
|
|
533
|
+
const appFilePath = findFileWithExts(pagesDir, "_app", fileMatcher);
|
|
534
|
+
const docFilePath = findFileWithExts(pagesDir, "_document", fileMatcher);
|
|
535
|
+
const hasApp = appFilePath !== null;
|
|
536
|
+
const hasDoc = docFilePath !== null;
|
|
535
537
|
const appImportCode = hasApp
|
|
536
|
-
? `import { default as AppComponent } from ${JSON.stringify(
|
|
538
|
+
? `import { default as AppComponent } from ${JSON.stringify(appFilePath.replace(/\\/g, "/"))};`
|
|
537
539
|
: `const AppComponent = null;`;
|
|
538
540
|
const docImportCode = hasDoc
|
|
539
|
-
? `import { default as DocumentComponent } from ${JSON.stringify(
|
|
541
|
+
? `import { default as DocumentComponent } from ${JSON.stringify(docFilePath.replace(/\\/g, "/"))};`
|
|
540
542
|
: `const DocumentComponent = null;`;
|
|
541
543
|
// Serialize i18n config for embedding in the server entry
|
|
542
544
|
const i18nConfigJson = nextConfig?.i18n
|
|
@@ -1460,8 +1462,9 @@ ${middlewareExportCode}
|
|
|
1460
1462
|
* __NEXT_DATA__ to determine which page to hydrate.
|
|
1461
1463
|
*/
|
|
1462
1464
|
async function generateClientEntry() {
|
|
1463
|
-
const pageRoutes = await pagesRouter(pagesDir);
|
|
1464
|
-
const
|
|
1465
|
+
const pageRoutes = await pagesRouter(pagesDir, nextConfig?.pageExtensions, fileMatcher);
|
|
1466
|
+
const appFilePath = findFileWithExts(pagesDir, "_app", fileMatcher);
|
|
1467
|
+
const hasApp = appFilePath !== null;
|
|
1465
1468
|
// Build a map of route pattern -> dynamic import.
|
|
1466
1469
|
// Keys must use Next.js bracket format (e.g. "/user/[id]") to match
|
|
1467
1470
|
// __NEXT_DATA__.page which is set via patternToNextFormat() during SSR.
|
|
@@ -1473,7 +1476,7 @@ ${middlewareExportCode}
|
|
|
1473
1476
|
// lgtm[js/bad-code-sanitization]
|
|
1474
1477
|
return ` ${JSON.stringify(nextFormatPattern)}: () => import(${JSON.stringify(absPath)})`;
|
|
1475
1478
|
});
|
|
1476
|
-
const appFileBase =
|
|
1479
|
+
const appFileBase = appFilePath?.replace(/\\/g, "/");
|
|
1477
1480
|
return `
|
|
1478
1481
|
import React from "react";
|
|
1479
1482
|
import { hydrateRoot } from "react-dom/client";
|
|
@@ -1666,8 +1669,10 @@ hydrate();
|
|
|
1666
1669
|
middlewarePath = findMiddlewareFile(root);
|
|
1667
1670
|
instrumentationPath = findInstrumentationFile(root);
|
|
1668
1671
|
// Load next.config.js if present (always from project root, not src/)
|
|
1669
|
-
const
|
|
1672
|
+
const phase = env?.command === "build" ? PHASE_PRODUCTION_BUILD : PHASE_DEVELOPMENT_SERVER;
|
|
1673
|
+
const rawConfig = await loadNextConfig(root, phase);
|
|
1670
1674
|
nextConfig = await resolveNextConfig(rawConfig);
|
|
1675
|
+
fileMatcher = createValidFileMatcher(nextConfig.pageExtensions);
|
|
1671
1676
|
// Merge env from next.config.js with NEXT_PUBLIC_* env vars
|
|
1672
1677
|
const defines = getNextPublicEnvDefines();
|
|
1673
1678
|
if (!config.define ||
|
|
@@ -2110,10 +2115,10 @@ hydrate();
|
|
|
2110
2115
|
}
|
|
2111
2116
|
// App Router virtual modules
|
|
2112
2117
|
if (id === RESOLVED_RSC_ENTRY && hasAppDir) {
|
|
2113
|
-
const routes = await appRouter(appDir);
|
|
2118
|
+
const routes = await appRouter(appDir, nextConfig?.pageExtensions, fileMatcher);
|
|
2114
2119
|
const metaRoutes = scanMetadataFiles(appDir);
|
|
2115
2120
|
// Check for global-error.tsx at app root
|
|
2116
|
-
const globalErrorPath = findFileWithExts(appDir, "global-error");
|
|
2121
|
+
const globalErrorPath = findFileWithExts(appDir, "global-error", fileMatcher);
|
|
2117
2122
|
return generateRscEntry(appDir, routes, middlewarePath, metaRoutes, globalErrorPath, nextConfig?.basePath, nextConfig?.trailingSlash, {
|
|
2118
2123
|
redirects: nextConfig?.redirects,
|
|
2119
2124
|
rewrites: nextConfig?.rewrites,
|
|
@@ -2216,15 +2221,14 @@ hydrate();
|
|
|
2216
2221
|
hotUpdate(options) {
|
|
2217
2222
|
if (!hasPagesDir || hasAppDir)
|
|
2218
2223
|
return;
|
|
2219
|
-
|
|
2220
|
-
if (options.file.startsWith(pagesDir) && ext.test(options.file)) {
|
|
2224
|
+
if (options.file.startsWith(pagesDir) && fileMatcher.extensionRegex.test(options.file)) {
|
|
2221
2225
|
options.server.environments.client.hot.send({ type: "full-reload" });
|
|
2222
2226
|
return [];
|
|
2223
2227
|
}
|
|
2224
2228
|
},
|
|
2225
2229
|
configureServer(server) {
|
|
2226
2230
|
// Watch pages directory for file additions/removals to invalidate route cache.
|
|
2227
|
-
const pageExtensions =
|
|
2231
|
+
const pageExtensions = fileMatcher.extensionRegex;
|
|
2228
2232
|
/**
|
|
2229
2233
|
* Invalidate the virtual RSC entry module in Vite's module graph.
|
|
2230
2234
|
*
|
|
@@ -2587,10 +2591,20 @@ hydrate();
|
|
|
2587
2591
|
return;
|
|
2588
2592
|
}
|
|
2589
2593
|
}
|
|
2590
|
-
// Apply middleware response headers
|
|
2594
|
+
// Apply middleware response headers. Unpack
|
|
2595
|
+
// x-middleware-request-* headers into req.headers so
|
|
2596
|
+
// config has/missing conditions and downstream handlers
|
|
2597
|
+
// see middleware-modified cookies and headers.
|
|
2591
2598
|
if (result.responseHeaders) {
|
|
2599
|
+
const mwReqPrefix = "x-middleware-request-";
|
|
2592
2600
|
for (const [key, value] of result.responseHeaders) {
|
|
2593
|
-
|
|
2601
|
+
if (key.startsWith(mwReqPrefix)) {
|
|
2602
|
+
const realName = key.slice(mwReqPrefix.length);
|
|
2603
|
+
req.headers[realName] = value;
|
|
2604
|
+
}
|
|
2605
|
+
else if (!key.startsWith("x-middleware-")) {
|
|
2606
|
+
res.appendHeader(key, value);
|
|
2607
|
+
}
|
|
2594
2608
|
}
|
|
2595
2609
|
}
|
|
2596
2610
|
// Apply middleware rewrite (URL and optional status code)
|
|
@@ -2639,7 +2653,7 @@ hydrate();
|
|
|
2639
2653
|
const resolvedPathname = resolvedUrl.split("?")[0];
|
|
2640
2654
|
if (resolvedPathname.startsWith("/api/") ||
|
|
2641
2655
|
resolvedPathname === "/api") {
|
|
2642
|
-
const apiRoutes = await apiRouter(pagesDir);
|
|
2656
|
+
const apiRoutes = await apiRouter(pagesDir, nextConfig?.pageExtensions, fileMatcher);
|
|
2643
2657
|
const handled = await handleApiRoute(server, req, res, resolvedUrl, apiRoutes);
|
|
2644
2658
|
if (handled)
|
|
2645
2659
|
return;
|
|
@@ -2651,7 +2665,7 @@ hydrate();
|
|
|
2651
2665
|
res.end("404 - API route not found");
|
|
2652
2666
|
return;
|
|
2653
2667
|
}
|
|
2654
|
-
const routes = await pagesRouter(pagesDir);
|
|
2668
|
+
const routes = await pagesRouter(pagesDir, nextConfig?.pageExtensions, fileMatcher);
|
|
2655
2669
|
// Apply afterFiles rewrites — these run after initial route matching
|
|
2656
2670
|
// If beforeFiles already rewrote the URL, afterFiles still run on the
|
|
2657
2671
|
// *resolved* pathname. Next.js applies these when route matching succeeds
|
|
@@ -2666,7 +2680,7 @@ hydrate();
|
|
|
2666
2680
|
await proxyExternalRewriteNode(req, res, resolvedUrl);
|
|
2667
2681
|
return;
|
|
2668
2682
|
}
|
|
2669
|
-
const handler = createSSRHandler(server, routes, pagesDir, nextConfig?.i18n);
|
|
2683
|
+
const handler = createSSRHandler(server, routes, pagesDir, nextConfig?.i18n, fileMatcher);
|
|
2670
2684
|
const mwStatus = req.__vinextRewriteStatus;
|
|
2671
2685
|
// Try rendering the resolved URL
|
|
2672
2686
|
const match = matchRoute(resolvedUrl.split("?")[0], routes);
|
|
@@ -2700,6 +2714,41 @@ hydrate();
|
|
|
2700
2714
|
};
|
|
2701
2715
|
},
|
|
2702
2716
|
},
|
|
2717
|
+
// Strip server-only data-fetching exports (getServerSideProps, getStaticProps,
|
|
2718
|
+
// getStaticPaths) from page modules in the client bundle. These functions
|
|
2719
|
+
// often import server-only modules (database drivers, fs, etc.) that would
|
|
2720
|
+
// break or bloat the client bundle. Next.js does this via an SWC transform
|
|
2721
|
+
// (next-ssg-transform); we use Vite's parseAst + MagicString.
|
|
2722
|
+
//
|
|
2723
|
+
// Only applies to client builds (not SSR) and only to files under the
|
|
2724
|
+
// pages/ directory.
|
|
2725
|
+
{
|
|
2726
|
+
name: "vinext:strip-server-exports",
|
|
2727
|
+
transform: {
|
|
2728
|
+
// Only match page source files, not node_modules
|
|
2729
|
+
filter: { id: /\.(tsx?|jsx?|mjs)$/ },
|
|
2730
|
+
handler(code, id) {
|
|
2731
|
+
const ssr = this.environment?.name !== "client";
|
|
2732
|
+
if (ssr)
|
|
2733
|
+
return null;
|
|
2734
|
+
if (!hasPagesDir)
|
|
2735
|
+
return null;
|
|
2736
|
+
// Only transform files under the pages/ directory
|
|
2737
|
+
if (!id.startsWith(pagesDir))
|
|
2738
|
+
return null;
|
|
2739
|
+
// Skip API routes, _app, _document, _error
|
|
2740
|
+
const relativePath = id.slice(pagesDir.length);
|
|
2741
|
+
if (relativePath.startsWith("/api/") || relativePath === "/api")
|
|
2742
|
+
return null;
|
|
2743
|
+
if (/\/_(?:app|document|error)\b/.test(relativePath))
|
|
2744
|
+
return null;
|
|
2745
|
+
const result = stripServerExports(code);
|
|
2746
|
+
if (!result)
|
|
2747
|
+
return null;
|
|
2748
|
+
return { code: result, map: null };
|
|
2749
|
+
},
|
|
2750
|
+
},
|
|
2751
|
+
},
|
|
2703
2752
|
// Local image import transform:
|
|
2704
2753
|
// When a source file imports a local image (e.g., `import hero from './hero.jpg'`),
|
|
2705
2754
|
// this plugin transforms the default import to a StaticImageData object with
|
|
@@ -3342,6 +3391,7 @@ hydrate();
|
|
|
3342
3391
|
" Cache-Control: public, max-age=31536000, immutable",
|
|
3343
3392
|
"",
|
|
3344
3393
|
].join("\n");
|
|
3394
|
+
fs.mkdirSync(clientDir, { recursive: true });
|
|
3345
3395
|
fs.writeFileSync(headersPath, headersContent);
|
|
3346
3396
|
}
|
|
3347
3397
|
},
|
|
@@ -3400,6 +3450,101 @@ function extractConstraint(str, re) {
|
|
|
3400
3450
|
* :param+ — matches one or more segments
|
|
3401
3451
|
* (regex) — inline regex patterns in the source
|
|
3402
3452
|
*/
|
|
3453
|
+
/**
|
|
3454
|
+
* Strip server-only data-fetching exports from a page module's source code.
|
|
3455
|
+
* Returns the transformed code, or null if no changes were made.
|
|
3456
|
+
*
|
|
3457
|
+
* Handles:
|
|
3458
|
+
* - export (async) function getServerSideProps(...) { ... }
|
|
3459
|
+
* - export const getStaticProps = async (...) => { ... }
|
|
3460
|
+
* - export const getServerSideProps = someHelper;
|
|
3461
|
+
*/
|
|
3462
|
+
/**
|
|
3463
|
+
* Skip past balanced brackets/parens/braces starting at `pos` (which should
|
|
3464
|
+
* point to the opening bracket). Returns the position AFTER the closing bracket.
|
|
3465
|
+
* Handles nested brackets, string literals, and comments.
|
|
3466
|
+
*/
|
|
3467
|
+
/**
|
|
3468
|
+
* Strip server-only data-fetching exports (getServerSideProps,
|
|
3469
|
+
* getStaticProps, getStaticPaths) from page modules for the client
|
|
3470
|
+
* bundle. Uses Vite's parseAst (Rollup/acorn) for correct handling
|
|
3471
|
+
* of all export patterns including function expressions, arrow
|
|
3472
|
+
* functions with TS return types, and re-exports.
|
|
3473
|
+
*
|
|
3474
|
+
* Modeled after Next.js's SWC `next-ssg-transform`.
|
|
3475
|
+
*/
|
|
3476
|
+
function stripServerExports(code) {
|
|
3477
|
+
const SERVER_EXPORTS = new Set(["getServerSideProps", "getStaticProps", "getStaticPaths"]);
|
|
3478
|
+
if (![...SERVER_EXPORTS].some(name => code.includes(name)))
|
|
3479
|
+
return null;
|
|
3480
|
+
let ast;
|
|
3481
|
+
try {
|
|
3482
|
+
ast = parseAst(code);
|
|
3483
|
+
}
|
|
3484
|
+
catch {
|
|
3485
|
+
// If parsing fails (shouldn't happen post-JSX/TS transform), bail out
|
|
3486
|
+
return null;
|
|
3487
|
+
}
|
|
3488
|
+
const s = new MagicString(code);
|
|
3489
|
+
let changed = false;
|
|
3490
|
+
for (const node of ast.body) {
|
|
3491
|
+
if (node.type !== "ExportNamedDeclaration")
|
|
3492
|
+
continue;
|
|
3493
|
+
// Case 1: export function name() {} / export async function name() {}
|
|
3494
|
+
// Case 2: export const/let/var name = ...
|
|
3495
|
+
if (node.declaration) {
|
|
3496
|
+
const decl = node.declaration;
|
|
3497
|
+
if (decl.type === "FunctionDeclaration" && SERVER_EXPORTS.has(decl.id?.name)) {
|
|
3498
|
+
s.overwrite(node.start, node.end, `export function ${decl.id.name}() { return { props: {} }; }`);
|
|
3499
|
+
changed = true;
|
|
3500
|
+
}
|
|
3501
|
+
else if (decl.type === "VariableDeclaration") {
|
|
3502
|
+
for (const declarator of decl.declarations) {
|
|
3503
|
+
if (declarator.id?.type === "Identifier" && SERVER_EXPORTS.has(declarator.id.name)) {
|
|
3504
|
+
s.overwrite(node.start, node.end, `export const ${declarator.id.name} = undefined;`);
|
|
3505
|
+
changed = true;
|
|
3506
|
+
}
|
|
3507
|
+
}
|
|
3508
|
+
}
|
|
3509
|
+
continue;
|
|
3510
|
+
}
|
|
3511
|
+
// Case 3: export { getServerSideProps } or export { getServerSideProps as gSSP }
|
|
3512
|
+
if (node.specifiers && node.specifiers.length > 0 && !node.source) {
|
|
3513
|
+
const kept = [];
|
|
3514
|
+
const stripped = [];
|
|
3515
|
+
for (const spec of node.specifiers) {
|
|
3516
|
+
// spec.local.name is the binding name, spec.exported.name is the export name
|
|
3517
|
+
const exportedName = spec.exported?.name ?? spec.exported?.value;
|
|
3518
|
+
if (SERVER_EXPORTS.has(exportedName)) {
|
|
3519
|
+
stripped.push(exportedName);
|
|
3520
|
+
}
|
|
3521
|
+
else {
|
|
3522
|
+
kept.push(spec);
|
|
3523
|
+
}
|
|
3524
|
+
}
|
|
3525
|
+
if (stripped.length > 0) {
|
|
3526
|
+
// Build replacement: keep non-server specifiers, add stubs for stripped ones
|
|
3527
|
+
const parts = [];
|
|
3528
|
+
if (kept.length > 0) {
|
|
3529
|
+
const keptStr = kept.map((sp) => {
|
|
3530
|
+
const local = sp.local.name;
|
|
3531
|
+
const exported = sp.exported?.name ?? sp.exported?.value;
|
|
3532
|
+
return local === exported ? local : `${local} as ${exported}`;
|
|
3533
|
+
}).join(", ");
|
|
3534
|
+
parts.push(`export { ${keptStr} };`);
|
|
3535
|
+
}
|
|
3536
|
+
for (const name of stripped) {
|
|
3537
|
+
parts.push(`export const ${name} = undefined;`);
|
|
3538
|
+
}
|
|
3539
|
+
s.overwrite(node.start, node.end, parts.join("\n"));
|
|
3540
|
+
changed = true;
|
|
3541
|
+
}
|
|
3542
|
+
}
|
|
3543
|
+
}
|
|
3544
|
+
if (!changed)
|
|
3545
|
+
return null;
|
|
3546
|
+
return s.toString();
|
|
3547
|
+
}
|
|
3403
3548
|
export function matchConfigPattern(pathname, pattern) {
|
|
3404
3549
|
// If the pattern contains regex groups like (\\d+) or (.*), use regex matching.
|
|
3405
3550
|
// Also enter this branch when a catch-all parameter (:param* or :param+) is
|
|
@@ -3610,16 +3755,44 @@ function applyRewrites(pathname, rewrites, ctx) {
|
|
|
3610
3755
|
function applyHeaders(pathname, res, headers, ctx) {
|
|
3611
3756
|
const matched = matchHeaders(pathname, headers, ctx);
|
|
3612
3757
|
for (const header of matched) {
|
|
3613
|
-
|
|
3758
|
+
// Use append semantics for headers where multiple values must coexist
|
|
3759
|
+
// (Vary, Set-Cookie). Using setHeader() on these would destroy
|
|
3760
|
+
// existing values like "Vary: RSC, Accept".
|
|
3761
|
+
const lk = header.key.toLowerCase();
|
|
3762
|
+
if (lk === "set-cookie") {
|
|
3763
|
+
// Node.js res.getHeader("set-cookie") returns string[] when
|
|
3764
|
+
// multiple Set-Cookie headers have been set. Preserve the array.
|
|
3765
|
+
const existing = res.getHeader(lk);
|
|
3766
|
+
if (Array.isArray(existing)) {
|
|
3767
|
+
res.setHeader(header.key, [...existing, header.value]);
|
|
3768
|
+
}
|
|
3769
|
+
else if (existing) {
|
|
3770
|
+
res.setHeader(header.key, [String(existing), header.value]);
|
|
3771
|
+
}
|
|
3772
|
+
else {
|
|
3773
|
+
res.setHeader(header.key, header.value);
|
|
3774
|
+
}
|
|
3775
|
+
}
|
|
3776
|
+
else if (lk === "vary") {
|
|
3777
|
+
const existing = res.getHeader(lk);
|
|
3778
|
+
if (existing) {
|
|
3779
|
+
res.setHeader(header.key, existing + ", " + header.value);
|
|
3780
|
+
}
|
|
3781
|
+
else {
|
|
3782
|
+
res.setHeader(header.key, header.value);
|
|
3783
|
+
}
|
|
3784
|
+
}
|
|
3785
|
+
else {
|
|
3786
|
+
res.setHeader(header.key, header.value);
|
|
3787
|
+
}
|
|
3614
3788
|
}
|
|
3615
3789
|
}
|
|
3616
3790
|
/**
|
|
3617
3791
|
* Find a file by name (without extension) in a directory.
|
|
3618
|
-
* Checks
|
|
3792
|
+
* Checks the configured page extensions.
|
|
3619
3793
|
*/
|
|
3620
|
-
function findFileWithExts(dir, name) {
|
|
3621
|
-
const
|
|
3622
|
-
for (const ext of extensions) {
|
|
3794
|
+
function findFileWithExts(dir, name, matcher) {
|
|
3795
|
+
for (const ext of matcher.dottedExtensions) {
|
|
3623
3796
|
const filePath = path.join(dir, name + ext);
|
|
3624
3797
|
if (fs.existsSync(filePath))
|
|
3625
3798
|
return filePath;
|
|
@@ -3664,4 +3837,5 @@ export { staticExportPages, staticExportApp } from "./build/static-export.js";
|
|
|
3664
3837
|
export { clientManualChunks, clientOutputConfig, clientTreeshakeConfig, computeLazyChunks };
|
|
3665
3838
|
export { resolvePostcssStringPlugins as _resolvePostcssStringPlugins };
|
|
3666
3839
|
export { parseStaticObjectLiteral as _parseStaticObjectLiteral };
|
|
3840
|
+
export { stripServerExports as _stripServerExports };
|
|
3667
3841
|
//# sourceMappingURL=index.js.map
|