Repository navigation
fix(astro): stop the head-metadata plugin invalidating its own virtual module - #18007
Conversation
…l module The `astro:head-metadata` transform hook invalidated `virtual:astro:component-metadata` unconditionally, including when the module being transformed was that virtual module itself. The dev app entrypoint imports it, so each invalidation reached the SSR entry chain, the module runner re-evaluated it on the next request, re-fetched the virtual module, and the transform hook invalidated it again. Dev servers using a non-runnable environment re-evaluated the whole server module graph on every request for the lifetime of the process. Fixes withastro#17995
Adds a unit test asserting the plugin does not invalidate the metadata module when transforming it, and a Cloudflare dev-server test that counts the invalidations the transform hook issues once the graph is warm and checks that a layout head edit still reaches the served HTML.
🦋 Changeset detectedLatest commit: 0713352 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 |
|
The red Here: On The three most recent completed This branch's Everything else on this PR is green. |
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)) | [`7.3.3` → `7.3.4`](https://renovatebot.com/diffs/npm/astro/7.3.3/7.3.4) |  |  | --- ### Release Notes <details> <summary>withastro/astro (astro)</summary> ### [`v7.3.4`](https://github.com/withastro/astro/blob/HEAD/packages/astro/CHANGELOG.md#734) [Compare Source](https://github.com/withastro/astro/compare/astro@7.3.3...astro@7.3.4) ##### Patch Changes - [#​18063](withastro/astro#18063) [`40896ac`](withastro/astro@40896ac) Thanks [@​adamchal](https://github.com/adamchal)! - Fixes incremental builds repeatedly rendering unchanged pages when modules or compiled CSS reference bundled assets. - [#​18053](withastro/astro#18053) [`cf5d72f`](withastro/astro@cf5d72f) Thanks [@​Princesseuh](https://github.com/Princesseuh)! - Improves the `astro check` error shown for TypeScript 7. The command now explains that TypeScript 7 is not currently supported and provides instructions for experimentally type-checking Astro files with TypeScript 7.1 and `@astrojs/ts-content-mapper`. - [#​18086](withastro/astro#18086) [`795a7e4`](withastro/astro@795a7e4) Thanks [@​ump45nose](https://github.com/ump45nose)! - Fix double-escaped ampersands in Markdown image `alt` and `title` attributes. The `__ASTRO_IMAGE_` round-trip now decodes the numeric (`&`) and named (`&`) character references the Markdown processors emit, so an `&` in an alt or title is escaped exactly once in the final HTML instead of twice. - [#​18074](withastro/astro#18074) [`0429805`](withastro/astro@0429805) Thanks [@​SurefireStudios](https://github.com/SurefireStudios)! - Fix three error names that did not match their documented reference. `MissingLocale`, `MissingIndexForInternationalization` and `NoManifestAvailable` reported names ending in `Error` in the dev overlay, while their error reference pages are published under the unsuffixed names, so the name shown to users could not be found in the docs. - [#​18007](withastro/astro#18007) [`2245837`](withastro/astro@2245837) Thanks [@​L4XB](https://github.com/L4XB)! - Fixes the dev server re-evaluating the whole server module graph on every request. The `astro:head-metadata` plugin invalidated its component metadata virtual module from its own `transform` hook, so each evaluation of that module scheduled the next one. Adapters that run requests outside Vite's module runner, such as `@astrojs/cloudflare`, paid for a full re-evaluation of the server graph on every request for the lifetime of the process. - [#​18096](withastro/astro#18096) [`43657c4`](withastro/astro@43657c4) Thanks [@​matthewp](https://github.com/matthewp)! - Fixes domain-based i18n routing to respect `security.allowedDomains` when selecting a locale from request host headers - [#​18043](withastro/astro#18043) [`8a53a8b`](withastro/astro@8a53a8b) Thanks [@​astro-factory](https://github.com/apps/astro-factory)! - Fixes `image.responsiveStyles` emitting invalid `object-position` CSS values for same-axis keyword pairs (`top bottom`, `left right`, etc.) - [#​18029](withastro/astro#18029) [`c08252d`](withastro/astro@c08252d) Thanks [@​matthewp](https://github.com/matthewp)! - Runs `astro dev` and `astro preview` in the foreground when an AI agent is detected on Windows, allowing the agent to manage the process lifetime. Pass `--background` explicitly to request an Astro-managed background process. Agent-inferred backgrounding remains enabled on other platforms. - Updated dependencies \[[`3fd16ee`](withastro/astro@3fd16ee), [`8358d59`](withastro/astro@8358d59)]: - [@​astrojs/markdown-satteri](https://github.com/astrojs/markdown-satteri)@0.4.2 </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. 🔕 **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 [Mend Renovate CLI](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xMTUuMiIsInVwZGF0ZWRJblZlciI6IjQ0LjExNS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->
Changes
Fixes #17995.
astro:head-metadataends itstransformhook with an unconditionalinvalidateComponentMetadataModule()(
packages/astro/src/vite-plugin-head/index.ts:197). That runs for everymodule it transforms — including
\0virtual:astro:component-metadataitself,which the plugin also loads.
That closes a cycle:
\0virtual:astro:component-metadata. It is invalidated,so Vite re-transforms it, and the
transformhook fires for it.ssrgraph is thepre-bundled dev app entrypoint
(
node_modules/.vite/deps_ssr/astro_app_entrypoint_dev.js), becauseentrypoints/virtual/dev.ts:4statically importsdev-nonrunnable.js, whoseheadElements()imports the virtual module(
packages/astro/src/core/environment/dev-nonrunnable.ts:101). Theinvalidation walks up that chain to the SSR entry.
re-evaluates all of it — which re-fetches the virtual module, and we are back
at step 1.
The cycle never converges, so a dev server on a non-runnable environment
(
@astrojs/cloudflareand other adapters that run requests outside Vite'smodule runner) re-evaluates the whole server module graph on every request for
the lifetime of the process.
The fix is to skip the invalidation when the module being transformed is the
virtual module. It reports metadata that other modules own and contributes none
of its own, so its own transform can never change what it emits. Every other
caller is unchanged, so a component that really does change head metadata still
invalidates.
Testing
Measured with
@astrojs/cloudflareon a two-page project with a layout thatholds
<head>, counting invalidations of the metadata module, calls into theastro:head-metadatatransform hook, andfetchModulecalls per request. Samefixture, same script, only the built
packages/astrodiffers.Before (
main@c2e6b0d7c7), aftertouch src/pages/index.astro:After, same sequence:
The graph is re-evaluated once after the edit and then settles, instead of once
per request forever. This project is small enough that the wall-clock difference
is only ~2x; the cost scales with the size of the server graph.
Two tests, both failing on
mainand passing here:packages/astro/test/units/vite-plugin-head/head-metadata.test.ts— assertsthe plugin does not invalidate the metadata module when transforming it, and
that a component carrying head content still does.
packages/integrations/cloudflare/test/head-metadata-invalidation.test.ts—boots a dev server and counts the invalidations the transform hook issues once
the graph is warm. It also edits the layout's
<head>and asserts the newmarkup is served, so a fix that stopped the loop by dropping a real update
would fail here.
Also run on this branch:
packages/astrounit suite — 3524 tests, 0 failurespackages/astrointegration suite — 0 failures (five files stalled under loadon my machine —
endpoint-response,endpoint-routing,endpoint-runtime,env-secret,hmr-markdown, none of which touch head metadata — and werere-run on their own: also 0 failures)
packages/integrations/cloudflarefull suite — 390 tests, 0 failurespnpm lint:ai— clean (the onenoConsolewarning inpackages/language-toolsis present onmaintoo)tsc -binpackages/astro— cleanOne thing this does not change, noted while measuring: the watcher listeners
registered in
configureServer(
packages/astro/src/vite-plugin-head/index.ts:123-125) invalidate on anyadd/unlink/changeunder the project root with no path filter. That is thehead-transforms=1 fetchModule=32row in the "after" output above — anunrelated write costs one full re-evaluation. It is bounded and self-correcting,
unlike the loop, so I left it alone rather than widening the diff. Happy to
follow up if you'd like it filtered.
Docs
No user-facing behaviour changes, so no docs needed.
File and line references are against
main@c2e6b0d7c7.