diff --git a/.changeset/wise-donuts-tickle.md b/.changeset/wise-donuts-tickle.md new file mode 100644 index 000000000000..38b1780ed1ef --- /dev/null +++ b/.changeset/wise-donuts-tickle.md @@ -0,0 +1,5 @@ +--- +"astro": patch +--- + +Fix Astro HMR from a CSS dependency diff --git a/packages/astro/e2e/astro-component.test.js b/packages/astro/e2e/astro-component.test.js index 7308ea292a8a..c96e9b1c4728 100644 --- a/packages/astro/e2e/astro-component.test.js +++ b/packages/astro/e2e/astro-component.test.js @@ -1,5 +1,5 @@ import { expect } from '@playwright/test'; -import { getColor, testFactory } from './test-utils.js'; +import { testFactory } from './test-utils.js'; const test = testFactory({ root: './fixtures/astro-component/' }); @@ -99,7 +99,7 @@ test.describe('Astro component HMR', () => { test('update linked dep Astro style', async ({ page, astro }) => { await page.goto(astro.resolveUrl('/')); let h1 = page.locator('#astro-linked-lib'); - expect(await getColor(h1)).toBe('rgb(255, 0, 0)'); + await expect(h1).toHaveCSS('color', 'rgb(255, 0, 0)'); await Promise.all([ page.waitForLoadState('networkidle'), await astro.editFile('../_deps/astro-linked-lib/Component.astro', (content) => @@ -107,6 +107,6 @@ test.describe('Astro component HMR', () => { ), ]); h1 = page.locator('#astro-linked-lib'); - expect(await getColor(h1)).toBe('rgb(0, 128, 0)'); + await expect(h1).toHaveCSS('color', 'rgb(0, 128, 0)'); }); }); diff --git a/packages/astro/e2e/css.test.js b/packages/astro/e2e/css.test.js index 184e5dba30c7..b302d9d90add 100644 --- a/packages/astro/e2e/css.test.js +++ b/packages/astro/e2e/css.test.js @@ -1,5 +1,5 @@ import { expect } from '@playwright/test'; -import { getColor, testFactory } from './test-utils.js'; +import { testFactory } from './test-utils.js'; const test = testFactory({ root: './fixtures/css/', @@ -20,13 +20,13 @@ test.describe('CSS HMR', () => { await page.goto(astro.resolveUrl('/')); const h = page.locator('h1'); - expect(await getColor(h)).toBe('rgb(255, 0, 0)'); + await expect(h).toHaveCSS('color', 'rgb(255, 0, 0)'); await astro.editFile('./src/styles/main.css', (original) => original.replace('--h1-color: red;', '--h1-color: green;') ); - expect(await getColor(h)).toBe('rgb(0, 128, 0)'); + await expect(h).toHaveCSS('color', 'rgb(0, 128, 0)'); }); test('removes Astro-injected CSS once Vite-injected CSS loads', async ({ page, astro }) => { diff --git a/packages/astro/e2e/fixtures/invalidate-script-deps/package.json b/packages/astro/e2e/fixtures/hmr/package.json similarity index 50% rename from packages/astro/e2e/fixtures/invalidate-script-deps/package.json rename to packages/astro/e2e/fixtures/hmr/package.json index 4b45ad505eb1..f5aa414601d8 100644 --- a/packages/astro/e2e/fixtures/invalidate-script-deps/package.json +++ b/packages/astro/e2e/fixtures/hmr/package.json @@ -1,8 +1,9 @@ { - "name": "@e2e/invalidate-script-deps", + "name": "@e2e/hmr", "version": "0.0.0", "private": true, "devDependencies": { - "astro": "workspace:*" + "astro": "workspace:*", + "sass": "^1.66.1" } } diff --git a/packages/astro/e2e/fixtures/hmr/src/pages/css-dep.astro b/packages/astro/e2e/fixtures/hmr/src/pages/css-dep.astro new file mode 100644 index 000000000000..38f4e7409713 --- /dev/null +++ b/packages/astro/e2e/fixtures/hmr/src/pages/css-dep.astro @@ -0,0 +1,14 @@ + + + Test + + +

This is blue

+ + + diff --git a/packages/astro/e2e/fixtures/invalidate-script-deps/src/pages/index.astro b/packages/astro/e2e/fixtures/hmr/src/pages/script-dep.astro similarity index 100% rename from packages/astro/e2e/fixtures/invalidate-script-deps/src/pages/index.astro rename to packages/astro/e2e/fixtures/hmr/src/pages/script-dep.astro diff --git a/packages/astro/e2e/fixtures/invalidate-script-deps/src/scripts/heading.js b/packages/astro/e2e/fixtures/hmr/src/scripts/heading.js similarity index 100% rename from packages/astro/e2e/fixtures/invalidate-script-deps/src/scripts/heading.js rename to packages/astro/e2e/fixtures/hmr/src/scripts/heading.js diff --git a/packages/astro/e2e/fixtures/hmr/src/styles/vars.scss b/packages/astro/e2e/fixtures/hmr/src/styles/vars.scss new file mode 100644 index 000000000000..5deae109febe --- /dev/null +++ b/packages/astro/e2e/fixtures/hmr/src/styles/vars.scss @@ -0,0 +1 @@ +$color: blue; \ No newline at end of file diff --git a/packages/astro/e2e/invalidate-script-deps.test.js b/packages/astro/e2e/hmr.test.js similarity index 57% rename from packages/astro/e2e/invalidate-script-deps.test.js rename to packages/astro/e2e/hmr.test.js index fe37ece8fea0..091aa716d689 100644 --- a/packages/astro/e2e/invalidate-script-deps.test.js +++ b/packages/astro/e2e/hmr.test.js @@ -2,7 +2,7 @@ import { expect } from '@playwright/test'; import { testFactory } from './test-utils.js'; const test = testFactory({ - root: './fixtures/invalidate-script-deps/', + root: './fixtures/hmr/', }); let devServer; @@ -17,7 +17,7 @@ test.afterAll(async () => { test.describe('Scripts with dependencies', () => { test('refresh with HMR', async ({ page, astro }) => { - await page.goto(astro.resolveUrl('/')); + await page.goto(astro.resolveUrl('/script-dep')); const h = page.locator('h1'); await expect(h, 'original text set').toHaveText('before'); @@ -29,3 +29,16 @@ test.describe('Scripts with dependencies', () => { await expect(h, 'text changed').toHaveText('after'); }); }); + +test.describe('Styles with dependencies', () => { + test('refresh with HMR', async ({ page, astro }) => { + await page.goto(astro.resolveUrl('/css-dep')); + + const h = page.locator('h1'); + await expect(h).toHaveCSS('color', 'rgb(0, 0, 255)'); + + await astro.editFile('./src/styles/vars.scss', (original) => original.replace('blue', 'red')); + + await expect(h).toHaveCSS('color', 'rgb(255, 0, 0)'); + }); +}); diff --git a/packages/astro/e2e/test-utils.js b/packages/astro/e2e/test-utils.js index 0768bff81bc8..79b7601b7142 100644 --- a/packages/astro/e2e/test-utils.js +++ b/packages/astro/e2e/test-utils.js @@ -71,13 +71,6 @@ export async function getErrorOverlayContent(page) { return { message, hint, absoluteFileLocation, fileLocation }; } -/** - * @returns {Promise} - */ -export async function getColor(el) { - return await el.evaluate((e) => getComputedStyle(e).color); -} - /** * Wait for `astro-island` that contains the `el` to hydrate * @param {import('@playwright/test').Page} page diff --git a/packages/astro/src/vite-plugin-astro/hmr.ts b/packages/astro/src/vite-plugin-astro/hmr.ts index 65186af5e3f8..6600b2f42271 100644 --- a/packages/astro/src/vite-plugin-astro/hmr.ts +++ b/packages/astro/src/vite-plugin-astro/hmr.ts @@ -90,7 +90,7 @@ export async function handleHotUpdate( // Bugfix: sometimes style URLs get normalized and end with `lang.css=` // These will cause full reloads, so filter them out here - const mods = ctx.modules.filter((m) => !m.url.endsWith('=')); + const mods = [...filtered].filter((m) => !m.url.endsWith('=')); const file = ctx.file.replace(config.root.pathname, '/'); // If only styles are changed, remove the component file from the update list @@ -109,17 +109,6 @@ export async function handleHotUpdate( } } - // If this is a module that is imported from a