diff --git a/packages/plugin-rsc/e2e/basic.test.ts b/packages/plugin-rsc/e2e/basic.test.ts
index 5a0464a09..d463b983b 100644
--- a/packages/plugin-rsc/e2e/basic.test.ts
+++ b/packages/plugin-rsc/e2e/basic.test.ts
@@ -11,9 +11,6 @@ import {
import path from 'node:path'
import os from 'node:os'
-// TODO: parallel?
-// TODO: all tests don't need to be tested in all variants?
-
test.describe('dev-default', () => {
const f = useFixture({ root: 'examples/basic', mode: 'dev' })
defineTest(f)
@@ -824,6 +821,14 @@ function defineTest(f: Fixture) {
)
})
+ test('transitive cjs dep', async ({ page }) => {
+ await page.goto(f.url())
+ await waitForHydration(page)
+ await expect(page.getByTestId('transitive-cjs-client')).toHaveText(
+ 'ok:browser',
+ )
+ })
+
test('use cache function', async ({ page }) => {
await page.goto(f.url())
await waitForHydration(page)
diff --git a/packages/plugin-rsc/examples/basic/package.json b/packages/plugin-rsc/examples/basic/package.json
index 43d95645d..6fb6344bc 100644
--- a/packages/plugin-rsc/examples/basic/package.json
+++ b/packages/plugin-rsc/examples/basic/package.json
@@ -21,6 +21,7 @@
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"@vitejs/plugin-react": "latest",
+ "@vitejs/test-dep-transitive-cjs": "file:./test-dep/transitive-cjs",
"@vitejs/test-dep-client-in-server": "file:./test-dep/client-in-server",
"@vitejs/test-dep-client-in-server2": "file:./test-dep/client-in-server2",
"@vitejs/test-dep-server-in-client": "file:./test-dep/server-in-client",
diff --git a/packages/plugin-rsc/examples/basic/src/routes/deps/transitive-cjs/client.tsx b/packages/plugin-rsc/examples/basic/src/routes/deps/transitive-cjs/client.tsx
new file mode 100644
index 000000000..11045ee39
--- /dev/null
+++ b/packages/plugin-rsc/examples/basic/src/routes/deps/transitive-cjs/client.tsx
@@ -0,0 +1,12 @@
+'use client'
+
+// @ts-ignore
+import { TestClient } from '@vitejs/test-dep-transitive-cjs/client'
+
+export function TestTransitiveCjsClient() {
+ return (
+
+ [test-dep-transitive-cjs-client: ]
+
+ )
+}
diff --git a/packages/plugin-rsc/examples/basic/src/routes/root.tsx b/packages/plugin-rsc/examples/basic/src/routes/root.tsx
index 52ce38dee..f679c362e 100644
--- a/packages/plugin-rsc/examples/basic/src/routes/root.tsx
+++ b/packages/plugin-rsc/examples/basic/src/routes/root.tsx
@@ -29,6 +29,7 @@ import { TestTemporaryReference } from './temporary-reference/client'
import { TestUseCache } from './use-cache/server'
import { TestHydrationMismatch } from './hydration-mismatch/server'
import { TestBrowserOnly } from './browser-only/client'
+import { TestTransitiveCjsClient } from './deps/transitive-cjs/client'
export function Root(props: { url: URL }) {
return (
@@ -67,6 +68,7 @@ export function Root(props: { url: URL }) {
+
diff --git a/packages/plugin-rsc/examples/basic/test-dep/transitive-cjs/client.js b/packages/plugin-rsc/examples/basic/test-dep/transitive-cjs/client.js
new file mode 100644
index 000000000..db2fd4b6f
--- /dev/null
+++ b/packages/plugin-rsc/examples/basic/test-dep/transitive-cjs/client.js
@@ -0,0 +1,27 @@
+'use client'
+
+import React from 'react'
+
+// similar to swr
+// https://github.com/vercel/swr/blob/063fe55dddb95f0b6c3f1637a935c43d732ded78/src/index/use-swr.ts#L3
+import { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'
+
+const h = React.createElement
+
+const noopStore = () => () => {}
+
+export function TestClient() {
+ const value = useSyncExternalStore(
+ noopStore,
+ () => 'ok:browser',
+ () => 'ok:ssr',
+ )
+
+ return h(
+ 'span',
+ {
+ 'data-testid': 'transitive-cjs-client',
+ },
+ value,
+ )
+}
diff --git a/packages/plugin-rsc/examples/basic/test-dep/transitive-cjs/package.json b/packages/plugin-rsc/examples/basic/test-dep/transitive-cjs/package.json
new file mode 100644
index 000000000..8368742da
--- /dev/null
+++ b/packages/plugin-rsc/examples/basic/test-dep/transitive-cjs/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "@vitejs/test-dep-transitive-cjs",
+ "private": true,
+ "type": "module",
+ "exports": {
+ "./client": "./client.js"
+ },
+ "dependencies": {
+ "use-sync-external-store": "^1.5.0"
+ },
+ "peerDependencies": {
+ "react": "*"
+ }
+}
diff --git a/packages/plugin-rsc/examples/basic/vite.config.ts b/packages/plugin-rsc/examples/basic/vite.config.ts
index 97d0f30b8..b0eec5511 100644
--- a/packages/plugin-rsc/examples/basic/vite.config.ts
+++ b/packages/plugin-rsc/examples/basic/vite.config.ts
@@ -135,12 +135,29 @@ export default { fetch: handler };
minify: false,
manifest: true,
},
- optimizeDeps: {
- exclude: [
- '@vitejs/test-dep-client-in-server/client',
- '@vitejs/test-dep-client-in-server2/client',
- '@vitejs/test-dep-server-in-client/client',
- ],
+ environments: {
+ client: {
+ optimizeDeps: {
+ entries: [
+ './src/routes/**/client.tsx',
+ './src/framework/entry.browser.tsx',
+ ],
+ exclude: [
+ '@vitejs/test-dep-client-in-server/client',
+ '@vitejs/test-dep-client-in-server2/client',
+ '@vitejs/test-dep-server-in-client/client',
+ ],
+ },
+ },
+ ssr: {
+ optimizeDeps: {
+ // TODO: this should be somehow auto inferred or at least show a warning
+ // to guide users to `optimizeDeps.include`
+ include: [
+ '@vitejs/test-dep-transitive-cjs > use-sync-external-store/shim/index.js',
+ ],
+ },
+ },
},
}) as any
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 8bd988406..8b1fa0154 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -542,6 +542,9 @@ importers:
'@vitejs/test-dep-server-in-server':
specifier: file:./test-dep/server-in-server
version: file:packages/plugin-rsc/examples/basic/test-dep/server-in-server(react@19.1.0)
+ '@vitejs/test-dep-transitive-cjs':
+ specifier: file:./test-dep/transitive-cjs
+ version: file:packages/plugin-rsc/examples/basic/test-dep/transitive-cjs(react@19.1.0)
rsc-html-stream:
specifier: ^0.0.7
version: 0.0.7
@@ -3094,6 +3097,11 @@ packages:
peerDependencies:
react: '*'
+ '@vitejs/test-dep-transitive-cjs@file:packages/plugin-rsc/examples/basic/test-dep/transitive-cjs':
+ resolution: {directory: packages/plugin-rsc/examples/basic/test-dep/transitive-cjs, type: directory}
+ peerDependencies:
+ react: '*'
+
'@vitest/expect@3.2.4':
resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==}
@@ -5536,6 +5544,11 @@ packages:
uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+ use-sync-external-store@1.5.0:
+ resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
@@ -7656,6 +7669,11 @@ snapshots:
dependencies:
react: 19.1.0
+ '@vitejs/test-dep-transitive-cjs@file:packages/plugin-rsc/examples/basic/test-dep/transitive-cjs(react@19.1.0)':
+ dependencies:
+ react: 19.1.0
+ use-sync-external-store: 1.5.0(react@19.1.0)
+
'@vitest/expect@3.2.4':
dependencies:
'@types/chai': 5.2.2
@@ -10440,6 +10458,10 @@ snapshots:
dependencies:
punycode: 2.3.1
+ use-sync-external-store@1.5.0(react@19.1.0):
+ dependencies:
+ react: 19.1.0
+
util-deprecate@1.0.2: {}
valibot@0.41.0(typescript@5.8.3):