Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion packages/vinext/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@
"peerDependencies": {
"@mdx-js/rollup": "^3.0.0",
"@vitejs/plugin-react": "^5.1.4 || ^6.0.0",
"@vitejs/plugin-rsc": "^0.5.26",
"@vitejs/plugin-rsc": "^0.5.29",

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if peer dep bump should be breaking change. From the past commit history, there doesn't seem to be strict policy.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other times i've switched to new Vite related functionality, i've left the old behaviour behind a version check to avoid breaking changes. Will probably have to see if the same thing can be done for this too. I can have a look at that no worries

"react": "^19.2.6",
"react-dom": "^19.2.6",
"react-server-dom-webpack": "^19.2.6",
Expand Down
11 changes: 3 additions & 8 deletions packages/vinext/src/entries/app-rsc-entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,17 +289,12 @@ import {
createTemporaryReferenceSet,`
: ""
}
} from ${JSON.stringify(
hasServerActions ? "@vitejs/plugin-rsc/rsc" : "@vitejs/plugin-rsc/react/rsc",
)};
import { createClientManifest as _createClientManifest } from "@vitejs/plugin-rsc/core/rsc";
import { prerender as _prerender } from "@vitejs/plugin-rsc/vendor/react-server-dom/static.edge";
} from "@vitejs/plugin-rsc/rsc/server";
import { prerender as _prerender } from "@vitejs/plugin-rsc/rsc/static";
Comment on lines +292 to +293

@hi-ogawa hi-ogawa Jul 23, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hasServerActions ? "@vitejs/plugin-rsc/rsc" : "@vitejs/plugin-rsc/react/rsc"

This hasServerActions branch is introduced by #2206, but this shouldn't matter since tree shaking server action API is mostly done by the import branch above:

import {
renderToReadableStream as _renderToReadableStream,
${
hasServerActions
? `decodeAction,
decodeFormState,
decodeReply,
loadServerAction,
createTemporaryReferenceSet,`
: ""
}

So this has been consolidated to just /rsc/server import unconditionally.

import { createRscPrerenderer, createRscRenderer } from ${JSON.stringify(rscStreamHintsPath)};

const renderToReadableStream = createRscRenderer(_renderToReadableStream);
const prerenderToReadableStream = createRscPrerenderer(async (model, options) =>
_prerender(model, _createClientManifest(), options),
);
const prerenderToReadableStream = createRscPrerenderer(_prerender);
import { createElement } from "react";
import { getNavigationContext as _getNavigationContext } from "next/navigation";
import { configureMemoryCacheHandler as __configureMemoryCacheHandler } from "vinext/shims/cache-handler";
Expand Down
5 changes: 1 addition & 4 deletions packages/vinext/src/entries/pages-server-entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,6 @@ import { configureMemoryCacheHandler as __configureMemoryCacheHandler } from "vi
import { registerConfiguredCacheAdapters as __registerConfiguredCacheAdapters } from "virtual:vinext-cache-adapters";
import __pagesClientAssets from "virtual:vinext-pages-client-assets";
import { setPagesClientAssets as __setPagesClientAssets } from "vinext/server/pages-client-assets";
import { runWithPrivateCache } from "vinext/cache-runtime";
import { ensureFetchPatch, runWithFetchCache } from "vinext/fetch-cache";
import "vinext/router-state";
import { runWithServerInsertedHTMLState } from "vinext/navigation-state";
Expand Down Expand Up @@ -292,9 +291,7 @@ async function _renderIsrPassToStringAsync(element) {
// intact: this second pass still belongs to the same request.
return await runWithServerInsertedHTMLState(() =>
runWithHeadState(() =>
_runWithCacheState(() =>
runWithPrivateCache(() => runWithFetchCache(async () => _renderToStringAsync(element))),
),
_runWithCacheState(() => runWithFetchCache(async () => _renderToStringAsync(element))),
),
);
}
Expand Down
8 changes: 6 additions & 2 deletions packages/vinext/src/shims/cache-runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ export function getCacheContext(): CacheContext | null {
// ---------------------------------------------------------------------------

/**
* RSC serialization APIs from @vitejs/plugin-rsc/react/rsc.
* RSC serialization APIs from @vitejs/plugin-rsc/rsc/server and /rsc/client.
* Lazily loaded because these are only available in the Vite RSC environment
* (they depend on virtual modules set up by @vitejs/plugin-rsc).
* In test environments, the import fails and we fall back to JSON.
Expand Down Expand Up @@ -232,7 +232,11 @@ let _rscModule: RscModule | null | typeof NOT_LOADED = NOT_LOADED;
async function getRscModule(): Promise<RscModule | null> {
if (_rscModule !== NOT_LOADED) return _rscModule;
try {
_rscModule = (await import("@vitejs/plugin-rsc/react/rsc")) as RscModule;
const [server, client] = await Promise.all([
import("@vitejs/plugin-rsc/rsc/server"),
import("@vitejs/plugin-rsc/rsc/client"),
]);
Comment on lines +235 to +238

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like using /rsc/* here breaks for pages router setup because no rsc plugin means no virtual module used by /rsc/* entry.

I think ideally page router only mode can entirely nullifying packages/vinext/src/shims/cache-runtime.ts (and other related app router only modules). Let me check a bit.

@hi-ogawa hi-ogawa Jul 23, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Attempting to remove "cache-runtime" import from pages router ssr entry 95d9862. The existing test appears to be asserting internal request context, which has no user facing pages router feature, so it's adjusted accordingly.

_rscModule = { ...server, ...client } as RscModule;
} catch {
_rscModule = null;
}
Expand Down
93 changes: 49 additions & 44 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ catalog:
"@next/mdx": 16.2.7
recma-codehike: 0.0.1
remark-codehike: 0.0.1
"@vitejs/plugin-rsc": ^0.5.27
"@vitejs/plugin-rsc": ^0.5.29
"@vitest/coverage-istanbul": 4.1.9
better-auth: ^1.5.6
better-sqlite3: ^12.0.0
Expand Down
6 changes: 5 additions & 1 deletion tests/entry-templates.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1244,7 +1244,11 @@ describe("App Router entry templates", () => {
hasServerActions: false,
});

expect(code).toContain('from "@vitejs/plugin-rsc/react/rsc"');
expect(code).toContain('from "@vitejs/plugin-rsc/rsc/server"');
expect(code).toContain('from "@vitejs/plugin-rsc/rsc/static"');
expect(code).not.toContain("@vitejs/plugin-rsc/react/");
expect(code).not.toContain("@vitejs/plugin-rsc/core/");
expect(code).not.toContain("@vitejs/plugin-rsc/vendor/");
expect(code).not.toContain("app-server-action-execution.js");
expect(code).not.toContain("decodeAction,");
expect(code).not.toContain("decodeFormState,");
Expand Down
6 changes: 0 additions & 6 deletions tests/fixtures/pages-basic/pages/isr-second-render-state.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,8 @@ interface ISRSecondRenderStateProps {
export default function ISRSecondRenderStatePage({ timestamp }: ISRSecondRenderStateProps) {
const ctx = getRequestContext();
const headBefore = ctx.ssrHeadChildren.length;
const privateCacheBefore = ctx._privateCache?.size ?? 0;
const insertedHtmlBefore = ctx.serverInsertedHTMLCallbacks.length;

if (ctx._privateCache === null) {
ctx._privateCache = new Map();
}
ctx._privateCache.set("isr-second-render-state", timestamp);
ctx.serverInsertedHTMLCallbacks.push(() => "<style data-isr-second-render-state></style>");

return (
Expand All @@ -25,7 +20,6 @@ export default function ISRSecondRenderStatePage({ timestamp }: ISRSecondRenderS
</Head>
<h1>ISR Second Render State</h1>
<p data-testid="head-before">{headBefore}</p>
<p data-testid="private-cache-before">{privateCacheBefore}</p>
<p data-testid="inserted-html-before">{insertedHtmlBefore}</p>
<p data-testid="timestamp">{timestamp}</p>
</>
Expand Down
4 changes: 0 additions & 4 deletions tests/pages-router.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1410,15 +1410,13 @@ export default function Page({ marker }: { marker: string }) {
expect(firstRes.headers.get("x-vinext-cache")).toBeNull();
const firstHtml = await firstRes.text();
expect(firstHtml).toContain('data-testid="head-before">0<');
expect(firstHtml).toContain('data-testid="private-cache-before">0<');
expect(firstHtml).toContain('data-testid="inserted-html-before">0<');

const secondRes = await fetch(`${baseUrl}/isr-second-render-state`);
expect(secondRes.status).toBe(200);
expect(secondRes.headers.get("x-vinext-cache")).toBeNull();
const secondHtml = await secondRes.text();
expect(secondHtml).toContain('data-testid="head-before">0<');
expect(secondHtml).toContain('data-testid="private-cache-before">0<');
expect(secondHtml).toContain('data-testid="inserted-html-before">0<');
});

Expand Down Expand Up @@ -6104,15 +6102,13 @@ export default function CounterPage() {
expect(isrFirstRes.headers.get("x-vinext-cache")).toBe("MISS");
const isrFirstHtml = await isrFirstRes.text();
expect(isrFirstHtml).toContain('data-testid="head-before">0<');
expect(isrFirstHtml).toContain('data-testid="private-cache-before">0<');
expect(isrFirstHtml).toContain('data-testid="inserted-html-before">0<');

const isrSecondRes = await fetch(`${prodUrl}/isr-second-render-state`);
expect(isrSecondRes.status).toBe(200);
expect(isrSecondRes.headers.get("x-vinext-cache")).toBe("HIT");
const isrSecondHtml = await isrSecondRes.text();
expect(isrSecondHtml).toContain('data-testid="head-before">0<');
expect(isrSecondHtml).toContain('data-testid="private-cache-before">0<');
expect(isrSecondHtml).toContain('data-testid="inserted-html-before">0<');

// Test: SSR page with getServerSideProps
Expand Down
2 changes: 1 addition & 1 deletion tests/shims.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6803,7 +6803,7 @@ describe('"use cache" runtime', () => {
});

it("falls back to JSON when RSC module is unavailable (test environment)", async () => {
// In vitest, @vitejs/plugin-rsc/react/rsc is not available (no Vite RSC
// In vitest, @vitejs/plugin-rsc/rsc entries are not available (no Vite RSC
// environment). The runtime should gracefully fall back to JSON.stringify
// for cache values and stableStringify for cache keys.
const { registerCachedFunction } =
Expand Down
Loading