From d9c5e952ccb2645e8fac568f11dcc35b8851a019 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 1 Aug 2025 10:23:56 +0900 Subject: [PATCH 1/3] fix(rsc): avoid unnecessary server hmr due to tailwind module deps --- .../examples/basic/src/routes/tailwind/unused.tsx | 1 + packages/plugin-rsc/src/plugin.ts | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 packages/plugin-rsc/examples/basic/src/routes/tailwind/unused.tsx diff --git a/packages/plugin-rsc/examples/basic/src/routes/tailwind/unused.tsx b/packages/plugin-rsc/examples/basic/src/routes/tailwind/unused.tsx new file mode 100644 index 000000000..9599c3bb3 --- /dev/null +++ b/packages/plugin-rsc/examples/basic/src/routes/tailwind/unused.tsx @@ -0,0 +1 @@ +console.log('unused file text-[#f12345]') diff --git a/packages/plugin-rsc/src/plugin.ts b/packages/plugin-rsc/src/plugin.ts index a8b946ea2..fa0e7e552 100644 --- a/packages/plugin-rsc/src/plugin.ts +++ b/packages/plugin-rsc/src/plugin.ts @@ -398,6 +398,16 @@ export default function vitePluginRsc( if (!isInsideClientBoundary(ctx.modules)) { if (this.environment.name === 'rsc') { + // detect if this module is only created as css deps (e.g. tailwind) + // (NOTE: this is not necessary since Vite 7.1.0-beta.0 https://github.com/vitejs/vite/pull/20391 ) + if ( + ctx.modules + .flatMap((m) => [...m.importers]) + .every((m) => m.id && isCSSRequest(m.id)) + ) { + return + } + // transform js to surface syntax errors for (const mod of ctx.modules) { if (mod.type === 'js') { @@ -426,6 +436,7 @@ export default function vitePluginRsc( // Server files can be included in client module graph, for example, // when `addWatchFile` is used to track js files as style dependency (e.g. tailwind) // In this case, reload all importers (for css hmr), and return empty modules to avoid full-reload. + // (NOTE: this is not necessary since Vite 7.1.0-beta.0 https://github.com/vitejs/vite/pull/20391 ) const env = ctx.server.environments.rsc! const mod = env.moduleGraph.getModuleById(ctx.file) if (mod) { From 98e3c9c1fefca9c2760fa3c15b8ff3cec2c089e7 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 1 Aug 2025 10:34:20 +0900 Subject: [PATCH 2/3] fix: tweak condition --- packages/plugin-rsc/examples/basic/src/styles.css | 2 +- packages/plugin-rsc/src/plugin.ts | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/plugin-rsc/examples/basic/src/styles.css b/packages/plugin-rsc/examples/basic/src/styles.css index e34d4399d..2cb11909b 100644 --- a/packages/plugin-rsc/examples/basic/src/styles.css +++ b/packages/plugin-rsc/examples/basic/src/styles.css @@ -1,4 +1,4 @@ -@import 'tailwindcss' source('./'); +@import 'tailwindcss'; button { @apply bg-gray-100 mx-1 px-2 border hover:bg-gray-200 active:bg-gray-300; diff --git a/packages/plugin-rsc/src/plugin.ts b/packages/plugin-rsc/src/plugin.ts index fa0e7e552..e895c8531 100644 --- a/packages/plugin-rsc/src/plugin.ts +++ b/packages/plugin-rsc/src/plugin.ts @@ -400,12 +400,14 @@ export default function vitePluginRsc( if (this.environment.name === 'rsc') { // detect if this module is only created as css deps (e.g. tailwind) // (NOTE: this is not necessary since Vite 7.1.0-beta.0 https://github.com/vitejs/vite/pull/20391 ) - if ( - ctx.modules - .flatMap((m) => [...m.importers]) - .every((m) => m.id && isCSSRequest(m.id)) - ) { - return + if (ctx.modules.length === 1) { + const importers = [...ctx.modules[0]!.importers] + if ( + importers.length > 0 && + importers.every((m) => m.id && isCSSRequest(m.id)) + ) { + return + } } // transform js to surface syntax errors From 8a9e3f8ea0c8a88a3a3e1b5017215341c69f89f6 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 1 Aug 2025 11:05:55 +0900 Subject: [PATCH 3/3] test: add e2e --- packages/plugin-rsc/e2e/basic.test.ts | 18 ++++++++++++++++++ packages/plugin-rsc/e2e/fixture.ts | 3 +++ .../basic/src/framework/entry.browser.tsx | 3 ++- .../basic/src/routes/tailwind/unused.tsx | 2 +- packages/plugin-rsc/src/plugin.ts | 2 +- 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/packages/plugin-rsc/e2e/basic.test.ts b/packages/plugin-rsc/e2e/basic.test.ts index 6fff84076..a2c9e4c20 100644 --- a/packages/plugin-rsc/e2e/basic.test.ts +++ b/packages/plugin-rsc/e2e/basic.test.ts @@ -637,6 +637,24 @@ function defineTest(f: Fixture) { 'rgb(255, 0, 0)', ) }) + + test('tailwind no redundant server hmr', async ({ page }) => { + await page.goto(f.url()) + await waitForHydration(page) + const logs: string[] = [] + page.on('console', (msg) => { + if (msg.type() === 'log') { + logs.push(msg.text()) + } + }) + f.createEditor('src/routes/tailwind/unused.tsx').resave() + await page.waitForTimeout(200) + f.createEditor('src/routes/tailwind/server.tsx').resave() + await page.waitForTimeout(200) + expect(logs).toEqual([ + expect.stringMatching(/\[vite-rsc:update\].*\/tailwind\/server.tsx/), + ]) + }) }) test('temporary references @js', async ({ page }) => { diff --git a/packages/plugin-rsc/e2e/fixture.ts b/packages/plugin-rsc/e2e/fixture.ts index aa61f332a..1848ba3f5 100644 --- a/packages/plugin-rsc/e2e/fixture.ts +++ b/packages/plugin-rsc/e2e/fixture.ts @@ -142,6 +142,9 @@ export function useFixture(options: { reset(): void { fs.writeFileSync(filepath, originalFiles[filepath]!) }, + resave(): void { + fs.writeFileSync(filepath, current) + }, } } diff --git a/packages/plugin-rsc/examples/basic/src/framework/entry.browser.tsx b/packages/plugin-rsc/examples/basic/src/framework/entry.browser.tsx index 473fc492d..1998e86ff 100644 --- a/packages/plugin-rsc/examples/basic/src/framework/entry.browser.tsx +++ b/packages/plugin-rsc/examples/basic/src/framework/entry.browser.tsx @@ -70,7 +70,8 @@ async function main() { // implement server HMR by trigering re-fetch/render of RSC upon server code change if (import.meta.hot) { - import.meta.hot.on('rsc:update', () => { + import.meta.hot.on('rsc:update', (e) => { + console.log('[vite-rsc:update]', e.file) fetchRscPayload() }) } diff --git a/packages/plugin-rsc/examples/basic/src/routes/tailwind/unused.tsx b/packages/plugin-rsc/examples/basic/src/routes/tailwind/unused.tsx index 9599c3bb3..98476b011 100644 --- a/packages/plugin-rsc/examples/basic/src/routes/tailwind/unused.tsx +++ b/packages/plugin-rsc/examples/basic/src/routes/tailwind/unused.tsx @@ -1 +1 @@ -console.log('unused file text-[#f12345]') +console.log(
unused
) diff --git a/packages/plugin-rsc/src/plugin.ts b/packages/plugin-rsc/src/plugin.ts index e895c8531..3016a3b68 100644 --- a/packages/plugin-rsc/src/plugin.ts +++ b/packages/plugin-rsc/src/plugin.ts @@ -406,7 +406,7 @@ export default function vitePluginRsc( importers.length > 0 && importers.every((m) => m.id && isCSSRequest(m.id)) ) { - return + return [] } }