From dc4f69ee853e6b278a04470cb07ae8c90d61c2db Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 12 Sep 2025 15:57:22 +0900 Subject: [PATCH 1/5] refactor(rsc): self-accept rsc css module on client environment --- packages/plugin-rsc/src/plugin.ts | 33 +++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/packages/plugin-rsc/src/plugin.ts b/packages/plugin-rsc/src/plugin.ts index ad0004af..2223df89 100644 --- a/packages/plugin-rsc/src/plugin.ts +++ b/packages/plugin-rsc/src/plugin.ts @@ -1976,6 +1976,39 @@ function vitePluginRscCss( } }, }, + { + // self accept css module used in server component to avoid full reload + // https://github.com/vitejs/vite/blob/84079a84ad94de4c1ef4f1bdb2ab448ff2c01196/packages/vite/src/node/plugins/css.ts#L1096 + name: 'rsc:rsc-css-self-accept', + apply: 'serve', + transform: { + order: 'post', + handler(_code, id, _options) { + if ( + this.environment.name === 'client' && + this.environment.mode === 'dev' && + isCSSRequest(id) + ) { + const mod = this.environment.moduleGraph.getModuleById(id) + const { filename, query } = parseIdQuery(id) + if (mod && !mod.isSelfAccepting && 'direct' in query) { + const serverMods = + manager.server.environments.rsc!.moduleGraph.getModulesByFile( + filename, + ) + // filter out module nodes created by tailwind dependenncy. + // for Vite 7.1, we can use `m.type !== "asset"`. + const isServerCss = [...(serverMods ?? [])].some((m) => + [...m.importers].some((m) => m.id && !isCSSRequest(m.id)), + ) + if (isServerCss) { + mod.isSelfAccepting = true + } + } + } + }, + }, + }, { name: 'rsc:css-virtual', resolveId(source) { From 885ad2a9d02f1cd1b33da61cd2acea3c72fc8169 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 12 Sep 2025 16:00:21 +0900 Subject: [PATCH 2/5] chore: cleanup --- packages/plugin-rsc/src/plugin.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/plugin-rsc/src/plugin.ts b/packages/plugin-rsc/src/plugin.ts index 2223df89..46df4eb3 100644 --- a/packages/plugin-rsc/src/plugin.ts +++ b/packages/plugin-rsc/src/plugin.ts @@ -563,11 +563,7 @@ export default function vitePluginRsc( async hotUpdate(ctx) { if (isCSSRequest(ctx.file)) { if (this.environment.name === 'client') { - // filter out `.css?direct` (injected by SSR) to avoid browser full reload - // when changing non-self accepting css such as `module.css`. - return ctx.modules.filter( - (m) => !(m.id?.includes('?direct') && !m.isSelfAccepting), - ) + return } } From 2af36d53fa75cfa11d5c1bb3e95034706144192f Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 12 Sep 2025 16:02:49 +0900 Subject: [PATCH 3/5] chore: comment --- packages/plugin-rsc/src/plugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-rsc/src/plugin.ts b/packages/plugin-rsc/src/plugin.ts index 46df4eb3..9441bf4c 100644 --- a/packages/plugin-rsc/src/plugin.ts +++ b/packages/plugin-rsc/src/plugin.ts @@ -1973,7 +1973,7 @@ function vitePluginRscCss( }, }, { - // self accept css module used in server component to avoid full reload + // self accept css module imported in rsc environment to avoid full reload // https://github.com/vitejs/vite/blob/84079a84ad94de4c1ef4f1bdb2ab448ff2c01196/packages/vite/src/node/plugins/css.ts#L1096 name: 'rsc:rsc-css-self-accept', apply: 'serve', From 8992a2ffb7f88652ee1cccd08eb2417142ff6e87 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 12 Sep 2025 16:15:25 +0900 Subject: [PATCH 4/5] fix: fix css module on ssr environment --- packages/plugin-rsc/src/plugin.ts | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/packages/plugin-rsc/src/plugin.ts b/packages/plugin-rsc/src/plugin.ts index 9441bf4c..6492c638 100644 --- a/packages/plugin-rsc/src/plugin.ts +++ b/packages/plugin-rsc/src/plugin.ts @@ -1973,7 +1973,8 @@ function vitePluginRscCss( }, }, { - // self accept css module imported in rsc environment to avoid full reload + // force self accepting "?direct" css (injected via SSR ``) to avoid full reload. + // this should only apply to css modules // https://github.com/vitejs/vite/blob/84079a84ad94de4c1ef4f1bdb2ab448ff2c01196/packages/vite/src/node/plugins/css.ts#L1096 name: 'rsc:rsc-css-self-accept', apply: 'serve', @@ -1986,20 +1987,9 @@ function vitePluginRscCss( isCSSRequest(id) ) { const mod = this.environment.moduleGraph.getModuleById(id) - const { filename, query } = parseIdQuery(id) - if (mod && !mod.isSelfAccepting && 'direct' in query) { - const serverMods = - manager.server.environments.rsc!.moduleGraph.getModulesByFile( - filename, - ) - // filter out module nodes created by tailwind dependenncy. - // for Vite 7.1, we can use `m.type !== "asset"`. - const isServerCss = [...(serverMods ?? [])].some((m) => - [...m.importers].some((m) => m.id && !isCSSRequest(m.id)), - ) - if (isServerCss) { - mod.isSelfAccepting = true - } + const parsed = parseIdQuery(id) + if (mod && !mod.isSelfAccepting && 'direct' in parsed.query) { + mod.isSelfAccepting = true } } }, From 394529a21eec63a0c20491d6ad4245c82f697520 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 12 Sep 2025 16:17:26 +0900 Subject: [PATCH 5/5] refactor: tweak --- packages/plugin-rsc/src/plugin.ts | 7 ++++--- packages/plugin-rsc/src/plugins/vite-utils.ts | 3 +++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/plugin-rsc/src/plugin.ts b/packages/plugin-rsc/src/plugin.ts index 6492c638..8ab1c4cc 100644 --- a/packages/plugin-rsc/src/plugin.ts +++ b/packages/plugin-rsc/src/plugin.ts @@ -34,6 +34,7 @@ import { generateEncryptionKey, toBase64 } from './utils/encryption-utils' import { createRpcServer } from './utils/rpc' import { cleanUrl, + directRequestRE, evalValue, normalizeViteImportAnalysisUrl, prepareError, @@ -1984,11 +1985,11 @@ function vitePluginRscCss( if ( this.environment.name === 'client' && this.environment.mode === 'dev' && - isCSSRequest(id) + isCSSRequest(id) && + directRequestRE.test(id) ) { const mod = this.environment.moduleGraph.getModuleById(id) - const parsed = parseIdQuery(id) - if (mod && !mod.isSelfAccepting && 'direct' in parsed.query) { + if (mod && !mod.isSelfAccepting) { mod.isSelfAccepting = true } } diff --git a/packages/plugin-rsc/src/plugins/vite-utils.ts b/packages/plugin-rsc/src/plugins/vite-utils.ts index 2f6bd5e3..afa780b1 100644 --- a/packages/plugin-rsc/src/plugins/vite-utils.ts +++ b/packages/plugin-rsc/src/plugins/vite-utils.ts @@ -161,3 +161,6 @@ export function evalValue(rawValue: string): T { `) return fn() } + +// https://github.com/vitejs/vite/blob/84079a84ad94de4c1ef4f1bdb2ab448ff2c01196/packages/vite/src/node/utils.ts#L321 +export const directRequestRE: RegExp = /(\?|&)direct=?(?:&|$)/