diff --git a/packages/plugin-rsc/e2e/client-package-resolution.test.ts b/packages/plugin-rsc/e2e/client-package-resolution.test.ts
new file mode 100644
index 000000000..26a5084a9
--- /dev/null
+++ b/packages/plugin-rsc/e2e/client-package-resolution.test.ts
@@ -0,0 +1,121 @@
+import { expect, test } from '@playwright/test'
+import { setupInlineFixture, useFixture } from './fixture'
+import { waitForHydration } from './helper'
+
+test.describe(() => {
+ const root = 'examples/e2e/temp/client-package-resolution'
+
+ test.beforeAll(async () => {
+ await setupInlineFixture({
+ src: 'examples/starter-extra',
+ dest: root,
+ files: {
+ 'package.json': {
+ edit: (source) => {
+ const packageJson = JSON.parse(source)
+ packageJson.dependencies = {
+ ...packageJson.dependencies,
+ '@vitejs/test-dep-root-conflict': '1.0.0',
+ '@vitejs/test-dep-server-with-root-conflict': '1.0.0',
+ }
+ return JSON.stringify(packageJson, null, 2) + '\n'
+ },
+ },
+ 'src/root.tsx': /* tsx */ `
+ import { TestServer } from '@vitejs/test-dep-server-with-root-conflict/server'
+
+ export function Root() {
+ return (
+
+
+
+
+
+ )
+ }
+ `,
+ 'node_modules/@vitejs/test-dep-root-conflict/package.json': /* json */ `
+ {
+ "name": "@vitejs/test-dep-root-conflict",
+ "version": "1.0.0",
+ "type": "module",
+ "exports": {
+ ".": "./index.js"
+ }
+ }
+ `,
+ 'node_modules/@vitejs/test-dep-root-conflict/index.js': /* js */ `
+ export const root = true
+ `,
+ 'node_modules/@vitejs/test-dep-server-with-root-conflict/package.json': /* json */ `
+ {
+ "name": "@vitejs/test-dep-server-with-root-conflict",
+ "version": "1.0.0",
+ "type": "module",
+ "exports": {
+ "./server": "./server.js"
+ },
+ "dependencies": {
+ "@vitejs/test-dep-root-conflict": "2.0.0"
+ },
+ "peerDependencies": {
+ "react": "*"
+ }
+ }
+ `,
+ 'node_modules/@vitejs/test-dep-server-with-root-conflict/server.js': /* js */ `
+ import { TestClient } from '@vitejs/test-dep-root-conflict/client'
+ import React from 'react'
+
+ export function TestServer() {
+ return React.createElement(TestClient)
+ }
+ `,
+ 'node_modules/@vitejs/test-dep-server-with-root-conflict/node_modules/@vitejs/test-dep-root-conflict/package.json': /* json */ `
+ {
+ "name": "@vitejs/test-dep-root-conflict",
+ "version": "2.0.0",
+ "type": "module",
+ "exports": {
+ "./client": "./client.js"
+ },
+ "peerDependencies": {
+ "react": "*"
+ }
+ }
+ `,
+ 'node_modules/@vitejs/test-dep-server-with-root-conflict/node_modules/@vitejs/test-dep-root-conflict/client.js': /* js */ `
+ 'use client'
+
+ import React from 'react'
+
+ export function TestClient() {
+ const [count, setCount] = React.useState(0)
+ return React.createElement(
+ 'button',
+ { onClick: () => setCount((value) => value + 1) },
+ 'Nested client: ' + count,
+ )
+ }
+ `,
+ },
+ })
+ })
+
+ for (const mode of ['dev', 'build'] as const) {
+ test.describe(mode, () => {
+ const f = useFixture({ root, mode })
+
+ test('uses the client package resolved from its importer', async ({
+ page,
+ }) => {
+ await page.goto(f.url())
+ await waitForHydration(page)
+ await page.getByRole('button', { name: 'Nested client: 0' }).click()
+ await expect(
+ page.getByRole('button', { name: 'Nested client: 1' }),
+ ).toBeVisible()
+ })
+ })
+ }
+})
diff --git a/packages/plugin-rsc/src/plugin.ts b/packages/plugin-rsc/src/plugin.ts
index 9253de54f..198eb3515 100644
--- a/packages/plugin-rsc/src/plugin.ts
+++ b/packages/plugin-rsc/src/plugin.ts
@@ -1738,11 +1738,17 @@ function vitePluginUseClient(
this.environment.config.root,
'index.html',
)
- const resolvedAtRoot = await this.resolve(
- source,
- rootImporter,
- options,
- )
+ let resolvedAtRoot
+ try {
+ resolvedAtRoot = await this.resolve(
+ source,
+ rootImporter,
+ options,
+ )
+ } catch {
+ // A different version at the root may not export this subpath.
+ return
+ }
if (!resolvedAtRoot || resolvedAtRoot.id !== resolved.id) {
return
}