Repository navigation
fix(dev): refresh stale CSS for component <style> block HMR - #17383
Conversation
🦋 Changeset detectedLatest commit: d365a8c The changes in this PR will be included in the next version bump. Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
felmonon
left a comment
There was a problem hiding this comment.
Traced this against main to confirm the root cause; the fix direction looks right.
Root cause verified: on main, an Astro component style virtual module (/src/Component.astro?astro&type=style&index=0&lang.css) is never classified as a style module — hasStyleExtension fails on both mod.file (.astro) and mod.id.split('?')[0] (also .astro) — so it falls through to the generic branch. When the module also exists in the client graph, the update is skipped outright (clientModule != null → continue), meaning the hasSkippedStyleModules path never runs and the per-route dev-css virtual modules are never invalidated — so the inline anti-FOUC styles keep serving stale CSS until a dev-server restart. Classifying via parseAstroRequest is the right discriminator, and the query-order-permutation test is a good catch given the params have no guaranteed order.
The SSR-only special case is also justified as written: without it, the new classification would route SSR-only style modules into the skip path, where there is no client-side CSS HMR to actually deliver the update — restoring invalidate + full-reload for exactly that sub-case preserves main's behavior for those modules. A one-line comment on the new branch saying "no client module means nothing will apply the CSS update client-side, so force a reload" would make the asymmetry (one sub-case skips, the other reloads) obvious to the next reader.
Non-blocking nit: isAstroStyleModule parses the query twice per style module (once inside isStyleModule, once in the hotUpdate branch). Trivial cost, but hoisting the parse result would avoid it.
Unit coverage (css/scss/less, query-order permutations, ws expectations) looks solid.
… into astro-css-fix
… into astro-css-fix
|
Noticed this same issue was happening for other framework The same stale dev CSS path can happen for Svelte and Vue style block modules like:
These are collected by Astro’s dev CSS graph, but were not recognised by The fix now classifies Astro/Svelte/Vue style block requests explicitly, keeps the client-CSS-HMR path when a client module exists, and keeps the SSR invalidation/full-reload fallback when no client module exists. I've personally tested and verified that with this fix, component |
<style> block HMR
|
@matthewp would you mind giving this a review when you have a chance? This builds on my previous PR you approved #16957 and includes some cases I missed. It addresses a dev CSS HMR regression that’s been around since the Astro 5 to Astro 6 transition, and I think it would be valuable to get into the next release if possible. |
|
@thelazylamaGit Yes, adding it to my review stack, thanks! |
|
Noticed after some more testing that normal CSS files could be swallowed when no client style module was available, requiring a manual reload. This was because the previous PR logic invalidated This now does one exact client lookup first, then falls back to |
|
Note whilst this PR fixes some genuine bugs and makes css hmr better than it was, its still not perfect and can cause some false positives due to The alternative which is doing exact matches only would result in forcing full reloads a lot of the time even when it doesn't necessarily have to. I'm going to do some more investigating into how vite 8 client modules work and do another PR that hopefully should fix this and prevent false positives whilst still allowing hot-reloads when applicable. |
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [@astrojs/markdown-remark](https://astro.build) ([source](https://github.com/withastro/astro/tree/HEAD/packages/markdown/remark)) | [`7.2.1` → `7.2.2`](https://renovatebot.com/diffs/npm/@astrojs%2fmarkdown-remark/7.2.1/7.2.2) |  |  | | [astro](https://astro.build) ([source](https://github.com/withastro/astro/tree/HEAD/packages/astro)) | [`7.1.4` → `7.1.6`](https://renovatebot.com/diffs/npm/astro/7.1.4/7.1.6) |  |  | --- ### Release Notes <details> <summary>withastro/astro (@​astrojs/markdown-remark)</summary> ### [`v7.2.2`](https://github.com/withastro/astro/blob/HEAD/packages/markdown/remark/CHANGELOG.md#722) [Compare Source](https://github.com/withastro/astro/compare/@astrojs/markdown-remark@7.2.1...@astrojs/markdown-remark@7.2.2) ##### Patch Changes - Updated dependencies \[[`c895b12`](withastro/astro@c895b12)]: - [@​astrojs/internal-helpers](https://github.com/astrojs/internal-helpers)@​0.10.2 </details> <details> <summary>withastro/astro (astro)</summary> ### [`v7.1.6`](https://github.com/withastro/astro/blob/HEAD/packages/astro/CHANGELOG.md#716) [Compare Source](https://github.com/withastro/astro/compare/astro@7.1.5...astro@7.1.6) ##### Patch Changes - [#​17536](withastro/astro#17536) [`ff97b86`](withastro/astro@ff97b86) Thanks [@​dmgawel](https://github.com/dmgawel)! - Fixes concurrent static builds failing to generate i18n rewrite fallbacks for dynamic routes - [#​17383](withastro/astro#17383) [`296e1b0`](withastro/astro@296e1b0) Thanks [@​thelazylamaGit](https://github.com/thelazylamaGit)! - Fixes stale dev CSS after editing component style blocks and CSS files in dev - [#​17543](withastro/astro#17543) [`bbc1ec9`](withastro/astro@bbc1ec9) Thanks [@​ematipico](https://github.com/ematipico)! - Adds a feature to `experimental.collectionStorage` that allows to change the size of chunks. For example, you can reduce the size of chunks to 1MB: ```js // astro.config.mjs import { defineConfig } from 'astro/config'; export default defineConfig({ experimental: { collectionStorage: { type: 'chunked', chunkSize: 1024 * 1024, }, }, }); ``` - [#​17545](withastro/astro#17545) [`5214663`](withastro/astro@5214663) Thanks [@​ematipico](https://github.com/ematipico)! - Bumps the Astro compiler to the latest version. [Changelog](https://github.com/withastro/compiler-rs/releases/tag/%40astrojs%2Fcompiler-rs%400.3.2). ### [`v7.1.5`](https://github.com/withastro/astro/blob/HEAD/packages/astro/CHANGELOG.md#715) [Compare Source](https://github.com/withastro/astro/compare/astro@7.1.4...astro@7.1.5) ##### Patch Changes - [#​17524](withastro/astro#17524) [`7613030`](withastro/astro@7613030) Thanks [@​matthewp](https://github.com/matthewp)! - Fixes a bug where an error while finalizing a request could prevent a response from being sent - [#​17480](withastro/astro#17480) [`f61ba9c`](withastro/astro@f61ba9c) Thanks [@​florian-lefebvre](https://github.com/florian-lefebvre)! - Fixes a case where a custom `logger.entrypoint` failed to load at runtime in a built server bundle. - [#​17525](withastro/astro#17525) [`e614b7b`](withastro/astro@e614b7b) Thanks [@​matthewp](https://github.com/matthewp)! - Fixes action path resolution so that properties of a resolved action function are not treated as routable path segments - [#​17284](withastro/astro#17284) [`c775c1f`](withastro/astro@c775c1f) Thanks [@​matthewp](https://github.com/matthewp)! - Fixes a bug where the custom 404 (or 500) page was not rendered when a middleware rewrite targeted a route that returned an empty 404/500 response, and a blank page was returned instead - [#​17474](withastro/astro#17474) [`c895b12`](withastro/astro@c895b12) Thanks [@​nicksnyder](https://github.com/nicksnyder)! - Updates dependency `js-yaml` to v4.3.0 - Updated dependencies \[[`c895b12`](withastro/astro@c895b12)]: - [@​astrojs/internal-helpers](https://github.com/astrojs/internal-helpers)@​0.10.2 - [@​astrojs/markdown-remark](https://github.com/astrojs/markdown-remark)@​7.2.2 - [@​astrojs/markdown-satteri](https://github.com/astrojs/markdown-satteri)@​0.3.5 </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODEuMSIsInVwZGF0ZWRJblZlciI6IjQzLjI4MS4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->
Changes
<style>block cases to dev CSS HMR handling.Fixes stale dev CSS after editing component style blocks that are compiled into virtual CSS modules.
Astro’s dev CSS collector already treats style block requests like these as CSS:
*.astro?astro&type=style...*.svelte?svelte&type=style...*.vue?vue&type=style...But
astro:hmr-reloadonly recognized real CSS file paths, so these style block modules could skip the per-routevirtual:astro:dev-css:*invalidation path. This caused stale SSR/dev CSS after HMR edits.This PR classifies Astro, Svelte, and Vue style block requests as style modules, invalidates per-route dev CSS when client CSS HMR can handle the update, and preserves SSR invalidation/full reload when no client module exists to apply the update.
Also addresses #17083
Testing
Added unit coverage for Astro, Svelte, and Vue style block virtual modules invalidating per-route dev CSS modules.
Added coverage for SSR-only style block modules using SSR invalidation/full reload.
Added negative coverage for non-style component queries, raw CSS imports, unrelated
type=stylerequests, and component-style-looking requests without the matching compiler marker.Docs