astro 6.0.7 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/client.d.ts +30 -40
  2. package/dist/actions/runtime/server.d.ts +3 -1
  3. package/dist/actions/runtime/server.js +39 -8
  4. package/dist/assets/build/generate.js +17 -19
  5. package/dist/assets/build/remote.d.ts +4 -4
  6. package/dist/assets/build/remote.js +12 -10
  7. package/dist/assets/fonts/infra/dev-font-file-id-generator.js +4 -1
  8. package/dist/assets/fonts/vite-plugin-fonts.js +8 -0
  9. package/dist/assets/services/sharp.d.ts +21 -2
  10. package/dist/assets/services/sharp.js +54 -12
  11. package/dist/assets/vite-plugin-assets.js +4 -1
  12. package/dist/cli/add/index.js +54 -0
  13. package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
  14. package/dist/content/content-layer.js +3 -3
  15. package/dist/content/index.d.ts +1 -1
  16. package/dist/content/index.js +2 -3
  17. package/dist/content/runtime.d.ts +2 -0
  18. package/dist/content/runtime.js +2 -1
  19. package/dist/content/types-generator.js +4 -0
  20. package/dist/content/utils.d.ts +0 -1
  21. package/dist/content/utils.js +1 -10
  22. package/dist/core/app/dev/app.d.ts +5 -0
  23. package/dist/core/app/dev/app.js +7 -0
  24. package/dist/core/app/entrypoints/virtual/dev.js +4 -0
  25. package/dist/core/app/node.js +5 -4
  26. package/dist/core/app/validate-headers.d.ts +6 -0
  27. package/dist/core/app/validate-headers.js +4 -0
  28. package/dist/core/base-pipeline.d.ts +5 -0
  29. package/dist/core/base-pipeline.js +7 -0
  30. package/dist/core/build/generate.d.ts +47 -0
  31. package/dist/core/build/generate.js +43 -25
  32. package/dist/core/build/plugins/plugin-css.js +8 -4
  33. package/dist/core/config/schemas/base.d.ts +4 -2
  34. package/dist/core/config/schemas/base.js +22 -1
  35. package/dist/core/config/schemas/relative.d.ts +3 -3
  36. package/dist/core/constants.js +1 -1
  37. package/dist/core/create-vite.js +1 -1
  38. package/dist/core/dev/dev.js +13 -1
  39. package/dist/core/head-propagation/boundary.d.ts +8 -0
  40. package/dist/core/head-propagation/boundary.js +11 -0
  41. package/dist/core/head-propagation/buffer.d.ts +21 -0
  42. package/dist/core/head-propagation/buffer.js +18 -0
  43. package/dist/core/head-propagation/comment.d.ts +7 -0
  44. package/dist/core/head-propagation/comment.js +7 -0
  45. package/dist/core/head-propagation/graph.d.ts +18 -0
  46. package/dist/core/head-propagation/graph.js +32 -0
  47. package/dist/core/head-propagation/policy.d.ts +22 -0
  48. package/dist/core/head-propagation/policy.js +14 -0
  49. package/dist/core/head-propagation/resolver.d.ts +28 -0
  50. package/dist/core/head-propagation/resolver.js +25 -0
  51. package/dist/core/messages/runtime.d.ts +3 -0
  52. package/dist/core/messages/runtime.js +9 -1
  53. package/dist/core/middleware/vite-plugin.d.ts +1 -1
  54. package/dist/core/middleware/vite-plugin.js +25 -0
  55. package/dist/core/redirects/render.d.ts +17 -0
  56. package/dist/core/redirects/render.js +33 -24
  57. package/dist/core/routing/create-manifest.d.ts +15 -0
  58. package/dist/core/routing/create-manifest.js +131 -130
  59. package/dist/core/routing/prerender.d.ts +5 -0
  60. package/dist/core/routing/prerender.js +7 -1
  61. package/dist/core/routing/rewrite.d.ts +9 -0
  62. package/dist/core/routing/rewrite.js +39 -26
  63. package/dist/core/server-islands/vite-plugin-server-islands.js +18 -6
  64. package/dist/integrations/hooks.js +4 -1
  65. package/dist/jsx/rehype.js +1 -1
  66. package/dist/manifest/serialized.js +5 -0
  67. package/dist/manifest/virtual-module.d.ts +4 -1
  68. package/dist/manifest/virtual-module.js +37 -35
  69. package/dist/runtime/client/dev-toolbar/apps/audit/rules/a11y.js +3 -3
  70. package/dist/runtime/server/render/astro/factory.js +6 -7
  71. package/dist/runtime/server/render/astro/instance.js +2 -4
  72. package/dist/runtime/server/render/astro/render.js +2 -11
  73. package/dist/runtime/server/render/common.js +3 -2
  74. package/dist/runtime/server/render/head-propagation/runtime.d.ts +20 -0
  75. package/dist/runtime/server/render/head-propagation/runtime.js +53 -0
  76. package/dist/runtime/server/render/page.js +5 -1
  77. package/dist/runtime/server/transition.d.ts +19 -1
  78. package/dist/runtime/server/transition.js +6 -1
  79. package/dist/transitions/events.d.ts +1 -1
  80. package/dist/transitions/events.js +5 -5
  81. package/dist/transitions/router.js +23 -19
  82. package/dist/types/public/config.d.ts +70 -11
  83. package/dist/types/public/integrations.d.ts +9 -2
  84. package/dist/vite-plugin-app/app.d.ts +5 -0
  85. package/dist/vite-plugin-app/app.js +17 -1
  86. package/dist/vite-plugin-app/createAstroServerApp.js +4 -0
  87. package/dist/vite-plugin-astro-server/plugin.js +2 -1
  88. package/dist/vite-plugin-astro-server/vite.js +2 -2
  89. package/dist/vite-plugin-css/index.js +2 -0
  90. package/dist/vite-plugin-head/index.js +63 -25
  91. package/dist/vite-plugin-scripts/index.js +5 -0
  92. package/package.json +11 -11
@@ -1,12 +1,5 @@
1
1
  import { internalFetchHeaders } from "virtual:astro:adapter-config/client";
2
- import {
3
- doPreparation,
4
- doSwap,
5
- TRANSITION_AFTER_SWAP,
6
- onPageLoad,
7
- triggerEvent,
8
- updateScrollPosition
9
- } from "./events.js";
2
+ import { doPreparation, doSwap, onPageLoad, triggerEvent, updateScrollPosition } from "./events.js";
10
3
  import { detectScriptExecuted } from "./swap-functions.js";
11
4
  const inBrowser = import.meta.env.SSR === false;
12
5
  const supportsViewTransitions = inBrowser && !!document.startViewTransition;
@@ -212,13 +205,11 @@ async function updateDOM(preparationEvent, options, currentTransition, historySt
212
205
  animateFallbackOld
213
206
  );
214
207
  moveToLocation(swapEvent.to, swapEvent.from, options, pageTitleForBrowserHistory, historyState);
215
- triggerEvent(TRANSITION_AFTER_SWAP);
216
- if (fallback === "animate") {
217
- if (!currentTransition.transitionSkipped && !swapEvent.signal.aborted) {
218
- animate("new").finally(() => currentTransition.viewTransitionFinished());
219
- } else {
220
- currentTransition.viewTransitionFinished();
221
- }
208
+ triggerEvent("astro:after-swap");
209
+ if (fallback === "animate" && !currentTransition.transitionSkipped && !swapEvent.signal.aborted) {
210
+ animate("new").finally(() => currentTransition.viewTransitionFinished());
211
+ } else {
212
+ currentTransition.viewTransitionFinished?.();
222
213
  }
223
214
  }
224
215
  function abortAndRecreateMostRecentNavigation() {
@@ -227,7 +218,7 @@ function abortAndRecreateMostRecentNavigation() {
227
218
  controller: new AbortController()
228
219
  };
229
220
  }
230
- async function transition(direction, from, to, options, historyState) {
221
+ async function transition(direction, from, to, options, historyState, hasUAVisualTransition = false) {
231
222
  const currentNavigation = abortAndRecreateMostRecentNavigation();
232
223
  if (!transitionEnabledOnThisPage() || location.origin !== to.origin) {
233
224
  if (currentNavigation === mostRecentNavigation) mostRecentNavigation = void 0;
@@ -323,14 +314,20 @@ async function transition(direction, from, to, options, historyState) {
323
314
  return;
324
315
  }
325
316
  document.documentElement.setAttribute(DIRECTION_ATTR, prepEvent.direction);
326
- if (supportsViewTransitions) {
317
+ if (supportsViewTransitions && !hasUAVisualTransition) {
327
318
  currentTransition.viewTransition = document.startViewTransition(
328
319
  async () => await updateDOM(prepEvent, options, currentTransition, historyState)
329
320
  );
330
321
  } else {
331
322
  const updateDone = (async () => {
332
323
  await Promise.resolve();
333
- await updateDOM(prepEvent, options, currentTransition, historyState, getFallback());
324
+ await updateDOM(
325
+ prepEvent,
326
+ options,
327
+ currentTransition,
328
+ historyState,
329
+ hasUAVisualTransition ? "swap" : getFallback()
330
+ );
334
331
  return void 0;
335
332
  })();
336
333
  currentTransition.viewTransition = {
@@ -396,7 +393,14 @@ function onPopState(ev) {
396
393
  const nextIndex = state.index;
397
394
  const direction = nextIndex > currentHistoryIndex ? "forward" : "back";
398
395
  currentHistoryIndex = nextIndex;
399
- transition(direction, originalLocation, new URL(location.href), {}, state);
396
+ transition(
397
+ direction,
398
+ originalLocation,
399
+ new URL(location.href),
400
+ {},
401
+ state,
402
+ ev.hasUAVisualTransition
403
+ );
400
404
  }
401
405
  const onScrollEnd = () => {
402
406
  if (history.state && (scrollX !== history.state.scrollX || scrollY !== history.state.scrollY)) {
@@ -1,6 +1,6 @@
1
1
  import type { OutgoingHttpHeaders } from 'node:http';
2
2
  import type { RemotePattern } from '@astrojs/internal-helpers/remote';
3
- import type { RehypePlugins, RemarkPlugins, RemarkRehype, ShikiConfig, SyntaxHighlightConfigType } from '@astrojs/markdown-remark';
3
+ import type { RehypePlugins, RemarkPlugins, RemarkRehype, ShikiConfig, Smartypants, SyntaxHighlightConfigType } from '@astrojs/markdown-remark';
4
4
  import type { Config as SvgoConfig } from 'svgo';
5
5
  import type { UserConfig as OriginalViteUserConfig, SSROptions as ViteSSROptions } from 'vite';
6
6
  import type { FontFamily, FontProvider } from '../../assets/fonts/types.js';
@@ -1607,6 +1607,13 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
1607
1607
  * entrypoint: 'astro/assets/services/sharp',
1608
1608
  * config: {
1609
1609
  * limitInputPixels: false,
1610
+ * webp: {
1611
+ * effort: 6,
1612
+ * alphaQuality: 80,
1613
+ * },
1614
+ * jpeg: {
1615
+ * mozjpeg: true,
1616
+ * },
1610
1617
  * },
1611
1618
  * },
1612
1619
  * },
@@ -1640,6 +1647,62 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
1640
1647
  *
1641
1648
  * By default this is `undefined`, which maps to Sharp's default kernel of `lanczos3`.
1642
1649
  */
1650
+ /**
1651
+ * @docs
1652
+ * @name image.service.config.jpeg
1653
+ * @kind h4
1654
+ * @type {Record<string, any> | undefined}
1655
+ * @default `undefined`
1656
+ * @version 6.1.0
1657
+ * @description
1658
+ *
1659
+ * The default encoder options passed to `sharp().jpeg()` when using Astro's built-in Sharp image service.
1660
+ *
1661
+ * This can be used for options such as `mozjpeg`, `progressive`, `chromaSubsampling`, or a default `quality`.
1662
+ * Per-image `quality` values from `<Image />`, `<Picture />`, and `getImage()` still take precedence.
1663
+ */
1664
+ /**
1665
+ * @docs
1666
+ * @name image.service.config.webp
1667
+ * @kind h4
1668
+ * @type {Record<string, any> | undefined}
1669
+ * @default `undefined`
1670
+ * @version 6.1.0
1671
+ * @description
1672
+ *
1673
+ * The default encoder options passed to `sharp().webp()` when using Astro's built-in Sharp image service.
1674
+ *
1675
+ * This can be used for options such as `effort`, `alphaQuality`, `lossless`, `nearLossless`, or a default `quality`.
1676
+ * Per-image `quality` values from `<Image />`, `<Picture />`, and `getImage()` still take precedence.
1677
+ */
1678
+ /**
1679
+ * @docs
1680
+ * @name image.service.config.avif
1681
+ * @kind h4
1682
+ * @type {Record<string, any> | undefined}
1683
+ * @default `undefined`
1684
+ * @version 6.1.0
1685
+ * @description
1686
+ *
1687
+ * The default encoder options passed to `sharp().avif()` when using Astro's built-in Sharp image service.
1688
+ *
1689
+ * This can be used for options such as `effort`, `chromaSubsampling`, `bitdepth`, `lossless`, or a default `quality`.
1690
+ * Per-image `quality` values from `<Image />`, `<Picture />`, and `getImage()` still take precedence.
1691
+ */
1692
+ /**
1693
+ * @docs
1694
+ * @name image.service.config.png
1695
+ * @kind h4
1696
+ * @type {Record<string, any> | undefined}
1697
+ * @default `undefined`
1698
+ * @version 6.1.0
1699
+ * @description
1700
+ *
1701
+ * The default encoder options passed to `sharp().png()` when using Astro's built-in Sharp image service.
1702
+ *
1703
+ * This can be used for options such as `compressionLevel`, `effort`, `palette`, or a default `quality`.
1704
+ * Per-image `quality` values from `<Image />`, `<Picture />`, and `getImage()` still take precedence.
1705
+ */
1643
1706
  /**
1644
1707
  * @docs
1645
1708
  * @name image.domains
@@ -1945,21 +2008,17 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
1945
2008
  /**
1946
2009
  * @docs
1947
2010
  * @name markdown.smartypants
1948
- * @type {boolean}
2011
+ * @type {boolean | Smartypants}
1949
2012
  * @default `true`
1950
2013
  * @version 2.0.0
1951
2014
  * @description
1952
- * Astro uses the [SmartyPants formatter](https://daringfireball.net/projects/smartypants/) by default. To disable this, set the `smartypants` flag to `false`:
2015
+ * Whether to use the [SmartyPants formatter](https://daringfireball.net/projects/smartypants/) to transform straight quotes into smart quotes, dashes into en/em dashes, and triple dots into ellipses.
1953
2016
  *
1954
- * ```js
1955
- * {
1956
- * markdown: {
1957
- * smartypants: false,
1958
- * }
1959
- * }
1960
- * ```
2017
+ * To disable this, set the `smartypants` flag to `false`.
2018
+ *
2019
+ * For more control over typography, you can instead specify a configuration object with the [properties supported by `retext-smartypants`](https://github.com/retextjs/retext-smartypants?tab=readme-ov-file#fields).
1961
2020
  */
1962
- smartypants?: boolean;
2021
+ smartypants?: boolean | Smartypants;
1963
2022
  /**
1964
2023
  * @docs
1965
2024
  * @name markdown.remarkRehype
@@ -204,8 +204,11 @@ export interface AstroPrerenderer {
204
204
  getStaticPaths: () => Promise<PathWithRoute[]>;
205
205
  /**
206
206
  * Renders a single page. Called by Astro for each path returned by getStaticPaths.
207
- * @param request - The request to render
208
- * @param options - Render options including routeData
207
+ * @param request - The request to render. The URL reflects the build format
208
+ * (e.g. trailing slash for `directory` format). To get the canonical pathname,
209
+ * use the `pathname` from the `PathWithRoute` entry returned by `getStaticPaths`.
210
+ * @param options - Render options
211
+ * @param options.routeData - The matched route for this path
209
212
  */
210
213
  render: (request: Request, options: {
211
214
  routeData: RouteData;
@@ -379,6 +382,10 @@ export interface IntegrationResolvedRoute extends Pick<RouteData, 'params' | 'pa
379
382
  * {@link RouteData.redirectRoute}
380
383
  */
381
384
  redirectRoute?: IntegrationResolvedRoute;
385
+ /**
386
+ * {@link RouteData.fallbackRoutes}
387
+ */
388
+ fallbackRoutes: IntegrationResolvedRoute[];
382
389
  /**
383
390
  * @param {any} data The optional parameters of the route
384
391
  *
@@ -26,6 +26,11 @@ export declare class AstroServerApp extends BaseApp<RunnablePipeline> {
26
26
  * Called via HMR when content collection data changes.
27
27
  */
28
28
  clearRouteCache(): void;
29
+ /**
30
+ * Clears the cached middleware so it is re-resolved on the next request.
31
+ * Called via HMR when middleware files change.
32
+ */
33
+ clearMiddleware(): void;
29
34
  devMatch(pathname: string): Promise<DevMatch | undefined>;
30
35
  static create(manifest: SSRManifest, routesList: RoutesList, logger: Logger, loader: ModuleLoader, settings: AstroSettings, getDebugInfo: () => Promise<string>): Promise<AstroServerApp>;
31
36
  createPipeline(_streaming: boolean, manifest: SSRManifest, settings: AstroSettings, logger: Logger, loader: ModuleLoader, manifestData: RoutesList, getDebugInfo: () => Promise<string>): RunnablePipeline;
@@ -1,5 +1,6 @@
1
1
  import { removeTrailingForwardSlash } from "@astrojs/internal-helpers/path";
2
2
  import { BaseApp } from "../core/app/entrypoints/index.js";
3
+ import { getFirstForwardedValue, validateForwardedHeaders } from "../core/app/validate-headers.js";
3
4
  import { shouldAppendForwardSlash } from "../core/build/util.js";
4
5
  import { clientLocalsSymbol } from "../core/constants.js";
5
6
  import {
@@ -48,6 +49,13 @@ class AstroServerApp extends BaseApp {
48
49
  clearRouteCache() {
49
50
  this.pipeline.clearRouteCache();
50
51
  }
52
+ /**
53
+ * Clears the cached middleware so it is re-resolved on the next request.
54
+ * Called via HMR when middleware files change.
55
+ */
56
+ clearMiddleware() {
57
+ this.pipeline.clearMiddleware();
58
+ }
51
59
  async devMatch(pathname) {
52
60
  const matchedRoute = await matchRoute(
53
61
  pathname,
@@ -86,7 +94,15 @@ class AstroServerApp extends BaseApp {
86
94
  incomingResponse,
87
95
  isHttps
88
96
  }) {
89
- const origin = `${isHttps ? "https" : "http"}://${incomingRequest.headers[":authority"] ?? incomingRequest.headers.host}`;
97
+ const validated = validateForwardedHeaders(
98
+ getFirstForwardedValue(incomingRequest.headers["x-forwarded-proto"]),
99
+ getFirstForwardedValue(incomingRequest.headers["x-forwarded-host"]),
100
+ getFirstForwardedValue(incomingRequest.headers["x-forwarded-port"]),
101
+ this.manifest.allowedDomains
102
+ );
103
+ const protocol = validated.protocol ?? (isHttps ? "https" : "http");
104
+ const host = validated.host ?? incomingRequest.headers[":authority"] ?? incomingRequest.headers.host;
105
+ const origin = `${protocol}://${host}`;
90
106
  const url = new URL(origin + incomingRequest.url);
91
107
  let pathname;
92
108
  if (this.manifest.trailingSlash === "never" && !incomingRequest.url) {
@@ -58,6 +58,10 @@ async function createAstroServerApp(controller, settings, loader, logger) {
58
58
  app.clearRouteCache();
59
59
  actualLogger.debug("router", "Route cache cleared due to content change");
60
60
  });
61
+ import.meta.hot.on("astro:middleware-updated", () => {
62
+ app.clearMiddleware();
63
+ actualLogger.debug("router", "Middleware cache cleared due to file change");
64
+ });
61
65
  }
62
66
  return {
63
67
  handler(incomingRequest, incomingResponse) {
@@ -211,7 +211,8 @@ async function createDevelopmentManifest(settings) {
211
211
  componentMetadata: /* @__PURE__ */ new Map(),
212
212
  inlinedScripts: /* @__PURE__ */ new Map(),
213
213
  i18n: i18nManifest,
214
- checkOrigin: (settings.config.security?.checkOrigin && settings.buildOutput === "server") ?? false,
214
+ checkOrigin: settings.config.security?.checkOrigin ?? false,
215
+ allowedDomains: settings.config.security?.allowedDomains,
215
216
  actionBodySizeLimit: settings.config.security?.actionBodySizeLimit ? settings.config.security.actionBodySizeLimit : 1024 * 1024,
216
217
  // 1mb default
217
218
  serverIslandBodySizeLimit: settings.config.security?.serverIslandBodySizeLimit ? settings.config.security.serverIslandBodySizeLimit : 1024 * 1024,
@@ -1,9 +1,9 @@
1
1
  import npath from "node:path";
2
2
  import { isCSSRequest } from "vite";
3
3
  import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from "../core/constants.js";
4
+ import { isPropagatedAssetBoundary } from "../core/head-propagation/boundary.js";
4
5
  import { unwrapId } from "../core/util.js";
5
6
  import { hasSpecialQueries } from "../vite-plugin-utils/index.js";
6
- import { PROPAGATED_ASSET_QUERY_PARAM } from "../content/consts.js";
7
7
  const fileExtensionsToSSR = /* @__PURE__ */ new Set([".astro", ".mdoc", ...SUPPORTED_MARKDOWN_FILE_EXTENSIONS]);
8
8
  const STRIP_QUERY_PARAMS_REGEX = /\?.*$/;
9
9
  async function* crawlGraph(environment, _id, isRootFile, scanned = /* @__PURE__ */ new Set()) {
@@ -35,7 +35,7 @@ async function* crawlGraph(environment, _id, isRootFile, scanned = /* @__PURE__
35
35
  if (!importedModule.id) continue;
36
36
  const importedModulePathname = importedModule.id.replace(STRIP_QUERY_PARAMS_REGEX, "");
37
37
  const isFileTypeNeedingSSR = fileExtensionsToSSR.has(npath.extname(importedModulePathname));
38
- const isPropagationStoppingPoint = importedModule.id.includes(PROPAGATED_ASSET_QUERY_PARAM);
38
+ const isPropagationStoppingPoint = isPropagatedAssetBoundary(importedModule.id);
39
39
  if (isFileTypeNeedingSSR && // Should not SSR a module with ?astroPropagatedAssets
40
40
  !isPropagationStoppingPoint) {
41
41
  const mod = environment.moduleGraph.getModuleById(importedModule.id);
@@ -26,6 +26,8 @@ async function ensureModulesLoaded(env, mod, seen = /* @__PURE__ */ new Set()) {
26
26
  if (!imp.id) continue;
27
27
  if (seen.has(imp.id)) continue;
28
28
  if (imp.id.includes(PROPAGATED_ASSET_QUERY_PARAM)) continue;
29
+ if (imp.id === RESOLVED_MODULE_DEV_CSS || imp.id === RESOLVED_MODULE_DEV_CSS_ALL || imp.id.startsWith(RESOLVED_MODULE_DEV_CSS_PREFIX))
30
+ continue;
29
31
  if (!imp.transformResult) {
30
32
  try {
31
33
  await env.fetchModule(imp.id);
@@ -1,23 +1,49 @@
1
- import { getParentModuleInfos, getTopLevelPageModuleInfos } from "../core/build/graph.js";
1
+ import { hasHeadInjectComment } from "../core/head-propagation/comment.js";
2
+ import {
3
+ buildImporterGraphFromModuleInfo,
4
+ computeInTreeAncestors
5
+ } from "../core/head-propagation/graph.js";
6
+ import { getTopLevelPageModuleInfos } from "../core/build/graph.js";
2
7
  import { getAstroMetadata } from "../vite-plugin-astro/index.js";
3
8
  import { ASTRO_VITE_ENVIRONMENT_NAMES } from "../core/constants.js";
4
- const injectExp = /(?:^\/\/|\/\/!)\s*astro-head-inject/;
5
9
  function configHeadVitePlugin() {
6
10
  let environment;
7
- function propagateMetadata(id, prop, value, seen = /* @__PURE__ */ new Set()) {
8
- if (seen.has(id)) return;
9
- seen.add(id);
10
- const mod = environment.moduleGraph.getModuleById(id);
11
- const info = this.getModuleInfo(id);
12
- if (info?.meta.astro) {
13
- const astroMetadata = getAstroMetadata(info);
14
- if (astroMetadata) {
15
- Reflect.set(astroMetadata, prop, value);
11
+ function buildImporterGraphFromEnvironment(seed) {
12
+ const queue = [seed];
13
+ const collected = /* @__PURE__ */ new Set();
14
+ while (queue.length > 0) {
15
+ const current = queue.pop();
16
+ if (collected.has(current)) continue;
17
+ collected.add(current);
18
+ const mod = environment.moduleGraph.getModuleById(current);
19
+ for (const importer of mod?.importers ?? []) {
20
+ if (importer.id) {
21
+ queue.push(importer.id);
22
+ }
16
23
  }
17
24
  }
18
- for (const parent of mod?.importers || []) {
19
- if (parent.id) {
20
- propagateMetadata.call(this, parent.id, prop, value, seen);
25
+ return buildImporterGraphFromModuleInfo(collected, (id) => {
26
+ const mod = environment.moduleGraph.getModuleById(id);
27
+ if (!mod) return null;
28
+ return {
29
+ importers: Array.from(mod.importers).map((importer) => importer.id).filter((moduleId) => !!moduleId),
30
+ dynamicImporters: []
31
+ };
32
+ });
33
+ }
34
+ function propagateMetadata(seed, prop, value) {
35
+ const importerGraph = buildImporterGraphFromEnvironment(seed);
36
+ const allAncestors = computeInTreeAncestors({
37
+ seeds: [seed],
38
+ importerGraph
39
+ });
40
+ for (const id of allAncestors) {
41
+ const info = this.getModuleInfo(id);
42
+ if (info?.meta.astro) {
43
+ const astroMetadata = getAstroMetadata(info);
44
+ if (astroMetadata) {
45
+ Reflect.set(astroMetadata, prop, value);
46
+ }
21
47
  }
22
48
  }
23
49
  }
@@ -52,7 +78,7 @@ function configHeadVitePlugin() {
52
78
  if (info && getAstroMetadata(info)?.containsHead) {
53
79
  propagateMetadata.call(this, id, "containsHead", true);
54
80
  }
55
- if (injectExp.test(source)) {
81
+ if (hasHeadInjectComment(source)) {
56
82
  propagateMetadata.call(this, id, "propagation", "in-tree");
57
83
  }
58
84
  }
@@ -66,6 +92,9 @@ function astroHeadBuildPlugin(internals) {
66
92
  },
67
93
  generateBundle(_opts, bundle) {
68
94
  const map = internals.componentMetadata;
95
+ const moduleIds = /* @__PURE__ */ new Set();
96
+ const selfPropagationSeeds = /* @__PURE__ */ new Set();
97
+ const commentPropagationSeeds = /* @__PURE__ */ new Set();
69
98
  function getOrCreateMetadata(id) {
70
99
  if (map.has(id)) return map.get(id);
71
100
  const metadata = {
@@ -78,6 +107,7 @@ function astroHeadBuildPlugin(internals) {
78
107
  for (const [, output] of Object.entries(bundle)) {
79
108
  if (output.type !== "chunk") continue;
80
109
  for (const [id, mod] of Object.entries(output.modules)) {
110
+ moduleIds.add(id);
81
111
  const modinfo = this.getModuleInfo(id);
82
112
  if (modinfo) {
83
113
  const meta = getAstroMetadata(modinfo);
@@ -88,21 +118,29 @@ function astroHeadBuildPlugin(internals) {
88
118
  }
89
119
  }
90
120
  if (meta?.propagation === "self") {
91
- for (const info of getParentModuleInfos(id, this)) {
92
- let metadata = getOrCreateMetadata(info.id);
93
- if (metadata.propagation !== "self") {
94
- metadata.propagation = "in-tree";
95
- }
96
- }
121
+ selfPropagationSeeds.add(id);
97
122
  }
98
123
  }
99
- if (mod.code && injectExp.test(mod.code)) {
100
- for (const info of getParentModuleInfos(id, this)) {
101
- getOrCreateMetadata(info.id).propagation = "in-tree";
102
- }
124
+ if (mod.code && hasHeadInjectComment(mod.code)) {
125
+ commentPropagationSeeds.add(id);
103
126
  }
104
127
  }
105
128
  }
129
+ const importerGraph = buildImporterGraphFromModuleInfo(
130
+ moduleIds,
131
+ (id) => this.getModuleInfo(id)
132
+ );
133
+ const allPropagationSeeds = /* @__PURE__ */ new Set([...selfPropagationSeeds, ...commentPropagationSeeds]);
134
+ const allAncestors = computeInTreeAncestors({
135
+ seeds: allPropagationSeeds,
136
+ importerGraph
137
+ });
138
+ for (const id of allAncestors) {
139
+ const metadata = getOrCreateMetadata(id);
140
+ if (metadata.propagation !== "self") {
141
+ metadata.propagation = "in-tree";
142
+ }
143
+ }
106
144
  }
107
145
  };
108
146
  }
@@ -4,8 +4,12 @@ const BEFORE_HYDRATION_SCRIPT_ID = `${SCRIPT_ID_PREFIX}${"before-hydration"}.js`
4
4
  const PAGE_SCRIPT_ID = `${SCRIPT_ID_PREFIX}${"page"}.js`;
5
5
  const PAGE_SSR_SCRIPT_ID = `${SCRIPT_ID_PREFIX}${"page-ssr"}.js`;
6
6
  function astroScriptsPlugin({ settings }) {
7
+ let command;
7
8
  return {
8
9
  name: "astro:scripts",
10
+ config(_, env) {
11
+ command = env.command;
12
+ },
9
13
  resolveId: {
10
14
  filter: {
11
15
  id: new RegExp(`^${SCRIPT_ID_PREFIX}`)
@@ -37,6 +41,7 @@ function astroScriptsPlugin({ settings }) {
37
41
  }
38
42
  },
39
43
  buildStart() {
44
+ if (command === "serve") return;
40
45
  const hasHydrationScripts = settings.scripts.some((s) => s.stage === "before-hydration");
41
46
  if (hasHydrationScripts && (this.environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.client || this.environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.prerender || this.environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.ssr)) {
42
47
  this.emitFile({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "6.0.7",
3
+ "version": "6.1.0",
4
4
  "description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
5
5
  "type": "module",
6
6
  "author": "withastro",
@@ -101,9 +101,9 @@
101
101
  "README.md"
102
102
  ],
103
103
  "dependencies": {
104
- "@astrojs/compiler": "^3.0.0",
104
+ "@astrojs/compiler": "^3.0.1",
105
105
  "@capsizecss/unpack": "^4.0.0",
106
- "@clack/prompts": "^1.0.1",
106
+ "@clack/prompts": "^1.1.0",
107
107
  "@oslojs/encoding": "^1.1.0",
108
108
  "@rollup/pluginutils": "^5.3.0",
109
109
  "aria-query": "^5.3.2",
@@ -136,11 +136,11 @@
136
136
  "picomatch": "^4.0.3",
137
137
  "rehype": "^13.0.2",
138
138
  "semver": "^7.7.4",
139
- "shiki": "^4.0.0",
139
+ "shiki": "^4.0.2",
140
140
  "smol-toml": "^1.6.0",
141
- "svgo": "^4.0.0",
142
- "tinyclip": "^0.1.6",
143
- "tinyexec": "^1.0.2",
141
+ "svgo": "^4.0.1",
142
+ "tinyclip": "^0.1.12",
143
+ "tinyexec": "^1.0.4",
144
144
  "tinyglobby": "^0.2.15",
145
145
  "tsconfck": "^3.1.6",
146
146
  "ultrahtml": "^1.6.0",
@@ -154,14 +154,14 @@
154
154
  "yargs-parser": "^22.0.0",
155
155
  "zod": "^4.3.6",
156
156
  "@astrojs/internal-helpers": "0.8.0",
157
- "@astrojs/markdown-remark": "7.0.1",
157
+ "@astrojs/markdown-remark": "7.1.0",
158
158
  "@astrojs/telemetry": "3.3.0"
159
159
  },
160
160
  "optionalDependencies": {
161
161
  "sharp": "^0.34.0"
162
162
  },
163
163
  "devDependencies": {
164
- "@astrojs/compiler-rs": "^0.1.4",
164
+ "@astrojs/compiler-rs": "^0.1.6",
165
165
  "@playwright/test": "1.58.2",
166
166
  "@types/aria-query": "^5.0.4",
167
167
  "@types/dlv": "^1.1.5",
@@ -185,11 +185,11 @@
185
185
  "rehype-toc": "^3.0.2",
186
186
  "remark-code-titles": "^0.1.2",
187
187
  "rollup": "^4.58.0",
188
- "sass": "^1.97.3",
188
+ "sass": "^1.98.0",
189
189
  "typescript": "^5.9.3",
190
190
  "undici": "^7.22.0",
191
191
  "unified": "^11.0.5",
192
- "vitest": "^3.2.4",
192
+ "vitest": "^4.1.0",
193
193
  "@astrojs/check": "0.9.8",
194
194
  "astro-scripts": "0.0.14"
195
195
  },