astro 6.3.5 → 6.3.7

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.
@@ -13,6 +13,7 @@ import {
13
13
  isImageMetadata
14
14
  } from "./types.js";
15
15
  import { isESMImportedImage, isRemoteImage, resolveSrc } from "./utils/imageKind.js";
16
+ import { resolveDefaultOutputFormat } from "./utils/inferSourceFormat.js";
16
17
  import { inferRemoteSize } from "./utils/remoteProbe.js";
17
18
  import { createPlaceholderURL, stringifyPlaceholderURL } from "./utils/url.js";
18
19
  import { verifyOptions } from "./services/service.js";
@@ -73,6 +74,9 @@ async function getImage(options, imageConfig) {
73
74
  const result = await getRemoteSize(resolvedOptions.src);
74
75
  resolvedOptions.width ??= result.width;
75
76
  resolvedOptions.height ??= result.height;
77
+ if (result.format) {
78
+ resolvedOptions.format ??= resolveDefaultOutputFormat(result.format);
79
+ }
76
80
  originalWidth = result.width;
77
81
  originalHeight = result.height;
78
82
  }
@@ -126,6 +130,11 @@ async function getImage(options, imageConfig) {
126
130
  resolvedOptions["data-astro-image-pos"] = currentPosition.replace(/\s+/g, "-");
127
131
  }
128
132
  const validatedOptions = service.validateOptions ? await service.validateOptions(resolvedOptions, imageConfig) : resolvedOptions;
133
+ validatedOptions.format ??= await peekRemoteFormatForStaticEmit(
134
+ validatedOptions,
135
+ imageConfig,
136
+ service
137
+ );
129
138
  const srcSetTransforms = service.getSrcSet ? await service.getSrcSet(validatedOptions, imageConfig) : [];
130
139
  const lazyImageURLFactory = (getValue) => {
131
140
  let cached = null;
@@ -187,6 +196,17 @@ async function getImage(options, imageConfig) {
187
196
  attributes: service.getHTMLAttributes !== void 0 ? await service.getHTMLAttributes(validatedOptions, imageConfig) : {}
188
197
  };
189
198
  }
199
+ async function peekRemoteFormatForStaticEmit(options, imageConfig, service) {
200
+ if (!isRemoteImage(options.src) || !isRemoteAllowed(options.src, imageConfig) || !globalThis.astroAsset?.addStaticImage || !isLocalService(service) || !service.getRemoteSize) {
201
+ return void 0;
202
+ }
203
+ try {
204
+ const probed = await service.getRemoteSize(options.src, imageConfig);
205
+ return resolveDefaultOutputFormat(probed.format);
206
+ } catch {
207
+ return void 0;
208
+ }
209
+ }
190
210
  export {
191
211
  cssFitValues,
192
212
  getConfiguredImageService,
@@ -82,7 +82,7 @@ export type BaseServiceTransform = {
82
82
  src: string;
83
83
  width?: number;
84
84
  height?: number;
85
- format: string;
85
+ format?: string;
86
86
  quality?: string | null;
87
87
  fit?: ImageFit;
88
88
  position?: string;
@@ -1,8 +1,9 @@
1
1
  import { isRemoteAllowed } from "@astrojs/internal-helpers/remote";
2
2
  import { AstroError, AstroErrorData } from "../../core/errors/index.js";
3
3
  import { isRemotePath, joinPaths } from "../../core/path.js";
4
- import { DEFAULT_HASH_PROPS, DEFAULT_OUTPUT_FORMAT, VALID_SUPPORTED_FORMATS } from "../consts.js";
4
+ import { DEFAULT_HASH_PROPS, VALID_SUPPORTED_FORMATS } from "../consts.js";
5
5
  import { isESMImportedImage, isRemoteImage } from "../utils/imageKind.js";
6
+ import { inferSourceFormat, resolveDefaultOutputFormat } from "../utils/inferSourceFormat.js";
6
7
  import { inferRemoteSize } from "../utils/remoteProbe.js";
7
8
  function isLocalService(service) {
8
9
  if (!service) {
@@ -74,10 +75,11 @@ const baseService = {
74
75
  validateOptions(options) {
75
76
  verifyOptions(options);
76
77
  if (!options.format) {
77
- if (isESMImportedImage(options.src) && options.src.format === "svg") {
78
- options.format = "svg";
78
+ if (isESMImportedImage(options.src)) {
79
+ options.format = resolveDefaultOutputFormat(options.src.format);
79
80
  } else {
80
- options.format = DEFAULT_OUTPUT_FORMAT;
81
+ const inferred = inferSourceFormat(options.src);
82
+ if (inferred) options.format = resolveDefaultOutputFormat(inferred);
81
83
  }
82
84
  }
83
85
  if (options.width) options.width = Math.round(options.width);
@@ -120,7 +122,7 @@ const baseService = {
120
122
  const { targetWidth, targetHeight } = getTargetDimensions(options);
121
123
  const aspectRatio = targetWidth / targetHeight;
122
124
  const { widths, densities } = options;
123
- const targetFormat = options.format ?? DEFAULT_OUTPUT_FORMAT;
125
+ const targetFormat = options.format;
124
126
  let transformedWidths = (widths ?? []).sort(sortNumeric);
125
127
  let imageWidth = options.width;
126
128
  let maxWidth = Number.POSITIVE_INFINITY;
@@ -164,9 +166,7 @@ const baseService = {
164
166
  return {
165
167
  transform,
166
168
  descriptor,
167
- attributes: {
168
- type: `image/${targetFormat}`
169
- }
169
+ attributes: targetFormat ? { type: `image/${targetFormat}` } : {}
170
170
  };
171
171
  });
172
172
  },
@@ -210,7 +210,7 @@ const baseService = {
210
210
  src: params.get("href"),
211
211
  width: params.has("w") ? Number.parseInt(params.get("w")) : void 0,
212
212
  height: params.has("h") ? Number.parseInt(params.get("h")) : void 0,
213
- format: params.get("f"),
213
+ format: params.has("f") ? params.get("f") : void 0,
214
214
  quality: params.get("q"),
215
215
  fit: params.get("fit"),
216
216
  position: params.get("position") ?? void 0,
@@ -1,4 +1,5 @@
1
1
  import { AstroError, AstroErrorData } from "../../core/errors/index.js";
2
+ import { resolveDefaultOutputFormat } from "../utils/inferSourceFormat.js";
2
3
  import { detector } from "../utils/vendor/image-size/detector.js";
3
4
  import {
4
5
  baseService,
@@ -21,6 +22,9 @@ function resolveSharpQuality(quality) {
21
22
  }
22
23
  function resolveSharpEncoderOptions(transform, inputFormat, serviceConfig = {}) {
23
24
  const quality = resolveSharpQuality(transform.quality);
25
+ if (transform.format === void 0) {
26
+ return quality === void 0 ? void 0 : { quality };
27
+ }
24
28
  switch (transform.format) {
25
29
  case "jpg":
26
30
  case "jpeg":
@@ -82,11 +86,27 @@ const sharpService = {
82
86
  if (!sharp) sharp = await loadSharp();
83
87
  const transform = transformOptions;
84
88
  const kernel = config.service.config.kernel;
85
- if (transform.format === "svg") return { data: inputBuffer, format: "svg" };
86
- if (detector(inputBuffer) === "svg" && !config.dangerouslyProcessSVG) {
89
+ const bufferFormat = detector(inputBuffer);
90
+ const outputFormat = transform.format ?? resolveDefaultOutputFormat(bufferFormat);
91
+ if (outputFormat === "svg") {
92
+ if (bufferFormat && bufferFormat !== "svg") {
93
+ console.warn(
94
+ `\u26A0\uFE0F Astro expected an SVG for "${transform.src}" but the source is ${bufferFormat}. Passing it through as ${bufferFormat} instead.`
95
+ );
96
+ return { data: inputBuffer, format: bufferFormat };
97
+ }
98
+ return { data: inputBuffer, format: "svg" };
99
+ }
100
+ if (!bufferFormat) {
101
+ throw new AstroError({
102
+ ...AstroErrorData.NoImageMetadata,
103
+ message: AstroErrorData.NoImageMetadata.message(transform.src)
104
+ });
105
+ }
106
+ if (bufferFormat === "svg" && !config.dangerouslyProcessSVG) {
87
107
  throw new AstroError({
88
108
  ...AstroErrorData.UnsupportedImageFormat,
89
- message: "SVG image processing is disabled. Set `image.dangerouslyProcessSVG: true` to allow processing of SVG sources."
109
+ message: `SVG image processing is disabled, but the source for "${transform.src}" is an SVG. Pass it through unchanged by setting \`format="svg"\` on the component, or set \`image.dangerouslyProcessSVG: true\` to rasterize SVG sources.`
90
110
  });
91
111
  }
92
112
  const result = sharp(inputBuffer, {
@@ -95,15 +115,6 @@ const sharpService = {
95
115
  limitInputPixels: config.service.config.limitInputPixels
96
116
  });
97
117
  result.rotate();
98
- let format;
99
- try {
100
- ({ format } = await result.metadata());
101
- } catch {
102
- console.warn(
103
- `\u26A0\uFE0F Astro could not optimize image "${transform.src}". Sharp doesn't support this format. The image will be used unoptimized. Consider converting to WebP or placing in the public/ folder.`
104
- );
105
- return { data: inputBuffer, format: transform.format };
106
- }
107
118
  if (transform.width && transform.height) {
108
119
  const fit = transform.fit ? fitMap[transform.fit] ?? "inside" : void 0;
109
120
  result.resize({
@@ -130,23 +141,32 @@ const sharpService = {
130
141
  if (transform.background) {
131
142
  result.flatten({ background: transform.background });
132
143
  }
133
- if (transform.format) {
134
- const encoderOptions = resolveSharpEncoderOptions(transform, format, config.service.config);
135
- if (transform.format === "webp" && format === "gif") {
136
- result.webp(encoderOptions);
137
- } else if (transform.format === "webp") {
138
- result.webp(encoderOptions);
139
- } else if (transform.format === "png") {
140
- result.png(encoderOptions);
141
- } else if (transform.format === "avif") {
142
- result.avif(encoderOptions);
143
- } else if (transform.format === "jpeg" || transform.format === "jpg") {
144
- result.jpeg(encoderOptions);
145
- } else {
146
- result.toFormat(transform.format, encoderOptions);
147
- }
144
+ const encoderOptions = resolveSharpEncoderOptions(
145
+ { format: outputFormat, quality: transform.quality },
146
+ bufferFormat,
147
+ config.service.config
148
+ );
149
+ if (outputFormat === "webp") {
150
+ result.webp(encoderOptions);
151
+ } else if (outputFormat === "png") {
152
+ result.png(encoderOptions);
153
+ } else if (outputFormat === "avif") {
154
+ result.avif(encoderOptions);
155
+ } else if (outputFormat === "jpeg" || outputFormat === "jpg") {
156
+ result.jpeg(encoderOptions);
157
+ } else {
158
+ result.toFormat(outputFormat, encoderOptions);
159
+ }
160
+ let data;
161
+ let info;
162
+ try {
163
+ ({ data, info } = await result.toBuffer({ resolveWithObject: true }));
164
+ } catch {
165
+ console.warn(
166
+ `\u26A0\uFE0F Astro could not optimize image "${transform.src}". Sharp doesn't support this format. The image will be used unoptimized. Consider converting to WebP or placing in the public/ folder.`
167
+ );
168
+ return { data: inputBuffer, format: bufferFormat };
148
169
  }
149
- const { data, info } = await result.toBuffer({ resolveWithObject: true });
150
170
  const needsCopy = "buffer" in data && data.buffer instanceof SharedArrayBuffer;
151
171
  return {
152
172
  data: needsCopy ? new Uint8Array(data) : data,
@@ -1,6 +1,11 @@
1
1
  /**
2
- * Infer the image format from a source path or URL by examining
3
- * the file extension. For data: URIs, the MIME type is extracted.
4
- * Returns undefined if the format cannot be determined.
2
+ * Infer the image format from a source path or URL.
3
+ *
4
+ * For `data:` URIs the MIME is read up to the first `;` or `,` (whichever comes first),
5
+ * so both `data:image/svg+xml;base64,...` and `data:image/svg+xml,<svg>...` work.
6
+ * `image/svg+xml` normalizes to `svg`; otherwise the subtype after the slash is returned.
7
+ *
8
+ * Returns undefined when the format cannot be determined.
5
9
  */
6
10
  export declare function inferSourceFormat(src: string): string | undefined;
11
+ export declare function resolveDefaultOutputFormat(sourceFormat: string | undefined): string;
@@ -1,21 +1,32 @@
1
1
  import { removeQueryString } from "@astrojs/internal-helpers/path";
2
+ import { DEFAULT_OUTPUT_FORMAT } from "../consts.js";
2
3
  const DATA_PREFIX = "data:";
3
4
  function inferSourceFormat(src) {
4
5
  if (src.startsWith(DATA_PREFIX)) {
5
- const mime = src.slice(DATA_PREFIX.length, src.indexOf(";"));
6
+ const sepIndex = src.indexOf(";");
7
+ const commaIndex = src.indexOf(",");
8
+ const mimeEnd = sepIndex === -1 ? commaIndex : commaIndex === -1 ? sepIndex : Math.min(sepIndex, commaIndex);
9
+ if (mimeEnd === -1) return void 0;
10
+ const mime = src.slice(DATA_PREFIX.length, mimeEnd);
6
11
  if (mime === "image/svg+xml") return "svg";
7
12
  const sub = mime.split("/")[1];
8
13
  return sub || void 0;
9
14
  }
10
15
  try {
11
16
  const cleanSrc = removeQueryString(src).split("#")[0];
12
- const lastDot = cleanSrc.lastIndexOf(".");
17
+ const lastSlash = cleanSrc.lastIndexOf("/");
18
+ const basename = lastSlash === -1 ? cleanSrc : cleanSrc.slice(lastSlash + 1);
19
+ const lastDot = basename.lastIndexOf(".");
13
20
  if (lastDot === -1) return void 0;
14
- return cleanSrc.slice(lastDot + 1).toLowerCase();
21
+ return basename.slice(lastDot + 1).toLowerCase();
15
22
  } catch {
16
23
  return void 0;
17
24
  }
18
25
  }
26
+ function resolveDefaultOutputFormat(sourceFormat) {
27
+ return sourceFormat === "svg" ? "svg" : DEFAULT_OUTPUT_FORMAT;
28
+ }
19
29
  export {
20
- inferSourceFormat
30
+ inferSourceFormat,
31
+ resolveDefaultOutputFormat
21
32
  };
@@ -1,6 +1,6 @@
1
1
  class BuildTimeAstroVersionProvider {
2
2
  // Injected during the build through esbuild define
3
- version = "6.3.5";
3
+ version = "6.3.7";
4
4
  }
5
5
  export {
6
6
  BuildTimeAstroVersionProvider
@@ -191,7 +191,7 @@ ${contentConfig.error.message}`
191
191
  logger.info("Content config changed");
192
192
  shouldClear = true;
193
193
  }
194
- if (previousAstroVersion && previousAstroVersion !== "6.3.5") {
194
+ if (previousAstroVersion && previousAstroVersion !== "6.3.7") {
195
195
  logger.info("Astro version changed");
196
196
  shouldClear = true;
197
197
  }
@@ -199,8 +199,8 @@ ${contentConfig.error.message}`
199
199
  logger.info("Clearing content store");
200
200
  this.#store.clearAll();
201
201
  }
202
- if ("6.3.5") {
203
- this.#store.metaStore().set("astro-version", "6.3.5");
202
+ if ("6.3.7") {
203
+ this.#store.metaStore().set("astro-version", "6.3.7");
204
204
  }
205
205
  if (currentConfigDigest) {
206
206
  this.#store.metaStore().set("content-config-digest", currentConfigDigest);
@@ -351,7 +351,7 @@ async function updateImageReferencesInBody(html, fileName) {
351
351
  srcset: image.srcSet.attribute,
352
352
  // This attribute is used by the toolbar audit
353
353
  ...import.meta.env.DEV ? { "data-image-component": "true" } : {}
354
- }).map(([key, value]) => value ? `${key}="${escape(value)}"` : "").join(" ");
354
+ }).filter(([, value]) => value != null).map(([key, value]) => value === "" ? `${key}=""` : `${key}="${escape(String(value))}"`).join(" ");
355
355
  });
356
356
  }
357
357
  function updateImageReferencesInData(data, fileName, imageAssetMap) {
@@ -447,7 +447,11 @@ async function generateJSONSchema(fsMod, collectionConfig, collectionKey, collec
447
447
  zodSchemaForJson = await getContentLayerSchema(collectionConfig, collectionKey);
448
448
  }
449
449
  if (collectionConfig.type === CONTENT_LAYER_TYPE && collectionConfig.loader.name === "file-loader") {
450
- zodSchemaForJson = z.object({}).catchall(zodSchemaForJson);
450
+ const itemSchema = zodSchemaForJson;
451
+ zodSchemaForJson = z.union([
452
+ z.array(itemSchema),
453
+ z.object({ $schema: z.string().optional() }).catchall(itemSchema)
454
+ ]);
451
455
  }
452
456
  if (zodSchemaForJson instanceof z.ZodObject) {
453
457
  const existingMeta = z.globalRegistry.get(zodSchemaForJson);
@@ -219,6 +219,9 @@ function makeRequestBody(req, bodySizeLimit) {
219
219
  if (typeof req.body === "string" && req.body.length > 0) {
220
220
  return { body: Buffer.from(req.body) };
221
221
  }
222
+ if (req.body instanceof ArrayBuffer || ArrayBuffer.isView(req.body)) {
223
+ return { body: req.body };
224
+ }
222
225
  if (typeof req.body === "object" && req.body !== null && Object.keys(req.body).length > 0) {
223
226
  return { body: Buffer.from(JSON.stringify(req.body)) };
224
227
  }
@@ -1,6 +1,13 @@
1
1
  function getTimeStat(timeStart, timeEnd) {
2
2
  const buildTime = timeEnd - timeStart;
3
- return buildTime < 1e3 ? `${Math.round(buildTime)}ms` : `${(buildTime / 1e3).toFixed(2)}s`;
3
+ if (buildTime < 1e3) {
4
+ return `${Math.round(buildTime)}ms`;
5
+ } else if (buildTime < 6e4) {
6
+ return `${(buildTime / 1e3).toFixed(2)}s`;
7
+ }
8
+ const mins = Math.floor(buildTime / 6e4);
9
+ const secs = Math.round(buildTime % 6e4 / 1e3);
10
+ return `${mins}m ${secs}s`;
4
11
  }
5
12
  function shouldAppendForwardSlash(trailingSlash, buildFormat) {
6
13
  switch (trailingSlash) {
@@ -118,11 +118,16 @@ function createViteBuildConfig(opts) {
118
118
  target: "esnext",
119
119
  outDir: fileURLToPath(getClientOutputDirectory(settings)),
120
120
  copyPublicDir: true,
121
- sourcemap: viteConfig.environments?.client?.build?.sourcemap ?? false,
122
- minify: true,
121
+ sourcemap: viteConfig.environments?.client?.build?.sourcemap ?? viteConfig.build?.sourcemap ?? false,
122
+ minify: viteConfig.environments?.client?.build?.minify ?? viteConfig.build?.minify ?? true,
123
123
  rollupOptions: {
124
124
  preserveEntrySignatures: "exports-only",
125
125
  output: {
126
+ // Inherit top-level rollup output options (e.g. compact) as a
127
+ // base, then layer Astro defaults on top so that Astro's
128
+ // naming functions are preserved unless explicitly overridden
129
+ // via the environment-specific config.
130
+ ...viteConfig.build?.rollupOptions?.output,
126
131
  entryFileNames(chunkInfo) {
127
132
  return `${settings.config.build.assets}/${cleanChunkName(chunkInfo.name)}.[hash].js`;
128
133
  },
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "6.3.5";
1
+ const ASTRO_VERSION = "6.3.7";
2
2
  const ASTRO_GENERATOR = `Astro v${ASTRO_VERSION}`;
3
3
  const REROUTE_DIRECTIVE_HEADER = "X-Astro-Reroute";
4
4
  const REWRITE_DIRECTIVE_HEADER_KEY = "X-Astro-Rewrite";
@@ -37,7 +37,7 @@ async function dev(inlineConfig) {
37
37
  await telemetry.record([]);
38
38
  const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
39
39
  const logger = restart.container.logger;
40
- const currentVersion = "6.3.5";
40
+ const currentVersion = "6.3.7";
41
41
  const isPrerelease = currentVersion.includes("-");
42
42
  if (!isPrerelease) {
43
43
  try {
@@ -276,7 +276,7 @@ function printHelp({
276
276
  message.push(
277
277
  linebreak(),
278
278
  ` ${bgGreen(black(` ${commandName} `))} ${green(
279
- `v${"6.3.5"}`
279
+ `v${"6.3.7"}`
280
280
  )} ${headline}`
281
281
  );
282
282
  }
@@ -13,6 +13,7 @@ interface CallGetStaticPathsOptions {
13
13
  }
14
14
  export declare function callGetStaticPaths({ mod, route, routeCache, ssr, base, trailingSlash, }: CallGetStaticPathsOptions): Promise<GetStaticPathsResultKeyed>;
15
15
  interface RouteCacheEntry {
16
+ mod?: ComponentInstance;
16
17
  staticPaths: GetStaticPathsResultKeyed;
17
18
  }
18
19
  /**
@@ -13,7 +13,7 @@ async function callGetStaticPaths({
13
13
  if (!mod) {
14
14
  throw new Error("This is an error caused by Astro and not your code. Please file an issue.");
15
15
  }
16
- if (cached?.staticPaths) {
16
+ if (cached?.staticPaths && cached.mod === mod) {
17
17
  return cached.staticPaths;
18
18
  }
19
19
  validateDynamicRouteModule(mod, { ssr, route });
@@ -39,7 +39,7 @@ async function callGetStaticPaths({
39
39
  const paramsKey = stringifyParams(sp.params, route, trailingSlash);
40
40
  keyedStaticPaths.keyed.set(paramsKey, sp);
41
41
  }
42
- routeCache.set(route, { ...cached, staticPaths: keyedStaticPaths });
42
+ routeCache.set(route, { ...cached, mod, staticPaths: keyedStaticPaths });
43
43
  return keyedStaticPaths;
44
44
  }
45
45
  class RouteCache {
@@ -4,16 +4,18 @@ class MultiLevelEncodingError extends Error {
4
4
  this.name = "MultiLevelEncodingError";
5
5
  }
6
6
  }
7
+ const ENCODING_REGEX = /%25[0-9a-fA-F]{2}/;
7
8
  function validateAndDecodePathname(pathname) {
9
+ if (ENCODING_REGEX.test(pathname)) {
10
+ throw new MultiLevelEncodingError();
11
+ }
8
12
  let decoded;
9
13
  try {
10
14
  decoded = decodeURI(pathname);
11
15
  } catch (_e) {
12
16
  throw new Error("Invalid URL encoding");
13
17
  }
14
- const hasDecoding = decoded !== pathname;
15
- const decodedStillHasEncoding = /%[0-9a-fA-F]{2}/.test(decoded);
16
- if (hasDecoding && decodedStillHasEncoding) {
18
+ if (ENCODING_REGEX.test(decoded)) {
17
19
  throw new MultiLevelEncodingError();
18
20
  }
19
21
  return decoded;
@@ -17,7 +17,8 @@ function virtualModulePlugin({ settings }) {
17
17
  defaultLocale: ${JSON.stringify(config.i18n.defaultLocale)},
18
18
  locales: ${JSON.stringify(config.i18n.locales)},
19
19
  routing: ${JSON.stringify(routing)},
20
- fallback: ${JSON.stringify(config.i18n.fallback)}
20
+ fallback: ${JSON.stringify(config.i18n.fallback)},
21
+ domains: ${JSON.stringify(config.i18n.domains)}
21
22
  };`;
22
23
  }
23
24
  let imageCode = "const image = undefined;";
@@ -75,7 +75,7 @@ Did you forget to import the component or is it possible there is a typo?`);
75
75
  }
76
76
  case (!vnode.type && vnode.type !== 0):
77
77
  return "";
78
- case (typeof vnode.type === "string" && vnode.type !== ClientOnlyPlaceholder):
78
+ case (typeof vnode.type === "string" && vnode.type !== ClientOnlyPlaceholder && !vnode.type.includes("-")):
79
79
  return markHTMLString(await renderElement(result, vnode.type, vnode.props ?? {}));
80
80
  }
81
81
  if (vnode.type) {
@@ -1,4 +1,4 @@
1
- import * as config from "astro:config/server";
1
+ import * as config from "astro:config/client";
2
2
  import { toFallbackType } from "../core/app/common.js";
3
3
  import { toRoutingStrategy } from "../core/app/entrypoints/index.js";
4
4
  import {
@@ -31,12 +31,6 @@ function hmrReload() {
31
31
  const clientModule = server.environments.client.moduleGraph.getModuleById(mod.id);
32
32
  if (clientModule != null) continue;
33
33
  this.environment.moduleGraph.invalidateModule(mod, invalidatedModules, timestamp, true);
34
- if (isRunnableDevEnvironment(this.environment)) {
35
- const runnerModule = this.environment.runner.evaluatedModules.getModuleById(mod.id);
36
- if (runnerModule) {
37
- this.environment.runner.evaluatedModules.invalidateModule(runnerModule);
38
- }
39
- }
40
34
  hasSsrOnlyModules = true;
41
35
  }
42
36
  for (const invalidatedModule of invalidatedModules) {
@@ -49,6 +43,17 @@ function hmrReload() {
49
43
  }
50
44
  }
51
45
  if (hasSsrOnlyModules) {
46
+ if (isRunnableDevEnvironment(this.environment)) {
47
+ for (const invalidated of invalidatedModules) {
48
+ if (invalidated.id == null) continue;
49
+ const runnerModule = this.environment.runner.evaluatedModules.getModuleById(
50
+ invalidated.id
51
+ );
52
+ if (runnerModule) {
53
+ this.environment.runner.evaluatedModules.invalidateModule(runnerModule);
54
+ }
55
+ }
56
+ }
52
57
  server.ws.send({ type: "full-reload" });
53
58
  if (!isRunnableDevEnvironment(this.environment)) {
54
59
  this.environment.hot.send({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "6.3.5",
3
+ "version": "6.3.7",
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",
@@ -164,9 +164,9 @@
164
164
  "xxhash-wasm": "^1.1.0",
165
165
  "yargs-parser": "^22.0.0",
166
166
  "zod": "^4.3.6",
167
+ "@astrojs/internal-helpers": "0.9.1",
167
168
  "@astrojs/telemetry": "3.3.2",
168
- "@astrojs/markdown-remark": "7.1.2",
169
- "@astrojs/internal-helpers": "0.9.1"
169
+ "@astrojs/markdown-remark": "7.1.2"
170
170
  },
171
171
  "optionalDependencies": {
172
172
  "sharp": "^0.34.0"