Inject styles from dynamically imported components on first dev server load#15988
Merged
matthewp merged 4 commits intowithastro:mainfrom Mar 19, 2026
Merged
Conversation
… dev load In Astro 6, `collectCSSWithOrder()` walks the Vite module graph to find CSS dependencies, but dynamically imported modules are registered in the graph without being transformed yet — their `importedModules` set is empty, so the CSS walk terminates prematurely and their styles are never injected. Add `ensureModulesLoaded()` which recursively walks the graph and eagerly fetches any untransformed modules via `env.fetchModule()` before the CSS collection walk runs. This populates each module's `importedModules` set, making CSS dependencies from dynamically imported components visible on the first page load. Fixes withastro#15983
🦋 Changeset detectedLatest commit: 78e94a9 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 |
There was a problem hiding this comment.
Pull request overview
This PR fixes a dev-mode regression where CSS from components loaded via await import() in Astro frontmatter was not injected on the first page request, restoring behavior consistent with Astro 5.
Changes:
- Add an
ensureModulesLoaded()pre-walk that eagerly fetches/transforms reachable (previously untransformed) Vite modules before collecting CSS dependencies. - Add a dev-mode integration test + fixture to assert dynamic-imported component styles are present on the first dev server load.
- Add a changeset describing the patch release.
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| packages/astro/src/vite-plugin-css/index.ts | Preloads/transforms reachable module graph nodes before the CSS dependency walk in dev. |
| packages/astro/test/css-dynamic-import-dev.test.js | New integration test asserting styles from a dynamically imported layout are present on first load. |
| packages/astro/test/fixtures/css-dynamic-import-dev/package.json | Fixture package manifest for the new dev-mode regression test. |
| packages/astro/test/fixtures/css-dynamic-import-dev/src/pages/index.astro | Fixture page that dynamically imports a layout in frontmatter. |
| packages/astro/test/fixtures/css-dynamic-import-dev/src/layouts/Layout.astro | Fixture layout containing a <style> block that must be injected on first request. |
| .gitignore | Adds .claude to ignored files. |
| .changeset/fix-dynamic-import-css-dev.md | Patch changeset documenting the regression fix. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+49
to
+54
| if (seen.has(id)) return; | ||
| seen.add(id); | ||
|
|
||
| for (const imp of mod.importedModules) { | ||
| if (!imp.id) continue; | ||
| if (seen.has(imp.id)) continue; |
matthewp
approved these changes
Mar 19, 2026
Merged
1 task
dadezzz
pushed a commit
to dadezzz/ice-notes
that referenced
this pull request
Mar 24, 2026
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [astro](https://astro.build) ([source](https://github.com/withastro/astro/tree/HEAD/packages/astro)) | [`6.0.6` → `6.0.8`](https://renovatebot.com/diffs/npm/astro/6.0.6/6.0.8) |  |  | --- ### Release Notes <details> <summary>withastro/astro (astro)</summary> ### [`v6.0.8`](https://github.com/withastro/astro/blob/HEAD/packages/astro/CHANGELOG.md#608) [Compare Source](https://github.com/withastro/astro/compare/astro@6.0.7...astro@6.0.8) ##### Patch Changes - [#​15978](withastro/astro#15978) [`6d182fe`](withastro/astro@6d182fe) Thanks [@​seroperson](https://github.com/seroperson)! - Fixes a bug where Astro Actions didn't properly support nested object properties, causing problems when users used zod functions such as `superRefine` or `discriminatedUnion`. - [#​16011](withastro/astro#16011) [`e752170`](withastro/astro@e752170) Thanks [@​matthewp](https://github.com/matthewp)! - Fixes a dev server hang on the first request when using the Cloudflare adapter - [#​15997](withastro/astro#15997) [`1fddff7`](withastro/astro@1fddff7) Thanks [@​ematipico](https://github.com/ematipico)! - Fixes `Astro.rewrite()` failing when the target path contains duplicate slashes (e.g. `//about`). The duplicate slashes are now collapsed before URL parsing, preventing them from being interpreted as a protocol-relative URL. ### [`v6.0.7`](https://github.com/withastro/astro/blob/HEAD/packages/astro/CHANGELOG.md#607) [Compare Source](https://github.com/withastro/astro/compare/astro@6.0.6...astro@6.0.7) ##### Patch Changes - [#​15950](withastro/astro#15950) [`acce5e8`](withastro/astro@acce5e8) Thanks [@​matthewp](https://github.com/matthewp)! - Fixes a build regression in projects with multiple frontend integrations where `server:defer` server islands could fail at runtime when all pages are prerendered. - [#​15988](withastro/astro#15988) [`c93b4a0`](withastro/astro@c93b4a0) Thanks [@​ossaidqadri](https://github.com/ossaidqadri)! - Fix styles from dynamically imported components not being injected on first dev server load. - [#​15968](withastro/astro#15968) [`3e7a9d5`](withastro/astro@3e7a9d5) Thanks [@​chasemccoy](https://github.com/chasemccoy)! - Fixes `renderMarkdown` in custom content loaders not resolving images in markdown content. Images referenced in markdown processed by `renderMarkdown` are now correctly optimized, matching the behavior of the built-in `glob()` loader. - [#​15990](withastro/astro#15990) [`1e6017f`](withastro/astro@1e6017f) Thanks [@​ematipico](https://github.com/ematipico)! - Fixes an issue where `Astro.currentLocale` would always be the default locale instead of the actual one when using a dynamic route like `[locale].astro` or `[locale]/index.astro`. It now resolves to the correct locale from the URL. - [#​15990](withastro/astro#15990) [`1e6017f`](withastro/astro@1e6017f) Thanks [@​ematipico](https://github.com/ematipico)! - Fixes an issue where visiting an invalid locale URL (e.g. `/asdf/`) would show the content of a dynamic `[locale]` page with a 404 status code, instead of showing your custom 404 page. Now, the correct 404 page is rendered when the locale in the URL doesn't match any configured locale. - [#​15960](withastro/astro#15960) [`1d84020`](withastro/astro@1d84020) Thanks [@​matthewp](https://github.com/matthewp)! - Fixes Cloudflare dev server islands with `prerenderEnvironment: 'node'` by sharing the serialized manifest encryption key across dev environments and routing server island requests through the SSR runtime. - [#​15735](withastro/astro#15735) [`9685e2d`](withastro/astro@9685e2d) Thanks [@​fa-sharp](https://github.com/fa-sharp)! - Fixes an EventEmitter memory leak when serving static pages from Node.js middleware. When using the middleware handler, requests that were being passed on to Express / Fastify (e.g. static files / pre-rendered pages / etc.) weren't cleaning up socket listeners before calling `next()`, causing a memory leak warning. This fix makes sure to run the cleanup before calling `next()`. </details> --- ### Configuration 📅 **Schedule**: 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. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My43Ni4yIiwidXBkYXRlZEluVmVyIjoiNDMuODYuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==--> Co-authored-by: Renovate Bot <renovate@zarantonello.dev> Co-committed-by: Renovate Bot <renovate@zarantonello.dev>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changes
await import()in frontmatter are now injected on the first page request in dev mode. Previously they only appeared after a file save triggered HMR — a regression from Astro 5.collectCSSWithOrder(): dynamically imported modules are registered in the Vite module graph by Vite's import analysis but not yet transformed, so theirimportedModulesset is empty and the CSS walk terminates early. AddedensureModulesLoaded()which recursively walks the graph and eagerly fetches any untransformed modules viaenv.fetchModule()before the CSS collection walk runs.ensureModulesLoaded()mirrors the samePROPAGATED_ASSET_QUERY_PARAMstopping point used bycollectCSSWithOrder(), so it won't descend into propagated asset modules that the CSS walk would intentionally skip — avoiding unnecessary fetches in content collection graphs.Testing
test/css-dynamic-import-dev.test.js) with a fixture whose index page dynamically imports a layout component containing a<style>block. The test starts a dev server, fetches/on first load, and asserts the style is present in the HTML — directly covering the reported regression.css-order-importtests (including the dynamic import build scenario) continue to pass.Docs
Fixes #15983