diff --git a/packages/plugin-rsc/src/plugin.ts b/packages/plugin-rsc/src/plugin.ts index ebb17de5b..9ec4254e2 100644 --- a/packages/plugin-rsc/src/plugin.ts +++ b/packages/plugin-rsc/src/plugin.ts @@ -956,21 +956,21 @@ function vitePluginUseClient( const browserEnvironmentName = useClientPluginOptions.environment?.browser ?? 'client' + let optimizerMetadata: CustomOptimizerMetadata | undefined + // TODO: warning for late optimizer discovery function warnInoncistentClientOptimization( ctx: Rollup.TransformPluginContext, id: string, ) { - const { depsOptimizer } = server.environments.client - if (depsOptimizer) { - for (const dep of Object.values(depsOptimizer.metadata.optimized)) { - if (dep.src === id) { - ctx.warn( - `client component dependency is inconsistently optimized. ` + - `It's recommended to add the dependency to 'optimizeDeps.exclude'.`, - ) - } - } + // path in metafile is relative to cwd + // https://github.com/vitejs/vite/blob/dd96c2cd831ecba3874458b318ad4f0a7f173736/packages/vite/src/node/optimizer/index.ts#L644 + id = normalizePath(path.relative(process.cwd(), id)) + if (optimizerMetadata?.ids.includes(id)) { + ctx.warn( + `client component dependency is inconsistently optimized. ` + + `It's recommended to add the dependency to 'optimizeDeps.exclude'.`, + ) } } @@ -1160,6 +1160,104 @@ function vitePluginUseClient( } }, }, + ...customOptimizerMetadataPlugin({ + setMetadata: (metadata) => { + optimizerMetadata = metadata + }, + }), + ] +} + +type CustomOptimizerMetadata = { + ids: string[] +} + +function customOptimizerMetadataPlugin({ + setMetadata, +}: { + setMetadata: (metadata: CustomOptimizerMetadata) => void +}): Plugin[] { + const MEATADATA_FILE = '_metadata-rsc.json' + + type EsbuildPlugin = NonNullable< + NonNullable['plugins'] + >[number] + + function optimizerPluginEsbuild(): EsbuildPlugin { + return { + name: 'vite-rsc-metafile', + setup(build) { + build.onEnd((result) => { + // skip scan + if (!result.metafile?.inputs || !build.initialOptions.outdir) return + + const ids = Object.keys(result.metafile.inputs) + const metadata: CustomOptimizerMetadata = { ids } + setMetadata(metadata) + fs.writeFileSync( + path.join(build.initialOptions.outdir, MEATADATA_FILE), + JSON.stringify(metadata, null, 2), + ) + }) + }, + } + } + + function optimizerPluginRolldown(): Rollup.Plugin { + return { + name: 'vite-rsc-metafile', + writeBundle(options) { + assert(options.dir) + const ids = [...this.getModuleIds()].map((id) => + path.relative(process.cwd(), id), + ) + const metadata: CustomOptimizerMetadata = { ids } + setMetadata(metadata) + fs.writeFileSync( + path.join(options.dir!, MEATADATA_FILE), + JSON.stringify(metadata, null, 2), + ) + }, + } + } + + return [ + { + name: 'rsc:use-client:optimizer-metadata', + apply: 'serve', + config() { + return { + environments: { + client: { + optimizeDeps: + 'rolldownVersion' in this.meta + ? ({ + rolldownOptions: { + plugins: [optimizerPluginRolldown()], + }, + } as any) + : { + esbuildOptions: { + plugins: [optimizerPluginEsbuild()], + }, + }, + }, + }, + } + }, + configResolved(config) { + // https://github.com/vitejs/vite/blob/84079a84ad94de4c1ef4f1bdb2ab448ff2c01196/packages/vite/src/node/optimizer/index.ts#L941 + const file = path.join(config.cacheDir, 'deps', MEATADATA_FILE) + if (fs.existsSync(file)) { + try { + const metadata = JSON.parse(fs.readFileSync(file, 'utf-8')) + setMetadata(metadata) + } catch (e) { + this.warn(`failed to load '${file}'`) + } + } + }, + }, ] }