vinext 0.0.23 → 0.0.25
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 +24 -0
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +3 -2
- package/dist/check.js.map +1 -1
- package/dist/client/entry.js +1 -1
- package/dist/client/entry.js.map +1 -1
- package/dist/config/config-matchers.d.ts +21 -0
- package/dist/config/config-matchers.d.ts.map +1 -1
- package/dist/config/config-matchers.js +59 -9
- package/dist/config/config-matchers.js.map +1 -1
- package/dist/config/next-config.d.ts +8 -2
- package/dist/config/next-config.d.ts.map +1 -1
- package/dist/config/next-config.js +90 -35
- package/dist/config/next-config.js.map +1 -1
- package/dist/deploy.d.ts +10 -0
- package/dist/deploy.d.ts.map +1 -1
- package/dist/deploy.js +140 -56
- package/dist/deploy.js.map +1 -1
- package/dist/index.d.ts +14 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +195 -25
- package/dist/index.js.map +1 -1
- package/dist/plugins/async-hooks-stub.d.ts +16 -0
- package/dist/plugins/async-hooks-stub.d.ts.map +1 -0
- package/dist/plugins/async-hooks-stub.js +45 -0
- package/dist/plugins/async-hooks-stub.js.map +1 -0
- package/dist/routing/app-router.d.ts +12 -6
- package/dist/routing/app-router.d.ts.map +1 -1
- package/dist/routing/app-router.js +19 -40
- package/dist/routing/app-router.js.map +1 -1
- package/dist/routing/pages-router.d.ts.map +1 -1
- package/dist/routing/pages-router.js +3 -9
- package/dist/routing/pages-router.js.map +1 -1
- package/dist/routing/utils.d.ts +9 -0
- package/dist/routing/utils.d.ts.map +1 -1
- package/dist/routing/utils.js +10 -0
- package/dist/routing/utils.js.map +1 -1
- package/dist/server/api-handler.d.ts.map +1 -1
- package/dist/server/api-handler.js +6 -0
- package/dist/server/api-handler.js.map +1 -1
- package/dist/server/app-dev-server.d.ts +2 -2
- package/dist/server/app-dev-server.d.ts.map +1 -1
- package/dist/server/app-dev-server.js +294 -133
- package/dist/server/app-dev-server.js.map +1 -1
- package/dist/server/dev-module-runner.d.ts +84 -0
- package/dist/server/dev-module-runner.d.ts.map +1 -0
- package/dist/server/dev-module-runner.js +105 -0
- package/dist/server/dev-module-runner.js.map +1 -0
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/instrumentation.d.ts +52 -9
- package/dist/server/instrumentation.d.ts.map +1 -1
- package/dist/server/instrumentation.js +52 -15
- package/dist/server/instrumentation.js.map +1 -1
- package/dist/server/middleware.d.ts +7 -3
- package/dist/server/middleware.d.ts.map +1 -1
- package/dist/server/middleware.js +16 -6
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/prod-server.d.ts +8 -2
- package/dist/server/prod-server.d.ts.map +1 -1
- package/dist/server/prod-server.js +56 -35
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/worker-utils.d.ts +15 -0
- package/dist/server/worker-utils.d.ts.map +1 -0
- package/dist/server/worker-utils.js +41 -0
- package/dist/server/worker-utils.js.map +1 -0
- package/dist/shims/cache.d.ts.map +1 -1
- package/dist/shims/cache.js +14 -2
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/fetch-cache.d.ts.map +1 -1
- package/dist/shims/fetch-cache.js +139 -29
- package/dist/shims/fetch-cache.js.map +1 -1
- package/dist/shims/form.d.ts.map +1 -1
- package/dist/shims/form.js +2 -3
- package/dist/shims/form.js.map +1 -1
- package/dist/shims/headers.d.ts +6 -0
- package/dist/shims/headers.d.ts.map +1 -1
- package/dist/shims/headers.js +8 -0
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/layout-segment-context.d.ts +5 -4
- package/dist/shims/layout-segment-context.d.ts.map +1 -1
- package/dist/shims/layout-segment-context.js +6 -5
- package/dist/shims/layout-segment-context.js.map +1 -1
- package/dist/shims/link.d.ts.map +1 -1
- package/dist/shims/link.js +32 -17
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/navigation.d.ts +14 -11
- package/dist/shims/navigation.d.ts.map +1 -1
- package/dist/shims/navigation.js +122 -102
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/router.d.ts.map +1 -1
- package/dist/shims/router.js +37 -21
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/server.d.ts +2 -0
- package/dist/shims/server.d.ts.map +1 -1
- package/dist/shims/server.js +4 -0
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/url-utils.d.ts +13 -0
- package/dist/shims/url-utils.d.ts.map +1 -0
- package/dist/shims/url-utils.js +28 -0
- package/dist/shims/url-utils.js.map +1 -0
- package/dist/utils/project.d.ts +13 -1
- package/dist/utils/project.d.ts.map +1 -1
- package/dist/utils/project.js +63 -13
- package/dist/utils/project.js.map +1 -1
- package/package.json +6 -1
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { appRouter, invalidateAppRouteCache } from "./routing/app-router.js";
|
|
|
4
4
|
import { createValidFileMatcher } from "./routing/file-matcher.js";
|
|
5
5
|
import { createSSRHandler } from "./server/dev-server.js";
|
|
6
6
|
import { handleApiRoute } from "./server/api-handler.js";
|
|
7
|
+
import { createDirectRunner } from "./server/dev-module-runner.js";
|
|
7
8
|
import { generateRscEntry, generateSsrEntry, generateBrowserEntry, } from "./server/app-dev-server.js";
|
|
8
9
|
import { loadNextConfig, resolveNextConfig, } from "./config/next-config.js";
|
|
9
10
|
import { findMiddlewareFile, isProxyFile, runMiddleware } from "./server/middleware.js";
|
|
@@ -16,7 +17,9 @@ import { validateDevRequest } from "./server/dev-origin-check.js";
|
|
|
16
17
|
import { safeRegExp, isExternalUrl, proxyExternalRequest, parseCookies, matchHeaders, matchRedirect, matchRewrite, } from "./config/config-matchers.js";
|
|
17
18
|
import { scanMetadataFiles } from "./server/metadata-routes.js";
|
|
18
19
|
import { detectPackageManager } from "./utils/project.js";
|
|
20
|
+
import { asyncHooksStubPlugin } from "./plugins/async-hooks-stub.js";
|
|
19
21
|
import tsconfigPaths from "vite-tsconfig-paths";
|
|
22
|
+
import react from "@vitejs/plugin-react";
|
|
20
23
|
import MagicString from "magic-string";
|
|
21
24
|
import path from "node:path";
|
|
22
25
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
@@ -566,10 +569,35 @@ export default function vinext(options = {}) {
|
|
|
566
569
|
contentSecurityPolicy: nextConfig?.images?.contentSecurityPolicy,
|
|
567
570
|
},
|
|
568
571
|
});
|
|
572
|
+
// Generate instrumentation code if instrumentation.ts exists.
|
|
573
|
+
// For production (Cloudflare Workers), instrumentation.ts is bundled into the
|
|
574
|
+
// Worker and register() is called as a top-level await at module evaluation time —
|
|
575
|
+
// before any request is handled. This mirrors App Router behavior (generateRscEntry)
|
|
576
|
+
// and matches Next.js semantics: register() runs once on startup in the process
|
|
577
|
+
// that handles requests.
|
|
578
|
+
//
|
|
579
|
+
// The onRequestError handler is stored on globalThis so it is visible across
|
|
580
|
+
// all code within the Worker (same global scope).
|
|
581
|
+
const instrumentationImportCode = instrumentationPath
|
|
582
|
+
? `import * as _instrumentation from ${JSON.stringify(instrumentationPath.replace(/\\/g, "/"))};`
|
|
583
|
+
: "";
|
|
584
|
+
const instrumentationInitCode = instrumentationPath
|
|
585
|
+
? `// Run instrumentation register() once at module evaluation time — before any
|
|
586
|
+
// requests are handled. Matches Next.js semantics: register() is called once
|
|
587
|
+
// on startup in the process that handles requests.
|
|
588
|
+
if (typeof _instrumentation.register === "function") {
|
|
589
|
+
await _instrumentation.register();
|
|
590
|
+
}
|
|
591
|
+
// Store the onRequestError handler on globalThis so it is visible to all
|
|
592
|
+
// code within the Worker (same global scope).
|
|
593
|
+
if (typeof _instrumentation.onRequestError === "function") {
|
|
594
|
+
globalThis.__VINEXT_onRequestErrorHandler__ = _instrumentation.onRequestError;
|
|
595
|
+
}`
|
|
596
|
+
: "";
|
|
569
597
|
// Generate middleware code if middleware.ts exists
|
|
570
598
|
const middlewareImportCode = middlewarePath
|
|
571
599
|
? `import * as middlewareModule from ${JSON.stringify(middlewarePath.replace(/\\/g, "/"))};
|
|
572
|
-
import { NextRequest } from "next/server";`
|
|
600
|
+
import { NextRequest, NextFetchEvent } from "next/server";`
|
|
573
601
|
: "";
|
|
574
602
|
// The matcher config is read from the middleware module at import time.
|
|
575
603
|
// We inline the matching + execution logic so the prod server can call it.
|
|
@@ -580,7 +608,7 @@ ${generateNormalizePathCode("es5")}
|
|
|
580
608
|
${generateSafeRegExpCode("es5")}
|
|
581
609
|
${generateMiddlewareMatcherCode("es5")}
|
|
582
610
|
|
|
583
|
-
export async function runMiddleware(request) {
|
|
611
|
+
export async function runMiddleware(request, ctx) {
|
|
584
612
|
var isProxy = ${middlewarePath ? JSON.stringify(isProxyFile(middlewarePath)) : "false"};
|
|
585
613
|
var middlewareFn = isProxy
|
|
586
614
|
? (middlewareModule.proxy ?? middlewareModule.default)
|
|
@@ -614,12 +642,14 @@ export async function runMiddleware(request) {
|
|
|
614
642
|
mwRequest = new Request(mwUrl, request);
|
|
615
643
|
}
|
|
616
644
|
var nextRequest = mwRequest instanceof NextRequest ? mwRequest : new NextRequest(mwRequest);
|
|
645
|
+
var fetchEvent = new NextFetchEvent({ page: normalizedPathname });
|
|
617
646
|
var response;
|
|
618
|
-
try { response = await middlewareFn(nextRequest); }
|
|
647
|
+
try { response = await middlewareFn(nextRequest, fetchEvent); }
|
|
619
648
|
catch (e) {
|
|
620
649
|
console.error("[vinext] Middleware error:", e);
|
|
621
650
|
return { continue: false, response: new Response("Internal Server Error", { status: 500 }) };
|
|
622
651
|
}
|
|
652
|
+
if (ctx && typeof ctx.waitUntil === "function") { ctx.waitUntil(fetchEvent.drainWaitUntil()); } else { fetchEvent.drainWaitUntil(); }
|
|
623
653
|
|
|
624
654
|
if (!response) return { continue: true };
|
|
625
655
|
|
|
@@ -677,8 +707,11 @@ import { runWithHeadState } from "vinext/head-state";
|
|
|
677
707
|
import { safeJsonStringify } from "vinext/html";
|
|
678
708
|
import { getSSRFontLinks as _getSSRFontLinks, getSSRFontStyles as _getSSRFontStylesGoogle, getSSRFontPreloads as _getSSRFontPreloadsGoogle } from "next/font/google";
|
|
679
709
|
import { getSSRFontStyles as _getSSRFontStylesLocal, getSSRFontPreloads as _getSSRFontPreloadsLocal } from "next/font/local";
|
|
710
|
+
${instrumentationImportCode}
|
|
680
711
|
${middlewareImportCode}
|
|
681
712
|
|
|
713
|
+
${instrumentationInitCode}
|
|
714
|
+
|
|
682
715
|
// i18n config (embedded at build time)
|
|
683
716
|
const i18nConfig = ${i18nConfigJson};
|
|
684
717
|
|
|
@@ -1597,10 +1630,15 @@ hydrate();
|
|
|
1597
1630
|
// Shared state for the MDX proxy plugin. Populated during config() if MDX
|
|
1598
1631
|
// files are detected and @mdx-js/rollup is installed.
|
|
1599
1632
|
let mdxDelegate = null;
|
|
1633
|
+
const reactPlugin = options.react === false
|
|
1634
|
+
? false
|
|
1635
|
+
: react(options.react === true ? undefined : options.react);
|
|
1600
1636
|
const plugins = [
|
|
1601
1637
|
// Resolve tsconfig paths/baseUrl aliases so real-world Next.js repos
|
|
1602
1638
|
// that use @/*, #/*, or baseUrl imports work out of the box.
|
|
1603
1639
|
tsconfigPaths(),
|
|
1640
|
+
// React Fast Refresh + JSX transform for client components.
|
|
1641
|
+
reactPlugin,
|
|
1604
1642
|
// Transform CJS require()/module.exports to ESM before other plugins
|
|
1605
1643
|
// analyze imports (RSC directive scanning, shim resolution, etc.)
|
|
1606
1644
|
commonjs(),
|
|
@@ -1671,7 +1709,7 @@ hydrate();
|
|
|
1671
1709
|
// Load next.config.js if present (always from project root, not src/)
|
|
1672
1710
|
const phase = env?.command === "build" ? PHASE_PRODUCTION_BUILD : PHASE_DEVELOPMENT_SERVER;
|
|
1673
1711
|
const rawConfig = await loadNextConfig(root, phase);
|
|
1674
|
-
nextConfig = await resolveNextConfig(rawConfig);
|
|
1712
|
+
nextConfig = await resolveNextConfig(rawConfig, root);
|
|
1675
1713
|
fileMatcher = createValidFileMatcher(nextConfig.pageExtensions);
|
|
1676
1714
|
// Merge env from next.config.js with NEXT_PUBLIC_* env vars
|
|
1677
1715
|
const defines = getNextPublicEnvDefines();
|
|
@@ -1711,6 +1749,7 @@ hydrate();
|
|
|
1711
1749
|
// Build the shim alias map — used by both resolve.alias and resolveId
|
|
1712
1750
|
// (resolveId handles .js extension variants for libraries like nuqs)
|
|
1713
1751
|
nextShimMap = {
|
|
1752
|
+
...nextConfig.aliases,
|
|
1714
1753
|
"next/link": path.join(shimsDir, "link"),
|
|
1715
1754
|
"next/head": path.join(shimsDir, "head"),
|
|
1716
1755
|
"next/router": path.join(shimsDir, "router"),
|
|
@@ -1888,12 +1927,21 @@ hydrate();
|
|
|
1888
1927
|
origin: /^https?:\/\/(?:(?:[^:]+\.)?localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/,
|
|
1889
1928
|
},
|
|
1890
1929
|
},
|
|
1891
|
-
//
|
|
1892
|
-
//
|
|
1930
|
+
// Configure SSR transform behaviour for Node targets.
|
|
1931
|
+
// - `external`: React packages are loaded natively by Node (CJS)
|
|
1932
|
+
// rather than through Vite's ESM evaluator.
|
|
1933
|
+
// - `noExternal: true`: force everything else through Vite's
|
|
1934
|
+
// transform pipeline so non-JS imports (CSS, images) from
|
|
1935
|
+
// node_modules don't hit Node's native ESM loader.
|
|
1936
|
+
// Any user-provided `ssr.noExternal` is intentionally superseded
|
|
1937
|
+
// by this setting; only `ssr.external` entries escape Vite's transform.
|
|
1893
1938
|
// Skip when targeting bundled runtimes (Cloudflare/Nitro bundle everything).
|
|
1939
|
+
// This also resolves extensionless-import issues in packages like
|
|
1940
|
+
// `validator` (see #189) by routing them through Vite's resolver.
|
|
1894
1941
|
...(hasCloudflarePlugin || hasNitroPlugin ? {} : {
|
|
1895
1942
|
ssr: {
|
|
1896
1943
|
external: ["react", "react-dom", "react-dom/server"],
|
|
1944
|
+
noExternal: true,
|
|
1897
1945
|
},
|
|
1898
1946
|
}),
|
|
1899
1947
|
resolve: {
|
|
@@ -1928,6 +1976,17 @@ hydrate();
|
|
|
1928
1976
|
// Inject resolved PostCSS plugins if string names were found
|
|
1929
1977
|
...(postcssOverride ? { css: { postcss: postcssOverride } } : {}),
|
|
1930
1978
|
};
|
|
1979
|
+
// Collect user-provided ssr.external so we can propagate it into
|
|
1980
|
+
// both the RSC and SSR environment configs. Vite's `ssr.*` config
|
|
1981
|
+
// only applies to the default `ssr` environment, not custom ones
|
|
1982
|
+
// like `rsc`. Native addon packages (e.g. better-sqlite3) listed
|
|
1983
|
+
// in ssr.external must be externalized from ALL server environments.
|
|
1984
|
+
// Vite's SSROptions.external is `string[] | true`; handle both forms.
|
|
1985
|
+
const userSsrExternal = Array.isArray(config.ssr?.external)
|
|
1986
|
+
? config.ssr.external
|
|
1987
|
+
: config.ssr?.external === true
|
|
1988
|
+
? true
|
|
1989
|
+
: [];
|
|
1931
1990
|
// If app/ directory exists, configure RSC environments
|
|
1932
1991
|
if (hasAppDir) {
|
|
1933
1992
|
// Compute optimizeDeps.entries so Vite discovers server-side
|
|
@@ -1950,11 +2009,19 @@ hydrate();
|
|
|
1950
2009
|
// Note: Do NOT externalize react/react-dom here — they must
|
|
1951
2010
|
// be bundled with the "react-server" condition for RSC.
|
|
1952
2011
|
// Skip when targeting bundled runtimes (Cloudflare/Nitro).
|
|
1953
|
-
external: [
|
|
2012
|
+
external: userSsrExternal === true ? true : [
|
|
1954
2013
|
"satori",
|
|
1955
2014
|
"@resvg/resvg-js",
|
|
1956
2015
|
"yoga-wasm-web",
|
|
2016
|
+
...userSsrExternal,
|
|
1957
2017
|
],
|
|
2018
|
+
// Force all node_modules through Vite's transform pipeline
|
|
2019
|
+
// so non-JS imports (CSS, images) don't hit Node's native
|
|
2020
|
+
// ESM loader. Matches Next.js behavior of bundling everything.
|
|
2021
|
+
// Packages in `external` above take precedence per Vite rules.
|
|
2022
|
+
// When user sets `ssr.external: true`, skip noExternal since
|
|
2023
|
+
// everything is already externalized.
|
|
2024
|
+
...(userSsrExternal === true ? {} : { noExternal: true }),
|
|
1958
2025
|
},
|
|
1959
2026
|
}),
|
|
1960
2027
|
optimizeDeps: {
|
|
@@ -1969,6 +2036,17 @@ hydrate();
|
|
|
1969
2036
|
},
|
|
1970
2037
|
},
|
|
1971
2038
|
ssr: {
|
|
2039
|
+
...(hasCloudflarePlugin || hasNitroPlugin ? {} : {
|
|
2040
|
+
resolve: {
|
|
2041
|
+
external: userSsrExternal === true ? true : [...userSsrExternal],
|
|
2042
|
+
// Force all node_modules through Vite's transform pipeline
|
|
2043
|
+
// so non-JS imports (CSS, images) don't hit Node's native
|
|
2044
|
+
// ESM loader. Matches Next.js behavior of bundling everything.
|
|
2045
|
+
// When user sets `ssr.external: true`, skip noExternal since
|
|
2046
|
+
// everything is already externalized.
|
|
2047
|
+
...(userSsrExternal === true ? {} : { noExternal: true }),
|
|
2048
|
+
},
|
|
2049
|
+
}),
|
|
1972
2050
|
optimizeDeps: {
|
|
1973
2051
|
exclude: ["vinext"],
|
|
1974
2052
|
entries: appEntries,
|
|
@@ -1981,6 +2059,13 @@ hydrate();
|
|
|
1981
2059
|
},
|
|
1982
2060
|
},
|
|
1983
2061
|
client: {
|
|
2062
|
+
// Explicitly mark as client consumer so other plugins (e.g. Nitro)
|
|
2063
|
+
// can detect this during configEnvironment hooks — before Vite
|
|
2064
|
+
// applies the default consumer based on environment name.
|
|
2065
|
+
// Without this, Nitro's configEnvironment creates a server-side
|
|
2066
|
+
// service for the client environment, causing virtual module
|
|
2067
|
+
// imports to leak to Node's native ESM loader (ERR_UNSUPPORTED_ESM_URL_SCHEME).
|
|
2068
|
+
consumer: "client",
|
|
1984
2069
|
optimizeDeps: {
|
|
1985
2070
|
exclude: ["vinext"],
|
|
1986
2071
|
// React packages aren't crawled from app/ source files,
|
|
@@ -2018,6 +2103,7 @@ hydrate();
|
|
|
2018
2103
|
// and there's no client-side hydration.
|
|
2019
2104
|
viteConfig.environments = {
|
|
2020
2105
|
client: {
|
|
2106
|
+
consumer: "client",
|
|
2021
2107
|
build: {
|
|
2022
2108
|
manifest: true,
|
|
2023
2109
|
ssrManifest: true,
|
|
@@ -2124,8 +2210,8 @@ hydrate();
|
|
|
2124
2210
|
rewrites: nextConfig?.rewrites,
|
|
2125
2211
|
headers: nextConfig?.headers,
|
|
2126
2212
|
allowedOrigins: nextConfig?.serverActionsAllowedOrigins,
|
|
2127
|
-
allowedDevOrigins: nextConfig?.
|
|
2128
|
-
});
|
|
2213
|
+
allowedDevOrigins: nextConfig?.allowedDevOrigins,
|
|
2214
|
+
}, instrumentationPath);
|
|
2129
2215
|
}
|
|
2130
2216
|
if (id === RESOLVED_APP_SSR_ENTRY && hasAppDir) {
|
|
2131
2217
|
return generateSsrEntry();
|
|
@@ -2135,6 +2221,8 @@ hydrate();
|
|
|
2135
2221
|
}
|
|
2136
2222
|
},
|
|
2137
2223
|
},
|
|
2224
|
+
// Stub node:async_hooks in client builds — see src/plugins/async-hooks-stub.ts
|
|
2225
|
+
asyncHooksStubPlugin,
|
|
2138
2226
|
// Proxy plugin for @mdx-js/rollup. The real MDX plugin is created lazily
|
|
2139
2227
|
// during vinext:config's config() (when MDX files are detected), but
|
|
2140
2228
|
// plugins returned from config() hooks run too late in the pipeline —
|
|
@@ -2212,12 +2300,11 @@ hydrate();
|
|
|
2212
2300
|
{
|
|
2213
2301
|
name: "vinext:pages-router",
|
|
2214
2302
|
// HMR: trigger full-reload for Pages Router page changes.
|
|
2215
|
-
//
|
|
2216
|
-
//
|
|
2217
|
-
//
|
|
2218
|
-
//
|
|
2219
|
-
//
|
|
2220
|
-
// ensures changes are always reflected in the browser.
|
|
2303
|
+
// Even with @vitejs/plugin-react providing React Fast Refresh,
|
|
2304
|
+
// the Pages Router injects hydration via inline <script type="module">
|
|
2305
|
+
// which may not be tracked in Vite's module graph. Explicitly
|
|
2306
|
+
// sending full-reload ensures changes are always reflected in
|
|
2307
|
+
// the browser.
|
|
2221
2308
|
hotUpdate(options) {
|
|
2222
2309
|
if (!hasPagesDir || hasAppDir)
|
|
2223
2310
|
return;
|
|
@@ -2229,6 +2316,32 @@ hydrate();
|
|
|
2229
2316
|
configureServer(server) {
|
|
2230
2317
|
// Watch pages directory for file additions/removals to invalidate route cache.
|
|
2231
2318
|
const pageExtensions = fileMatcher.extensionRegex;
|
|
2319
|
+
// Build a long-lived ModuleRunner for loading all Pages Router modules
|
|
2320
|
+
// (middleware, API routes, SSR page rendering) on every request.
|
|
2321
|
+
//
|
|
2322
|
+
// We must NOT use server.ssrLoadModule() here: when @cloudflare/vite-plugin
|
|
2323
|
+
// is present its environments replace the SSR transport, causing
|
|
2324
|
+
// SSRCompatModuleRunner to crash with:
|
|
2325
|
+
// TypeError: Cannot read properties of undefined (reading 'outsideEmitter')
|
|
2326
|
+
// on the very first request.
|
|
2327
|
+
//
|
|
2328
|
+
// createDirectRunner() builds a runner on environment.fetchModule() which
|
|
2329
|
+
// is a plain async method — safe with all plugin combinations, including
|
|
2330
|
+
// @cloudflare/vite-plugin.
|
|
2331
|
+
//
|
|
2332
|
+
// The runner is created lazily on first use so that all environments are
|
|
2333
|
+
// fully registered before we inspect them. We prefer "ssr", then any
|
|
2334
|
+
// non-"rsc" environment, then whatever is available.
|
|
2335
|
+
let pagesRunner = null;
|
|
2336
|
+
function getPagesRunner() {
|
|
2337
|
+
if (!pagesRunner) {
|
|
2338
|
+
const env = server.environments["ssr"] ??
|
|
2339
|
+
Object.values(server.environments).find((e) => e !== server.environments["rsc"]) ??
|
|
2340
|
+
Object.values(server.environments)[0];
|
|
2341
|
+
pagesRunner = createDirectRunner(env);
|
|
2342
|
+
}
|
|
2343
|
+
return pagesRunner;
|
|
2344
|
+
}
|
|
2232
2345
|
/**
|
|
2233
2346
|
* Invalidate the virtual RSC entry module in Vite's module graph.
|
|
2234
2347
|
*
|
|
@@ -2266,12 +2379,6 @@ hydrate();
|
|
|
2266
2379
|
invalidateRscEntryModule();
|
|
2267
2380
|
}
|
|
2268
2381
|
});
|
|
2269
|
-
// Run instrumentation.ts register() if present (once at server startup)
|
|
2270
|
-
if (instrumentationPath) {
|
|
2271
|
-
runInstrumentation(server, instrumentationPath).catch((err) => {
|
|
2272
|
-
console.error("[vinext] Instrumentation error:", err);
|
|
2273
|
-
});
|
|
2274
|
-
}
|
|
2275
2382
|
// ── Dev request origin check ─────────────────────────────────────
|
|
2276
2383
|
// Registered directly (not in the returned function) so it runs
|
|
2277
2384
|
// BEFORE Vite's built-in middleware. This ensures all requests
|
|
@@ -2284,7 +2391,7 @@ hydrate();
|
|
|
2284
2391
|
"x-forwarded-host": req.headers["x-forwarded-host"],
|
|
2285
2392
|
"sec-fetch-site": req.headers["sec-fetch-site"],
|
|
2286
2393
|
"sec-fetch-mode": req.headers["sec-fetch-mode"],
|
|
2287
|
-
}, nextConfig?.
|
|
2394
|
+
}, nextConfig?.allowedDevOrigins);
|
|
2288
2395
|
if (blockReason) {
|
|
2289
2396
|
console.warn(`[vinext] Blocked dev request: ${blockReason} (${req.url})`);
|
|
2290
2397
|
res.writeHead(403, { "Content-Type": "text/plain" });
|
|
@@ -2295,6 +2402,32 @@ hydrate();
|
|
|
2295
2402
|
});
|
|
2296
2403
|
// Return a function to register middleware AFTER Vite's built-in middleware
|
|
2297
2404
|
return () => {
|
|
2405
|
+
// Run instrumentation.ts register() if present (once at server startup).
|
|
2406
|
+
// Must be inside the returned function so that all environments are
|
|
2407
|
+
// fully registered before getPagesRunner() inspects them.
|
|
2408
|
+
//
|
|
2409
|
+
// App Router: register() is baked into the generated RSC entry as a
|
|
2410
|
+
// top-level await, so it runs inside the Worker process (or RSC Vite
|
|
2411
|
+
// environment) — the same process as request handling. Calling
|
|
2412
|
+
// runInstrumentation() here too would run it a second time in the host
|
|
2413
|
+
// process, which is wrong when @cloudflare/vite-plugin is present.
|
|
2414
|
+
//
|
|
2415
|
+
// Pages Router prod: register() is baked into generateServerEntry() as
|
|
2416
|
+
// a top-level await, so it runs inside the Worker bundle — the same
|
|
2417
|
+
// process as request handling. configureServer() is never called during
|
|
2418
|
+
// a prod build, so there is no double-invocation risk there either.
|
|
2419
|
+
//
|
|
2420
|
+
// We pass getPagesRunner() (createDirectRunner) rather than server so
|
|
2421
|
+
// that this is safe when @cloudflare/vite-plugin is present. That
|
|
2422
|
+
// plugin replaces the SSR environment's hot channel, causing
|
|
2423
|
+
// server.ssrLoadModule() to crash with outsideEmitter. The runner
|
|
2424
|
+
// calls environment.fetchModule() directly and never touches the hot
|
|
2425
|
+
// channel, making it safe with all Vite plugin combinations.
|
|
2426
|
+
if (instrumentationPath && !hasAppDir) {
|
|
2427
|
+
runInstrumentation(getPagesRunner(), instrumentationPath).catch((err) => {
|
|
2428
|
+
console.error("[vinext] Instrumentation error:", err);
|
|
2429
|
+
});
|
|
2430
|
+
}
|
|
2298
2431
|
// App Router request logging in dev server
|
|
2299
2432
|
//
|
|
2300
2433
|
// For App Router, the RSC plugin handles requests internally.
|
|
@@ -2430,7 +2563,7 @@ hydrate();
|
|
|
2430
2563
|
"x-forwarded-host": req.headers["x-forwarded-host"],
|
|
2431
2564
|
"sec-fetch-site": req.headers["sec-fetch-site"],
|
|
2432
2565
|
"sec-fetch-mode": req.headers["sec-fetch-mode"],
|
|
2433
|
-
}, nextConfig?.
|
|
2566
|
+
}, nextConfig?.allowedDevOrigins);
|
|
2434
2567
|
if (blockReason) {
|
|
2435
2568
|
console.warn(`[vinext] Blocked dev request: ${blockReason} (${url})`);
|
|
2436
2569
|
res.writeHead(403, { "Content-Type": "text/plain" });
|
|
@@ -2559,7 +2692,7 @@ hydrate();
|
|
|
2559
2692
|
.filter(([, v]) => v !== undefined)
|
|
2560
2693
|
.map(([k, v]) => [k, Array.isArray(v) ? v.join(", ") : String(v)])),
|
|
2561
2694
|
});
|
|
2562
|
-
const result = await runMiddleware(
|
|
2695
|
+
const result = await runMiddleware(getPagesRunner(), middlewarePath, middlewareRequest);
|
|
2563
2696
|
if (!result.continue) {
|
|
2564
2697
|
if (result.redirectUrl) {
|
|
2565
2698
|
const redirectHeaders = { Location: result.redirectUrl };
|
|
@@ -2610,11 +2743,41 @@ hydrate();
|
|
|
2610
2743
|
// Apply middleware rewrite (URL and optional status code)
|
|
2611
2744
|
if (result.rewriteUrl) {
|
|
2612
2745
|
url = result.rewriteUrl;
|
|
2746
|
+
// Write the rewritten URL back onto req.url so every subsequent
|
|
2747
|
+
// handler in the connect chain sees the correct path. The local
|
|
2748
|
+
// `url` variable is only visible within this handler — anything
|
|
2749
|
+
// further down the chain (Vite's built-in middleware, the
|
|
2750
|
+
// Cloudflare plugin's handler, or any other connect middleware)
|
|
2751
|
+
// reads req.url directly. Without this, a middleware rewrite
|
|
2752
|
+
// would be invisible to those handlers and the original URL
|
|
2753
|
+
// would be dispatched instead.
|
|
2754
|
+
req.url = url;
|
|
2613
2755
|
}
|
|
2614
2756
|
if (result.rewriteStatus) {
|
|
2615
2757
|
req.__vinextRewriteStatus = result.rewriteStatus;
|
|
2616
2758
|
}
|
|
2617
2759
|
}
|
|
2760
|
+
// ── Cloudflare Workers dev mode ────────────────────────────
|
|
2761
|
+
// When @cloudflare/vite-plugin is present, ALL rendering runs
|
|
2762
|
+
// inside the miniflare Worker subprocess — both App Router (via
|
|
2763
|
+
// virtual:vinext-rsc-entry) and Pages Router (via
|
|
2764
|
+
// virtual:vinext-server-entry → renderPage/handleApiRoute).
|
|
2765
|
+
//
|
|
2766
|
+
// The Worker entry already handles config redirects, rewrites,
|
|
2767
|
+
// headers, and all routing internally. Running them here too
|
|
2768
|
+
// would duplicate that logic and produce incorrect behaviour
|
|
2769
|
+
// (double redirects, headers set on the wrong object, etc.).
|
|
2770
|
+
//
|
|
2771
|
+
// Middleware.ts is the only thing that belongs in the host connect
|
|
2772
|
+
// handler — it has already run above. Any terminal middleware
|
|
2773
|
+
// result (redirect, block response) has already been sent.
|
|
2774
|
+
// Any rewrite has been written back to req.url above so the
|
|
2775
|
+
// Cloudflare plugin's handler sees the correct path.
|
|
2776
|
+
//
|
|
2777
|
+
// Call next() to hand off to the Cloudflare plugin's connect
|
|
2778
|
+
// handler, which dispatches the request to miniflare.
|
|
2779
|
+
if (hasCloudflarePlugin)
|
|
2780
|
+
return next();
|
|
2618
2781
|
// Build request context once for has/missing condition checks
|
|
2619
2782
|
// across headers, redirects, and rewrites.
|
|
2620
2783
|
const reqUrl = new URL(url, `http://${req.headers.host || "localhost"}`);
|
|
@@ -3751,6 +3914,8 @@ function applyRewrites(pathname, rewrites, ctx) {
|
|
|
3751
3914
|
}
|
|
3752
3915
|
/**
|
|
3753
3916
|
* Apply custom header rules from next.config.js.
|
|
3917
|
+
* Middleware headers take precedence: if a header key was already set on the
|
|
3918
|
+
* response (by middleware), the config value is skipped for that key.
|
|
3754
3919
|
*/
|
|
3755
3920
|
function applyHeaders(pathname, res, headers, ctx) {
|
|
3756
3921
|
const matched = matchHeaders(pathname, headers, ctx);
|
|
@@ -3783,7 +3948,11 @@ function applyHeaders(pathname, res, headers, ctx) {
|
|
|
3783
3948
|
}
|
|
3784
3949
|
}
|
|
3785
3950
|
else {
|
|
3786
|
-
|
|
3951
|
+
// Middleware headers take precedence: skip config keys already set by
|
|
3952
|
+
// middleware so middleware always wins over next.config.js headers.
|
|
3953
|
+
if (!res.getHeader(lk)) {
|
|
3954
|
+
res.setHeader(header.key, header.value);
|
|
3955
|
+
}
|
|
3787
3956
|
}
|
|
3788
3957
|
}
|
|
3789
3958
|
}
|
|
@@ -3838,4 +4007,5 @@ export { clientManualChunks, clientOutputConfig, clientTreeshakeConfig, computeL
|
|
|
3838
4007
|
export { resolvePostcssStringPlugins as _resolvePostcssStringPlugins };
|
|
3839
4008
|
export { parseStaticObjectLiteral as _parseStaticObjectLiteral };
|
|
3840
4009
|
export { stripServerExports as _stripServerExports };
|
|
4010
|
+
export { asyncHooksStubPlugin as _asyncHooksStubPlugin };
|
|
3841
4011
|
//# sourceMappingURL=index.js.map
|