Fix Astro HMR from a CSS dependency (#8609)
* Fix Astro HMR from a CSS dependency * Improve css test * Create wise-donuts-tickle.md
This commit is contained in:
parent
e8c997db99
commit
5a988eaf60
12 changed files with 54 additions and 35 deletions
5
.changeset/wise-donuts-tickle.md
Normal file
5
.changeset/wise-donuts-tickle.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
"astro": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix Astro HMR from a CSS dependency
|
|
@ -1,5 +1,5 @@
|
||||||
import { expect } from '@playwright/test';
|
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/' });
|
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 }) => {
|
test('update linked dep Astro style', async ({ page, astro }) => {
|
||||||
await page.goto(astro.resolveUrl('/'));
|
await page.goto(astro.resolveUrl('/'));
|
||||||
let h1 = page.locator('#astro-linked-lib');
|
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([
|
await Promise.all([
|
||||||
page.waitForLoadState('networkidle'),
|
page.waitForLoadState('networkidle'),
|
||||||
await astro.editFile('../_deps/astro-linked-lib/Component.astro', (content) =>
|
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');
|
h1 = page.locator('#astro-linked-lib');
|
||||||
expect(await getColor(h1)).toBe('rgb(0, 128, 0)');
|
await expect(h1).toHaveCSS('color', 'rgb(0, 128, 0)');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { expect } from '@playwright/test';
|
import { expect } from '@playwright/test';
|
||||||
import { getColor, testFactory } from './test-utils.js';
|
import { testFactory } from './test-utils.js';
|
||||||
|
|
||||||
const test = testFactory({
|
const test = testFactory({
|
||||||
root: './fixtures/css/',
|
root: './fixtures/css/',
|
||||||
|
@ -20,13 +20,13 @@ test.describe('CSS HMR', () => {
|
||||||
await page.goto(astro.resolveUrl('/'));
|
await page.goto(astro.resolveUrl('/'));
|
||||||
|
|
||||||
const h = page.locator('h1');
|
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) =>
|
await astro.editFile('./src/styles/main.css', (original) =>
|
||||||
original.replace('--h1-color: red;', '--h1-color: green;')
|
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 }) => {
|
test('removes Astro-injected CSS once Vite-injected CSS loads', async ({ page, astro }) => {
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
{
|
{
|
||||||
"name": "@e2e/invalidate-script-deps",
|
"name": "@e2e/hmr",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"astro": "workspace:*"
|
"astro": "workspace:*",
|
||||||
|
"sass": "^1.66.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
14
packages/astro/e2e/fixtures/hmr/src/pages/css-dep.astro
Normal file
14
packages/astro/e2e/fixtures/hmr/src/pages/css-dep.astro
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Test</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1 class="css-dep">This is blue</h1>
|
||||||
|
<style lang="scss">
|
||||||
|
@use "../styles/vars.scss" as *;
|
||||||
|
.css-dep {
|
||||||
|
color: $color;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</body>
|
||||||
|
</html>
|
1
packages/astro/e2e/fixtures/hmr/src/styles/vars.scss
Normal file
1
packages/astro/e2e/fixtures/hmr/src/styles/vars.scss
Normal file
|
@ -0,0 +1 @@
|
||||||
|
$color: blue;
|
|
@ -2,7 +2,7 @@ import { expect } from '@playwright/test';
|
||||||
import { testFactory } from './test-utils.js';
|
import { testFactory } from './test-utils.js';
|
||||||
|
|
||||||
const test = testFactory({
|
const test = testFactory({
|
||||||
root: './fixtures/invalidate-script-deps/',
|
root: './fixtures/hmr/',
|
||||||
});
|
});
|
||||||
|
|
||||||
let devServer;
|
let devServer;
|
||||||
|
@ -17,7 +17,7 @@ test.afterAll(async () => {
|
||||||
|
|
||||||
test.describe('Scripts with dependencies', () => {
|
test.describe('Scripts with dependencies', () => {
|
||||||
test('refresh with HMR', async ({ page, astro }) => {
|
test('refresh with HMR', async ({ page, astro }) => {
|
||||||
await page.goto(astro.resolveUrl('/'));
|
await page.goto(astro.resolveUrl('/script-dep'));
|
||||||
|
|
||||||
const h = page.locator('h1');
|
const h = page.locator('h1');
|
||||||
await expect(h, 'original text set').toHaveText('before');
|
await expect(h, 'original text set').toHaveText('before');
|
||||||
|
@ -29,3 +29,16 @@ test.describe('Scripts with dependencies', () => {
|
||||||
await expect(h, 'text changed').toHaveText('after');
|
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)');
|
||||||
|
});
|
||||||
|
});
|
|
@ -71,13 +71,6 @@ export async function getErrorOverlayContent(page) {
|
||||||
return { message, hint, absoluteFileLocation, fileLocation };
|
return { message, hint, absoluteFileLocation, fileLocation };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {Promise<string>}
|
|
||||||
*/
|
|
||||||
export async function getColor(el) {
|
|
||||||
return await el.evaluate((e) => getComputedStyle(e).color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wait for `astro-island` that contains the `el` to hydrate
|
* Wait for `astro-island` that contains the `el` to hydrate
|
||||||
* @param {import('@playwright/test').Page} page
|
* @param {import('@playwright/test').Page} page
|
||||||
|
|
|
@ -90,7 +90,7 @@ export async function handleHotUpdate(
|
||||||
|
|
||||||
// Bugfix: sometimes style URLs get normalized and end with `lang.css=`
|
// Bugfix: sometimes style URLs get normalized and end with `lang.css=`
|
||||||
// These will cause full reloads, so filter them out here
|
// 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, '/');
|
const file = ctx.file.replace(config.root.pathname, '/');
|
||||||
|
|
||||||
// If only styles are changed, remove the component file from the update list
|
// 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 <script>, invalidate the Astro
|
|
||||||
// component so that it is cached by the time the script gets transformed.
|
|
||||||
for (const mod of filtered) {
|
|
||||||
if (mod.id && isAstroScript(mod.id) && mod.file) {
|
|
||||||
const astroMod = ctx.server.moduleGraph.getModuleById(mod.file);
|
|
||||||
if (astroMod) {
|
|
||||||
mods.unshift(astroMod);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Svelte files should be marked as `isSelfAccepting` but they don't appear to be
|
// TODO: Svelte files should be marked as `isSelfAccepting` but they don't appear to be
|
||||||
const isSelfAccepting = mods.every((m) => m.isSelfAccepting || m.url.endsWith('.svelte'));
|
const isSelfAccepting = mods.every((m) => m.isSelfAccepting || m.url.endsWith('.svelte'));
|
||||||
if (isSelfAccepting) {
|
if (isSelfAccepting) {
|
||||||
|
|
|
@ -992,6 +992,15 @@ importers:
|
||||||
specifier: ^3.3.4
|
specifier: ^3.3.4
|
||||||
version: 3.3.4
|
version: 3.3.4
|
||||||
|
|
||||||
|
packages/astro/e2e/fixtures/hmr:
|
||||||
|
devDependencies:
|
||||||
|
astro:
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../../..
|
||||||
|
sass:
|
||||||
|
specifier: ^1.66.1
|
||||||
|
version: 1.66.1
|
||||||
|
|
||||||
packages/astro/e2e/fixtures/hydration-race:
|
packages/astro/e2e/fixtures/hydration-race:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@astrojs/preact':
|
'@astrojs/preact':
|
||||||
|
@ -1004,12 +1013,6 @@ importers:
|
||||||
specifier: ^10.17.1
|
specifier: ^10.17.1
|
||||||
version: 10.17.1
|
version: 10.17.1
|
||||||
|
|
||||||
packages/astro/e2e/fixtures/invalidate-script-deps:
|
|
||||||
devDependencies:
|
|
||||||
astro:
|
|
||||||
specifier: workspace:*
|
|
||||||
version: link:../../..
|
|
||||||
|
|
||||||
packages/astro/e2e/fixtures/lit-component:
|
packages/astro/e2e/fixtures/lit-component:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@astrojs/lit':
|
'@astrojs/lit':
|
||||||
|
|
Loading…
Reference in a new issue