astro 7.1.5 → 7.2.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 (113) hide show
  1. package/dist/assets/build/generate.d.ts +8 -1
  2. package/dist/assets/build/generate.js +21 -1
  3. package/dist/assets/fonts/providers/index.js +12 -2
  4. package/dist/assets/types.d.ts +13 -0
  5. package/dist/assets/vite-plugin-assets.js +8 -0
  6. package/dist/cli/add/index.js +1 -1
  7. package/dist/cli/agent.d.ts +1 -0
  8. package/dist/cli/agent.js +11 -0
  9. package/dist/cli/dev/background.d.ts +3 -16
  10. package/dist/cli/dev/background.js +7 -93
  11. package/dist/cli/dev/index.d.ts +12 -0
  12. package/dist/cli/dev/index.js +30 -23
  13. package/dist/cli/dev/logs.js +2 -64
  14. package/dist/cli/dev/status.d.ts +2 -9
  15. package/dist/cli/dev/status.js +6 -24
  16. package/dist/cli/dev/stop.d.ts +2 -6
  17. package/dist/cli/dev/stop.js +6 -14
  18. package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
  19. package/dist/cli/install-package.js +1 -1
  20. package/dist/cli/preview/index.js +77 -3
  21. package/dist/cli/server.d.ts +60 -0
  22. package/dist/cli/server.js +274 -0
  23. package/dist/content/consts.d.ts +4 -0
  24. package/dist/content/consts.js +8 -0
  25. package/dist/content/content-layer.js +3 -3
  26. package/dist/content/data-store-writer.d.ts +1 -1
  27. package/dist/content/data-store-writer.js +4 -3
  28. package/dist/content/data-store.d.ts +3 -3
  29. package/dist/content/data-store.js +3 -3
  30. package/dist/content/mutable-data-store.d.ts +3 -3
  31. package/dist/content/mutable-data-store.js +5 -5
  32. package/dist/content/paths.d.ts +2 -1
  33. package/dist/content/paths.js +11 -0
  34. package/dist/content/runtime.d.ts +2 -0
  35. package/dist/content/runtime.js +2 -0
  36. package/dist/content/types-generator.js +1 -0
  37. package/dist/content/vite-plugin-content-assets.js +6 -1
  38. package/dist/content/vite-plugin-content-imports.js +12 -3
  39. package/dist/content/vite-plugin-content-virtual-mod.js +69 -31
  40. package/dist/core/app/entrypoints/index.d.ts +2 -0
  41. package/dist/core/app/entrypoints/index.js +14 -0
  42. package/dist/core/build/config-hash/index.d.ts +8 -0
  43. package/dist/core/build/config-hash/index.js +23 -0
  44. package/dist/core/build/config-hash/input.d.ts +199 -0
  45. package/dist/core/build/config-hash/input.js +43 -0
  46. package/dist/core/build/generate.d.ts +3 -1
  47. package/dist/core/build/generate.js +204 -62
  48. package/dist/core/build/incremental-content-collector.d.ts +10 -0
  49. package/dist/core/build/incremental-content-collector.js +33 -0
  50. package/dist/core/build/incremental-image-collector.d.ts +11 -0
  51. package/dist/core/build/incremental-image-collector.js +32 -0
  52. package/dist/core/build/incremental-metadata.d.ts +9 -0
  53. package/dist/core/build/incremental-metadata.js +17 -0
  54. package/dist/core/build/incremental.d.ts +123 -0
  55. package/dist/core/build/incremental.js +178 -0
  56. package/dist/core/build/index.d.ts +3 -0
  57. package/dist/core/build/index.js +6 -2
  58. package/dist/core/build/internal.d.ts +19 -0
  59. package/dist/core/build/lockfile/finder.d.ts +22 -0
  60. package/dist/core/build/lockfile/finder.js +45 -0
  61. package/dist/core/build/lockfile/hasher.d.ts +16 -0
  62. package/dist/core/build/lockfile/hasher.js +46 -0
  63. package/dist/core/build/lockfile/index.d.ts +9 -0
  64. package/dist/core/build/lockfile/index.js +16 -0
  65. package/dist/core/build/plugins/index.js +3 -1
  66. package/dist/core/build/plugins/plugin-incremental.d.ts +14 -0
  67. package/dist/core/build/plugins/plugin-incremental.js +134 -0
  68. package/dist/core/build/types.d.ts +2 -0
  69. package/dist/core/config/schemas/base.d.ts +7 -6
  70. package/dist/core/config/schemas/base.js +9 -1
  71. package/dist/core/config/schemas/defaults.d.ts +1 -0
  72. package/dist/core/config/schemas/defaults.js +1 -0
  73. package/dist/core/config/schemas/relative.d.ts +19 -10
  74. package/dist/core/constants.js +1 -1
  75. package/dist/core/create-vite.js +2 -1
  76. package/dist/core/dev/dev.js +5 -4
  77. package/dist/core/dev/lockfile.d.ts +8 -7
  78. package/dist/core/dev/lockfile.js +13 -13
  79. package/dist/core/encryption.d.ts +6 -0
  80. package/dist/core/encryption.js +14 -2
  81. package/dist/core/errors/default-handler.js +4 -5
  82. package/dist/core/fetch/index.js +1 -1
  83. package/dist/core/logger/config.d.ts +1 -1
  84. package/dist/core/logger/load.d.ts +3 -1
  85. package/dist/core/logger/load.js +3 -3
  86. package/dist/core/logger/utils.d.ts +6 -4
  87. package/dist/core/logger/utils.js +13 -5
  88. package/dist/core/logger/vite-plugin.js +1 -1
  89. package/dist/core/messages/runtime.js +1 -1
  90. package/dist/core/preview/static-preview-server.d.ts +2 -0
  91. package/dist/core/preview/static-preview-server.js +1 -0
  92. package/dist/core/routing/handler.js +1 -1
  93. package/dist/core/session/config.d.ts +2 -2
  94. package/dist/core/session/config.js +2 -1
  95. package/dist/core/session/provider-disabled.d.ts +2 -0
  96. package/dist/core/session/provider-disabled.js +7 -0
  97. package/dist/core/session/provider.d.ts +1 -0
  98. package/dist/core/session/provider.js +4 -0
  99. package/dist/core/session/utils.js +3 -0
  100. package/dist/core/session/vite-plugin.d.ts +3 -0
  101. package/dist/core/session/vite-plugin.js +41 -6
  102. package/dist/core/sync/index.js +5 -4
  103. package/dist/integrations/hooks.js +3 -1
  104. package/dist/runtime/prerender/static-paths.js +5 -1
  105. package/dist/runtime/server/render/util.js +3 -0
  106. package/dist/types/public/common.d.ts +1 -0
  107. package/dist/types/public/config.d.ts +73 -7
  108. package/dist/types/public/integrations.d.ts +29 -2
  109. package/dist/types/public/preview.d.ts +2 -0
  110. package/dist/vite-plugin-config-alias/index.js +1 -0
  111. package/dist/vite-plugin-environment/index.js +4 -1
  112. package/dist/vite-plugin-hmr-reload/index.js +60 -18
  113. package/package.json +2 -3
@@ -6,7 +6,7 @@ import colors from "piccolore";
6
6
  import { createServer } from "vite";
7
7
  import { syncFonts } from "../../assets/fonts/sync.js";
8
8
  import { CONTENT_TYPES_FILE } from "../../content/consts.js";
9
- import { getDataStoreDir, getDataStoreFile } from "../../content/paths.js";
9
+ import { getDataStoreChunkSize, getDataStoreDir, getDataStoreFile } from "../../content/paths.js";
10
10
  import { globalContentLayer } from "../../content/instance.js";
11
11
  import { createContentTypesGenerator } from "../../content/index.js";
12
12
  import { MutableDataStore } from "../../content/mutable-data-store.js";
@@ -59,7 +59,7 @@ async function clearContentLayerCache({
59
59
  fs = fsMod,
60
60
  isDev
61
61
  }) {
62
- if (settings.config.experimental.collectionStorage === "chunked") {
62
+ if (getDataStoreChunkSize(settings) !== void 0) {
63
63
  const dataStore = getDataStoreDir(settings, isDev);
64
64
  if (fs.existsSync(dataStore)) {
65
65
  logger.debug("content", "clearing data store");
@@ -98,9 +98,10 @@ async function syncInternal({
98
98
  settings.timer.start("Sync content layer");
99
99
  let store;
100
100
  try {
101
- if (settings.config.experimental.collectionStorage === "chunked") {
101
+ const chunkSize = getDataStoreChunkSize(settings);
102
+ if (chunkSize !== void 0) {
102
103
  const dataStoreDir = getDataStoreDir(settings, isDev);
103
- store = await MutableDataStore.fromDir(dataStoreDir);
104
+ store = await MutableDataStore.fromDir(dataStoreDir, chunkSize);
104
105
  } else {
105
106
  const dataStoreFile = getDataStoreFile(settings, isDev);
106
107
  store = await MutableDataStore.fromFile(dataStoreFile);
@@ -260,7 +260,9 @@ async function runHookConfigSetup({
260
260
  try {
261
261
  updatedConfig = await validateConfigRefined(updatedConfig);
262
262
  if (isLoggerUpdated) {
263
- logger.setDestination(await loadLoggerDestination(updatedConfig.logger));
263
+ logger.setDestination(
264
+ await loadLoggerDestination(updatedConfig.logger, updatedConfig.root)
265
+ );
264
266
  }
265
267
  } catch (error) {
266
268
  integrationLogger.error("An error occurred while updating the config");
@@ -61,7 +61,11 @@ class StaticPaths {
61
61
  });
62
62
  for (const staticPath of staticPaths) {
63
63
  const pathname = stringifyParams(staticPath.params, route, manifest.trailingSlash);
64
- paths.push({ pathname, route });
64
+ paths.push({
65
+ pathname,
66
+ route,
67
+ cacheKey: staticPath.cacheKey === void 0 ? void 0 : String(staticPath.cacheKey)
68
+ });
65
69
  }
66
70
  return paths;
67
71
  }
@@ -35,6 +35,9 @@ function isCustomElement(tagName) {
35
35
  return tagName.includes("-");
36
36
  }
37
37
  function handleBooleanAttribute(key, value, shouldEscape, tagName) {
38
+ if (key === "popover") {
39
+ return markHTMLString(value ? ` ${key}` : "");
40
+ }
38
41
  if (tagName && isCustomElement(tagName)) {
39
42
  return markHTMLString(` ${key}="${toAttributeString(value, shouldEscape)}"`);
40
43
  }
@@ -13,6 +13,7 @@ export interface GetStaticPathsOptions {
13
13
  export type GetStaticPathsItem = {
14
14
  params: Params;
15
15
  props?: Props;
16
+ cacheKey?: string | number;
16
17
  };
17
18
  export type GetStaticPathsResult = GetStaticPathsItem[];
18
19
  export type GetStaticPathsResultKeyed = GetStaticPathsResult & {
@@ -1171,6 +1171,7 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
1171
1171
  * Setting `build.format` controls what `Astro.url` is set to during the build. When it is:
1172
1172
  * - `directory` - The `Astro.url.pathname` will include a trailing slash to mimic folder behavior. (e.g. `/foo/`)
1173
1173
  * - `file` - The `Astro.url.pathname` will include `.html`. (e.g. `/foo.html`)
1174
+ * - `preserve` - The `Astro.url.pathname` matches the generated file for each page: index pages include a trailing slash (e.g. `/foo/`), while non-index pages include `.html` (e.g. `/foo.html`).
1174
1175
  *
1175
1176
  * This means that when you create relative URLs using `new URL('./relative', Astro.url)`, you will get consistent behavior between dev and build.
1176
1177
  *
@@ -1535,7 +1536,8 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
1535
1536
  * @description
1536
1537
  *
1537
1538
  * The entrypoint for the [logger implementation](https://docs.astro.build/en/reference/logger-reference/#the-logger-implementation).
1538
- * This can be an npm package, or a `URL` pointing to a file in your project:
1539
+ * This can be an npm package, a path relative to your project root, or a `URL` pointing to a
1540
+ * file in your project:
1539
1541
  *
1540
1542
  * ```js title="astro.config.mjs"
1541
1543
  * import { defineConfig } from 'astro/config';
@@ -1546,6 +1548,9 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
1546
1548
  * }
1547
1549
  * });
1548
1550
  * ```
1551
+ *
1552
+ * The logger entrypoint must be a JavaScript file. TypeScript is not supported. If Astro fails to load
1553
+ * the implementation, it falls back to its default logger.
1549
1554
  */
1550
1555
  /**
1551
1556
  * @docs
@@ -1573,6 +1578,7 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
1573
1578
  /**
1574
1579
  * @docs
1575
1580
  * @kind heading
1581
+ * @type {object | false}
1576
1582
  * @version 5.7.0
1577
1583
  * @name Session Options
1578
1584
  * @description
@@ -1596,9 +1602,19 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
1596
1602
  *
1597
1603
  * Session drivers are configured at build time. This means environment variables used in the driver configuration are inlined. You must create your own driver entrypoint to [override the configuration at runtime](https://docs.astro.build/en/guides/sessions/#overriding-the-configuration-at-runtime).
1598
1604
  *
1605
+ * Since Astro v7.2.0, you can opt out of session support by setting the option to `false`. When sessions are disabled, the session runtime is excluded from the SSR bundle, and adapters skip wiring their default session driver. This is useful for serverless and edge runtimes where bundle parse time is sensitive.
1606
+ *
1607
+ * ```js title="astro.config.mjs"
1608
+ * import { defineConfig } from 'astro/config';
1609
+ *
1610
+ * export default defineConfig({
1611
+ * session: false,
1612
+ * });
1613
+ * ```
1614
+ *
1599
1615
  * See [the sessions guide](https://docs.astro.build/en/guides/sessions/) for more information.
1600
1616
  */
1601
- session?: SessionConfig<TDriver>;
1617
+ session?: SessionConfig<TDriver> | false;
1602
1618
  /**
1603
1619
  * @docs
1604
1620
  * @name session.driver
@@ -3128,7 +3144,7 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
3128
3144
  svgOptimizer?: SvgOptimizer;
3129
3145
  /**
3130
3146
  * @name experimental.collectionStorage
3131
- * @type {'single-file' | 'chunked'}
3147
+ * @type {'single-file' | 'chunked' | { type: 'chunked', chunkSize: number }}
3132
3148
  * @default `'single-file'`
3133
3149
  * @version 7.1.0
3134
3150
  * @description
@@ -3139,22 +3155,72 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
3139
3155
  * file. For very large content collections, this file can grow large
3140
3156
  * enough to hit platform file-size limits.
3141
3157
  *
3142
- * When set to `'chunked'`, the store is split across many smaller,
3143
- * content-addressed files so that no single file grows unbounded.
3158
+ * When set to `'chunked'`, the store is split into files
3159
+ * with a maximum size of 20 MiB each. To customize the maximum size,
3160
+ * pass an object with `type: 'chunked'` and `chunkSize`. A 1 MiB limit
3161
+ * is recommended for broad adapter compatibility.
3144
3162
  *
3145
3163
  * ```js
3146
3164
  * import { defineConfig } from 'astro/config';
3147
3165
  *
3148
3166
  * export default defineConfig({
3149
3167
  * experimental: {
3150
- * collectionStorage: 'chunked',
3168
+ * collectionStorage: {
3169
+ * type: 'chunked',
3170
+ * chunkSize: 1024 * 1024,
3171
+ * },
3151
3172
  * },
3152
3173
  * });
3153
3174
  * ```
3154
3175
  *
3155
3176
  * See the [experimental data store chunking documentation](https://docs.astro.build/en/reference/experimental-flags/collection-storage/) for more information.
3156
3177
  */
3157
- collectionStorage?: 'single-file' | 'chunked';
3178
+ collectionStorage?: 'single-file' | 'chunked' | {
3179
+ type: 'chunked';
3180
+ /** Maximum UTF-8 byte size of each data store chunk. */
3181
+ chunkSize: number;
3182
+ };
3183
+ /**
3184
+ * @name experimental.incrementalBuild
3185
+ * @type {boolean}
3186
+ * @default `false`
3187
+ * @version 7.2
3188
+ * @description
3189
+ *
3190
+ * Enables incremental static builds. When enabled, pages with a `cacheKey` returned
3191
+ * from `getStaticPaths()` can be skipped during subsequent builds if neither
3192
+ * their data nor their dependencies have changed.
3193
+ *
3194
+ * On the first build, all pages are rendered normally and a cache manifest is saved.
3195
+ * On subsequent builds, each page is checked against the manifest: if the page's
3196
+ * `cacheKey` and the hash of its module dependency graph both match, the page is
3197
+ * skipped and the previous output is preserved.
3198
+ *
3199
+ * ```js
3200
+ * // astro.config.mjs
3201
+ * {
3202
+ * experimental: {
3203
+ * incrementalBuild: true,
3204
+ * },
3205
+ * }
3206
+ * ```
3207
+ *
3208
+ * In your dynamic routes, return a `cacheKey` from `getStaticPaths()`:
3209
+ *
3210
+ * ```js
3211
+ * // src/pages/blog/[slug].astro
3212
+ * export async function getStaticPaths() {
3213
+ * const posts = await fetchPosts();
3214
+ * return posts.map(post => ({
3215
+ * params: { slug: post.slug },
3216
+ * props: { post },
3217
+ * cacheKey: post.digest,
3218
+ * }));
3219
+ * }
3220
+ * ```
3221
+ * See the [experimental incremental static builds](https://docs.astro.build/en/reference/experimental-flags/incremental-build/) for more information.
3222
+ */
3223
+ incrementalBuild?: boolean;
3158
3224
  };
3159
3225
  }
3160
3226
  /**
@@ -1,7 +1,7 @@
1
1
  import type { AddressInfo } from 'node:net';
2
2
  import type { ViteDevServer, InlineConfig } from 'vite';
3
3
  import type { SerializedSSRManifest } from '../../core/app/types.js';
4
- import type { AssetsGlobalStaticImagesList } from '../../assets/types.js';
4
+ import type { AssetsGlobalStaticImagesList, SerializedStaticImage } from '../../assets/types.js';
5
5
  import type { PageBuildData } from '../../core/build/types.js';
6
6
  import type { AstroIntegrationLogger } from '../../core/logger/core.js';
7
7
  import type { AdapterFeatureStability } from '../../integrations/features-validation.js';
@@ -194,6 +194,28 @@ export type AstroAdapter = {
194
194
  export interface PathWithRoute {
195
195
  pathname: string;
196
196
  route: RouteData;
197
+ cacheKey?: string;
198
+ }
199
+ /**
200
+ * Incremental-build data an out-of-process prerenderer collects while rendering
201
+ * a page, reported back to the build process so skipped pages can be tracked and
202
+ * replayed without a re-render.
203
+ */
204
+ export interface PrerenderRenderMetadata {
205
+ /** Root-relative `filePath`s of the content entries the page rendered. */
206
+ contentEntryKeys?: string[];
207
+ /** Optimized-image transforms the page resolved. */
208
+ staticImages?: SerializedStaticImage[];
209
+ }
210
+ /**
211
+ * The richer result a prerenderer's `render()` may return instead of a bare
212
+ * `Response`, pairing the rendered response with the incremental-build metadata
213
+ * collected for that page. Used by out-of-process prerenderers, which collect
214
+ * the metadata in their own runtime rather than in the build's collectors.
215
+ */
216
+ export interface PrerenderResult {
217
+ response: Response;
218
+ metadata?: PrerenderRenderMetadata;
197
219
  }
198
220
  /**
199
221
  * Custom prerenderer that adapters can provide to control how pages are prerendered.
@@ -217,10 +239,15 @@ export interface AstroPrerenderer {
217
239
  * use the `pathname` from the `PathWithRoute` entry returned by `getStaticPaths`.
218
240
  * @param options - Render options
219
241
  * @param options.routeData - The matched route for this path
242
+ * @returns A `Response`, or a {@link PrerenderResult} pairing the response with
243
+ * the incremental-build metadata the page resolved. Out-of-process
244
+ * prerenderers return the latter to report metadata they collect in their own
245
+ * runtime; in-process prerenderers populate the build's collectors directly
246
+ * and return a bare `Response`.
220
247
  */
221
248
  render: (request: Request, options: {
222
249
  routeData: RouteData;
223
- }) => Promise<Response>;
250
+ }) => Promise<Response | PrerenderResult>;
224
251
  /**
225
252
  * Returns images collected in the adapter's runtime (e.g. workerd) to be merged
226
253
  * into the Node-side static image list. The default Sharp pipeline runs after.
@@ -1,8 +1,10 @@
1
1
  import type { OutgoingHttpHeaders } from 'node:http';
2
+ import type { ResolvedServerUrls } from 'vite';
2
3
  import type { AstroIntegrationLogger } from '../../core/logger/core.js';
3
4
  export interface PreviewServer {
4
5
  host?: string;
5
6
  port: number;
7
+ urls?: ResolvedServerUrls;
6
8
  closed(): Promise<void>;
7
9
  stop(): Promise<void>;
8
10
  }
@@ -68,6 +68,7 @@ function configAliasVitePlugin({
68
68
  let hasReplacement = false;
69
69
  const replaceAliases = (match, importId) => {
70
70
  if (!importId) return match;
71
+ if (importId.startsWith("data:")) return match;
71
72
  const resolved = resolveWithAlias(importId, configAlias);
72
73
  if (resolved) {
73
74
  hasReplacement = true;
@@ -16,7 +16,10 @@ const ALWAYS_NOEXTERNAL = [
16
16
  // Full explanation and related bug report: https://github.com/withastro/astro/pull/3667
17
17
  "@nanostores/preact",
18
18
  // fontsource packages are CSS that need to be processed
19
- "@fontsource/*"
19
+ "@fontsource/*",
20
+ // Must be bundled so the prerender output resolves Astro's own copy, not an
21
+ // older hoisted version from another dependency. See https://github.com/withastro/astro/issues/17508
22
+ "neotraverse"
20
23
  ];
21
24
  function vitePluginEnvironment({
22
25
  command,
@@ -3,15 +3,38 @@ import { VIRTUAL_PAGE_RESOLVED_MODULE_ID } from "../vite-plugin-pages/const.js";
3
3
  import { RESOLVED_MODULE_DEV_CSS_PREFIX } from "../vite-plugin-css/const.js";
4
4
  import { getDevCssModuleNameFromPageVirtualModuleName } from "../vite-plugin-css/util.js";
5
5
  import { isAstroServerEnvironment } from "../environments.js";
6
- const STYLE_EXT_REGEX = /\.(?:css|scss|sass|less|styl|pcss)$/i;
6
+ const STYLE_EXT_REGEX = /\.(?:css|less|sass|scss|styl|stylus|pcss|postcss|sss)$/i;
7
+ const STYLE_COMPONENT_EXT_REGEX = /\.(astro|svelte|vue)$/i;
7
8
  const RAW_QUERY_REGEX = /(?:\?|&)raw(?:&|$)/;
8
9
  function hasStyleExtension(id) {
9
10
  return STYLE_EXT_REGEX.test(id.split("?")[0]);
10
11
  }
11
- function isStyleModule(mod) {
12
- if (mod.id && RAW_QUERY_REGEX.test(mod.id) && hasStyleExtension(mod.id)) return false;
13
- if (mod.file && hasStyleExtension(mod.file)) return true;
14
- return mod.id ? hasStyleExtension(mod.id) : false;
12
+ function isComponentStyleModule(id) {
13
+ const [filename, rawQuery] = id.split("?", 2);
14
+ const extensionMatch = STYLE_COMPONENT_EXT_REGEX.exec(filename);
15
+ if (!rawQuery || !extensionMatch) return false;
16
+ const query = new URLSearchParams(rawQuery);
17
+ return query.get("type") === "style" && query.has(extensionMatch[1].toLowerCase());
18
+ }
19
+ function getStyleModuleType(mod) {
20
+ if (mod.id && RAW_QUERY_REGEX.test(mod.id) && hasStyleExtension(mod.id)) return;
21
+ if (mod.id && isComponentStyleModule(mod.id)) return "component";
22
+ if (mod.file && hasStyleExtension(mod.file)) return "file";
23
+ return mod.id && hasStyleExtension(mod.id) ? "file" : void 0;
24
+ }
25
+ function hasClientStyleModuleByFile(moduleGraph, mod, styleType) {
26
+ if (mod.file == null || moduleGraph.getModulesByFile == null) return false;
27
+ const fileModules = moduleGraph.getModulesByFile(mod.file);
28
+ if (fileModules == null) return false;
29
+ for (const fileMod of fileModules) {
30
+ if (fileMod.id == null) continue;
31
+ if (styleType === "component") {
32
+ if (isComponentStyleModule(fileMod.id)) return true;
33
+ } else if (!RAW_QUERY_REGEX.test(fileMod.id) && hasStyleExtension(fileMod.id)) {
34
+ return true;
35
+ }
36
+ }
37
+ return false;
15
38
  }
16
39
  function hmrReload() {
17
40
  return {
@@ -22,19 +45,45 @@ function hmrReload() {
22
45
  handler({ modules, server, timestamp, file }) {
23
46
  if (!isAstroServerEnvironment(this.environment)) return;
24
47
  let hasSsrOnlyModules = false;
48
+ let hasStyleModules = false;
25
49
  let hasSkippedStyleModules = false;
26
50
  const invalidatedModules = /* @__PURE__ */ new Set();
27
51
  for (const mod of modules) {
28
52
  if (mod.id == null) continue;
29
- if (isStyleModule(mod)) {
53
+ const styleType = getStyleModuleType(mod);
54
+ const clientModule = server.environments.client.moduleGraph.getModuleById(mod.id);
55
+ if (styleType) {
56
+ hasStyleModules = true;
57
+ if (clientModule == null && !hasClientStyleModuleByFile(server.environments.client.moduleGraph, mod, styleType)) {
58
+ this.environment.moduleGraph.invalidateModule(
59
+ mod,
60
+ invalidatedModules,
61
+ timestamp,
62
+ true
63
+ );
64
+ hasSsrOnlyModules = true;
65
+ continue;
66
+ }
30
67
  hasSkippedStyleModules = true;
31
68
  continue;
32
69
  }
33
- const clientModule = server.environments.client.moduleGraph.getModuleById(mod.id);
34
70
  if (clientModule != null) continue;
35
71
  this.environment.moduleGraph.invalidateModule(mod, invalidatedModules, timestamp, true);
36
72
  hasSsrOnlyModules = true;
37
73
  }
74
+ const invalidateDevCssModules = () => {
75
+ for (const [id, mod] of this.environment.moduleGraph.idToModuleMap) {
76
+ if (id.startsWith(RESOLVED_MODULE_DEV_CSS_PREFIX)) {
77
+ this.environment.moduleGraph.invalidateModule(mod, void 0, timestamp, true);
78
+ if (isRunnableDevEnvironment(this.environment)) {
79
+ const runnerMod = this.environment.runner.evaluatedModules.getModuleById(id);
80
+ if (runnerMod) {
81
+ this.environment.runner.evaluatedModules.invalidateModule(runnerMod);
82
+ }
83
+ }
84
+ }
85
+ }
86
+ };
38
87
  for (const invalidatedModule of invalidatedModules) {
39
88
  if (invalidatedModule.id?.startsWith(VIRTUAL_PAGE_RESOLVED_MODULE_ID)) {
40
89
  const cssMod = this.environment.moduleGraph.getModuleById(
@@ -45,6 +94,9 @@ function hmrReload() {
45
94
  }
46
95
  }
47
96
  if (hasSsrOnlyModules) {
97
+ if (hasStyleModules) {
98
+ invalidateDevCssModules();
99
+ }
48
100
  if (isRunnableDevEnvironment(this.environment)) {
49
101
  for (const invalidated of invalidatedModules) {
50
102
  if (invalidated.id == null) continue;
@@ -67,17 +119,7 @@ function hmrReload() {
67
119
  return [];
68
120
  }
69
121
  if (hasSkippedStyleModules) {
70
- for (const [id, mod] of this.environment.moduleGraph.idToModuleMap) {
71
- if (id.startsWith(RESOLVED_MODULE_DEV_CSS_PREFIX)) {
72
- this.environment.moduleGraph.invalidateModule(mod, void 0, timestamp, true);
73
- if (isRunnableDevEnvironment(this.environment)) {
74
- const runnerMod = this.environment.runner.evaluatedModules.getModuleById(id);
75
- if (runnerMod) {
76
- this.environment.runner.evaluatedModules.invalidateModule(runnerMod);
77
- }
78
- }
79
- }
80
- }
122
+ invalidateDevCssModules();
81
123
  return [];
82
124
  }
83
125
  if (modules.length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "7.1.5",
3
+ "version": "7.2.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",
@@ -96,11 +96,10 @@
96
96
  "README.md"
97
97
  ],
98
98
  "dependencies": {
99
- "@astrojs/compiler-rs": "^0.3.1",
99
+ "@astrojs/compiler-rs": "^0.3.2",
100
100
  "@capsizecss/unpack": "^4.0.0",
101
101
  "@clack/prompts": "^1.1.0",
102
102
  "@oslojs/encoding": "^1.1.0",
103
- "@rollup/pluginutils": "^5.3.0",
104
103
  "am-i-vibing": "^0.4.0",
105
104
  "aria-query": "^5.3.2",
106
105
  "axobject-query": "^4.1.0",