Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
96d2dec
fix(app-router): start optimistic prefetches immediately
james-elicx Jun 30, 2026
f144761
fix(app-router): support route tree prefetch inlining
james-elicx Jul 1, 2026
5b479c7
Merge commit 'f1447610395793f77c4a0e3b733306fcee40e95c' into codex/fi…
james-elicx Jul 1, 2026
47f9b8b
Merge commit '96d2dec9f3cdcd4c6b1cdb854b13335aae10b268' into codex/fi…
james-elicx Jul 1, 2026
3d1eec6
fix(app-router): dedupe max prefetch inlining requests
james-elicx Jul 1, 2026
e7f1e53
fix(app-router): cap route-tree prefetch size reads
james-elicx Jul 1, 2026
eb4dabc
fix(app-router): avoid runtime route-tree prefetch sizing
james-elicx Jul 1, 2026
caddde7
Fixed CI type error, flagged parity gap
ask-bonk[bot] Jul 1, 2026
a8f32b6
fix(app-router): preserve negative prefetch inlining thresholds
james-elicx Jul 1, 2026
936c29a
Merge remote-tracking branch 'origin/main' into codex/fix-segment-cac…
james-elicx Jul 1, 2026
95a96c9
Merge remote-tracking branch 'origin/main' into codex/fix-segment-cac…
james-elicx Jul 1, 2026
816faad
Merge remote-tracking branch 'origin/main' into codex/fix-segment-cac…
james-elicx Jul 1, 2026
0a84115
Merge remote-tracking branch 'origin/main' into codex/fix-segment-cac…
james-elicx Jul 1, 2026
e74c416
Merge remote-tracking branch 'origin/main' into codex/fix-segment-cac…
james-elicx Jul 1, 2026
68b96b5
fix(app-router): normalize rsc reference validation ids
james-elicx Jul 1, 2026
87b37a4
Revert "fix(app-router): normalize rsc reference validation ids"
james-elicx Jul 1, 2026
d738f95
fix(app-router): keep route-tree prefetch metadata scoped
james-elicx Jul 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 33 additions & 7 deletions packages/vinext/src/config/next-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,13 @@ export type MdxOptions = {
recmaPlugins?: unknown[];
};

export type PrefetchInliningConfig =
| false
| {
maxBundleSize: number;
maxSize: number;
};

export type NextConfig = {
/** Additional env variables */
env?: Record<string, string>;
Expand Down Expand Up @@ -302,6 +309,12 @@ export type NextConfig = {
* `useRouter().experimental_gesturePush()`.
*/
gestureTransition?: boolean;
/**
* Enables App Router Segment Cache prefetch inlining. When provided as an
* object, thresholds are resolved with Next.js defaults and non-finite
* values are clamped to Number.MAX_SAFE_INTEGER.
*/
prefetchInlining?: boolean | { maxBundleSize?: number; maxSize?: number };
[key: string]: unknown;
};
/**
Expand Down Expand Up @@ -368,11 +381,10 @@ export type ResolvedNextConfig = {
*/
gestureTransition: boolean;
/**
* Whether `experimental.prefetchInlining` is configured. Next.js uses this
* with the Segment Cache to fetch the route tree before the bundled inlined
* segment payload.
* Resolved `experimental.prefetchInlining` config. Next.js normalizes `true`
* and partial object config into concrete thresholds.
*/
prefetchInlining: boolean;
prefetchInlining: PrefetchInliningConfig;
redirects: NextRedirect[];
rewrites: {
beforeFiles: NextRewrite[];
Expand Down Expand Up @@ -1334,6 +1346,21 @@ function resolveStaleTimes(experimental: Record<string, unknown> | undefined): {
};
}

function normalizePrefetchInliningConfig(value: unknown): PrefetchInliningConfig {
if (!value) return false;
const raw = isUnknownRecord(value) ? value : null;
const maxSize = raw ? (raw.maxSize ?? 2048) : 2048;
const maxBundleSize = raw ? (raw.maxBundleSize ?? 10240) : 10240;
const normalizedMaxSize = Number(maxSize);
const normalizedMaxBundleSize = Number(maxBundleSize);
return {
maxBundleSize: Number.isFinite(normalizedMaxBundleSize)
? normalizedMaxBundleSize
: Number.MAX_SAFE_INTEGER,
maxSize: Number.isFinite(normalizedMaxSize) ? normalizedMaxSize : Number.MAX_SAFE_INTEGER,
};
}

/**
* Resolve a NextConfig into a fully-resolved ResolvedNextConfig.
* Awaits async functions for redirects/rewrites/headers.
Expand Down Expand Up @@ -1503,8 +1530,7 @@ export async function resolveNextConfig(
: [];
const inlineCss = experimental?.inlineCss === true;
const globalNotFound = experimental?.globalNotFound === true;
const prefetchInlining =
experimental?.prefetchInlining === true || isUnknownRecord(experimental?.prefetchInlining);
const prefetchInlining = normalizePrefetchInliningConfig(experimental?.prefetchInlining);

// Validate experimental.appShells co-flags. Next.js requires all of the
// following to be enabled when appShells is true:
Expand All @@ -1517,7 +1543,7 @@ export async function resolveNextConfig(
if (!config.cacheComponents) {
missingCoFlags.push("cacheComponents");
}
if (experimental?.prefetchInlining !== true) {
if (!prefetchInlining) {
missingCoFlags.push("experimental.prefetchInlining");
}
if (experimental?.varyParams !== true) {
Expand Down
5 changes: 5 additions & 0 deletions packages/vinext/src/entries/app-rsc-entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type {
NextI18nConfig,
NextRedirect,
NextRewrite,
PrefetchInliningConfig,
} from "../config/next-config.js";
import type { ImageConfig } from "../server/image-optimization.js";
import type { AppRoute } from "../routing/app-router.js";
Expand Down Expand Up @@ -164,6 +165,8 @@ type AppRouterConfig = {
globalNotFound?: boolean;
/** Enables Next.js Cache Components semantics for App Router document HTML. */
cacheComponents?: boolean;
/** Resolved `experimental.prefetchInlining` thresholds. */
prefetchInlining?: PrefetchInliningConfig;
/** Whether the RSC build discovered any server references. Defaults to true. */
hasServerActions?: boolean;
/** Internationalization routing config for middleware matcher locale handling. */
Expand Down Expand Up @@ -227,6 +230,7 @@ export function generateRscEntry(
const cacheMaxMemorySize = config?.cacheMaxMemorySize;
const inlineCss = config?.inlineCss === true;
const cacheComponents = config?.cacheComponents === true;
const prefetchInlining = config?.prefetchInlining ?? false;
const hasServerActions = config?.hasServerActions !== false;
const i18nConfig = config?.i18n ?? null;
const hasPagesDir = config?.hasPagesDir ?? false;
Expand Down Expand Up @@ -706,6 +710,7 @@ export default createAppRscHandler({
basePath: __basePath,
buildId: process.env.__VINEXT_BUILD_ID ?? null,
ensureRouteLoaded: __ensureRouteLoaded,
prefetchInlining: ${JSON.stringify(prefetchInlining)},
clearRequestContext() {
__clearRequestContext();
},
Expand Down
1 change: 1 addition & 0 deletions packages/vinext/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3308,6 +3308,7 @@ export default function vinext(options: VinextOptions = {}): PluginOption[] {
inlineCss: nextConfig?.inlineCss,
globalNotFound: nextConfig?.globalNotFound,
cacheComponents: nextConfig?.cacheComponents,
prefetchInlining: nextConfig?.prefetchInlining,
hasServerActions,
i18n: nextConfig?.i18n,
imageConfig: {
Expand Down
1 change: 1 addition & 0 deletions packages/vinext/src/server/app-browser-entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,7 @@ async function learnOptimisticRouteTemplatesFromPrefetchCache(options: {
if (optimisticRouteTemplateSources.has(sourceKey)) continue;
if (optimisticRouteTemplateLearning.has(sourceKey)) continue;
if (!isSettledPrefetchCacheEntry(entry)) continue;
if (entry.prefetchKind === "route-tree") continue;

const promise = learnOptimisticRouteTemplateFromPrefetch({
cacheKey,
Expand Down
Loading
Loading