Skip to content

Commit 4c4879b

Browse files
hi-ogawaclaude
andauthored
fix(rsc): fix CSS HMR with ?url (#776)
Co-authored-by: Claude <[email protected]>
1 parent 9869e2c commit 4c4879b

File tree

7 files changed

+85
-16
lines changed

7 files changed

+85
-16
lines changed

packages/plugin-rsc/e2e/basic.test.ts

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -632,11 +632,15 @@ function defineTest(f: Fixture) {
632632

633633
async function expectNoDuplicateServerCss(page: Page) {
634634
// check only manually inserted stylesheet link exists
635-
// (toHaveAttribute passes only when locator matches single element)
636-
await expect(page.locator('link[rel="stylesheet"]')).toHaveAttribute(
637-
'href',
638-
'/test-style-server-manual.css',
639-
)
635+
await expect(page.locator('link[rel="stylesheet"]')).toHaveCount(3)
636+
for (const locator of await page
637+
.locator('link[rel="stylesheet"]')
638+
.all()) {
639+
await expect(locator).toHaveAttribute(
640+
'data-precedence',
641+
'test-style-manual-link',
642+
)
643+
}
640644
}
641645

642646
test('no duplicate server css', async ({ page }) => {
@@ -854,6 +858,56 @@ function defineTest(f: Fixture) {
854858
)
855859
})
856860

861+
test('css url client @js', async ({ page }) => {
862+
await page.goto(f.url())
863+
await waitForHydration(page)
864+
await expect(page.locator('.test-style-url-client')).toHaveCSS(
865+
'color',
866+
'rgb(255, 165, 0)',
867+
)
868+
869+
if (f.mode !== 'dev') return
870+
871+
// test client css url HMR
872+
await using _ = await expectNoReload(page)
873+
const editor = f.createEditor('src/routes/style-client/client-url.css')
874+
editor.edit((s) => s.replaceAll('rgb(255, 165, 0)', 'rgb(0, 165, 255)'))
875+
await expect(page.locator('.test-style-url-client')).toHaveCSS(
876+
'color',
877+
'rgb(0, 165, 255)',
878+
)
879+
editor.reset()
880+
await expect(page.locator('.test-style-url-client')).toHaveCSS(
881+
'color',
882+
'rgb(255, 165, 0)',
883+
)
884+
})
885+
886+
test('css url server @js', async ({ page }) => {
887+
await page.goto(f.url())
888+
await waitForHydration(page)
889+
await expect(page.locator('.test-style-url-server')).toHaveCSS(
890+
'color',
891+
'rgb(255, 165, 0)',
892+
)
893+
894+
if (f.mode !== 'dev') return
895+
896+
// test server css url HMR
897+
await using _ = await expectNoReload(page)
898+
const editor = f.createEditor('src/routes/style-server/server-url.css')
899+
editor.edit((s) => s.replaceAll('rgb(255, 165, 0)', 'rgb(0, 165, 255)'))
900+
await expect(page.locator('.test-style-url-server')).toHaveCSS(
901+
'color',
902+
'rgb(0, 165, 255)',
903+
)
904+
editor.reset()
905+
await expect(page.locator('.test-style-url-server')).toHaveCSS(
906+
'color',
907+
'rgb(255, 165, 0)',
908+
)
909+
})
910+
857911
test('tailwind @js', async ({ page }) => {
858912
await page.goto(f.url())
859913
await waitForHydration(page)

packages/plugin-rsc/examples/basic/src/routes/css-queries/client.tsx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,15 @@ export function TestCssQueriesClient(props: {
1212
}) {
1313
const [enabled, setEnabled] = React.useState(false)
1414

15-
function urlWithHmr(href: string) {
16-
if (import.meta.hot) {
17-
href += '?t=' + Date.now()
18-
}
19-
return href
20-
}
21-
2215
return (
2316
<div>
2417
<button onClick={() => setEnabled(!enabled)}>test-css-queries</button>
2518
{enabled && (
2619
<>
27-
<link rel="stylesheet" href={urlWithHmr(cssUrl)} />
20+
<link rel="stylesheet" href={cssUrl} />
2821
<style>{cssInline}</style>
2922
<style>{cssRaw}</style>
30-
<link rel="stylesheet" href={urlWithHmr(props.serverUrl)} />
23+
<link rel="stylesheet" href={props.serverUrl} />
3124
<style>{props.serverInline}</style>
3225
<style>{props.serverRaw}</style>
3326
</>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.test-style-url-client {
2+
color: rgb(255, 165, 0);
3+
}

packages/plugin-rsc/examples/basic/src/routes/style-client/client.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import './client.css'
44
import { TestClientDep } from './client-dep'
55
import styles from './client.module.css'
6+
import styleUrl from './client-url.css?url'
67

78
export function TestStyleClient() {
89
return (
@@ -11,6 +12,12 @@ export function TestStyleClient() {
1112
<div data-testid="css-module-client" className={styles.client}>
1213
test-css-module-client
1314
</div>
15+
<link
16+
rel="stylesheet"
17+
href={styleUrl}
18+
precedence="test-style-manual-link"
19+
/>
20+
<div className="test-style-url-client">test-style-url-client</div>
1421
<TestClientDep />
1522
</>
1623
)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.test-style-url-server {
2+
color: rgb(255, 165, 0);
3+
}

packages/plugin-rsc/examples/basic/src/routes/style-server/server.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import './server.css'
22
import styles from './server.module.css'
3+
import styleUrl from './server-url.css?url'
34

45
export function TestStyleServer() {
56
return (
@@ -8,10 +9,16 @@ export function TestStyleServer() {
89
<div data-testid="css-module-server" className={styles.server}>
910
test-css-module-server
1011
</div>
12+
<link
13+
rel="stylesheet"
14+
href={styleUrl}
15+
precedence="test-style-manual-link"
16+
/>
17+
<div className="test-style-url-server">test-style-url-server</div>
1118
<link
1219
rel="stylesheet"
1320
href="/test-style-server-manual.css"
14-
precedence="test-style-server-manual"
21+
precedence="test-style-manual-link"
1522
/>
1623
<div className="test-style-server-manual">test-style-server-manual</div>
1724
</>

packages/plugin-rsc/src/plugin.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,9 @@ export default function vitePluginRsc(
481481
if (this.environment.name === 'client') {
482482
// filter out `.css?direct` (injected by SSR) to avoid browser full reload
483483
// when changing non-self accepting css such as `module.css`.
484-
return ctx.modules.filter((m) => !m.id?.includes('?direct'))
484+
return ctx.modules.filter(
485+
(m) => !(m.id?.includes('?direct') && !m.isSelfAccepting),
486+
)
485487
}
486488
}
487489

0 commit comments

Comments
 (0)