diff --git a/packages/plugin-rsc/examples/basic/vite.config.ts b/packages/plugin-rsc/examples/basic/vite.config.ts index d974b3ea3..72d42a074 100644 --- a/packages/plugin-rsc/examples/basic/vite.config.ts +++ b/packages/plugin-rsc/examples/basic/vite.config.ts @@ -32,6 +32,7 @@ export default defineConfig({ react(), vitePluginUseCache(), vitePluginVirtualModuleTest(), + testRscVirtualClientPackagePlugin(), rsc({ entries: { client: './src/framework/entry.browser.tsx', @@ -271,6 +272,25 @@ export default { fetch: handler }; }, }) as any +function testRscVirtualClientPackagePlugin(): Plugin { + return { + name: 'test-rsc-virtual-client-package', + enforce: 'pre', + resolveId(source, importer) { + // `rsc:virtual-client-package` should pass an explicit root importer. + if ( + this.environment.name === 'rsc' && + source === '@vitejs/test-dep-transitive-client/client' && + importer == null + ) { + throw new Error( + '`rsc:virtual-client-package` root resolution requires an importer', + ) + } + }, + } +} + function testBuildPlugin(): Plugin[] { const moduleIds: { name: string; ids: string[] }[] = [] return [ diff --git a/packages/plugin-rsc/src/plugin.ts b/packages/plugin-rsc/src/plugin.ts index b66c4119e..a57341245 100644 --- a/packages/plugin-rsc/src/plugin.ts +++ b/packages/plugin-rsc/src/plugin.ts @@ -1720,9 +1720,15 @@ function vitePluginUseClient( // transitive dependency reachable from `importer` but not installed // at the root (see #1247). In that case, skip virtualization and // let it fall back to referencing the fully resolved module id. + // Vite's resolver already treats an undefined importer as the project + // root, but other plugins may not, so pass the root importer explicitly. + const rootImporter = path.join( + this.environment.config.root, + 'index.html', + ) const resolvedAtRoot = await this.resolve( source, - undefined, + rootImporter, options, ) if (!resolvedAtRoot || resolvedAtRoot.id !== resolved.id) {