astro 2.1.8 → 2.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 (71) hide show
  1. package/config.d.ts +2 -1
  2. package/dist/@types/astro.d.ts +36 -9
  3. package/dist/assets/image-endpoint.js +2 -2
  4. package/dist/assets/index.d.ts +1 -1
  5. package/dist/assets/index.js +3 -2
  6. package/dist/assets/internal.d.ts +9 -9
  7. package/dist/assets/internal.js +10 -1
  8. package/dist/assets/services/service.d.ts +2 -2
  9. package/dist/assets/services/service.js +6 -0
  10. package/dist/assets/services/vendor/squoosh/copy-wasm.d.ts +1 -0
  11. package/dist/assets/services/vendor/squoosh/copy-wasm.js +19 -6
  12. package/dist/assets/services/vendor/squoosh/image-pool.d.ts +2 -2
  13. package/dist/assets/services/vendor/squoosh/image.d.ts +2 -2
  14. package/dist/assets/types.d.ts +19 -10
  15. package/dist/assets/utils/emitAsset.d.ts +2 -1
  16. package/dist/assets/utils/emitAsset.js +4 -1
  17. package/dist/assets/utils/transformToPath.d.ts +2 -1
  18. package/dist/assets/utils/transformToPath.js +7 -3
  19. package/dist/assets/vite-plugin-assets.js +21 -19
  20. package/dist/cli/index.js +1 -1
  21. package/dist/content/runtime-assets.d.ts +3 -7
  22. package/dist/content/runtime-assets.js +20 -16
  23. package/dist/content/template/virtual-mod.d.mts +1 -0
  24. package/dist/content/utils.d.ts +2 -6
  25. package/dist/content/utils.js +16 -56
  26. package/dist/content/vite-plugin-content-assets.js +13 -4
  27. package/dist/content/vite-plugin-content-imports.js +3 -4
  28. package/dist/content/vite-plugin-content-virtual-mod.js +1 -4
  29. package/dist/core/app/index.js +2 -0
  30. package/dist/core/build/add-rollup-input.d.ts +2 -2
  31. package/dist/core/build/generate.js +27 -7
  32. package/dist/core/build/internal.d.ts +3 -3
  33. package/dist/core/build/plugins/plugin-css.js +0 -29
  34. package/dist/core/build/plugins/plugin-internals.js +0 -7
  35. package/dist/core/build/plugins/plugin-ssr.js +12 -7
  36. package/dist/core/build/static-build.js +7 -3
  37. package/dist/core/config/schema.d.ts +12 -0
  38. package/dist/core/config/schema.js +2 -0
  39. package/dist/core/constants.js +1 -1
  40. package/dist/core/cookies/cookies.js +7 -0
  41. package/dist/core/create-vite.js +11 -2
  42. package/dist/core/dev/container.js +0 -3
  43. package/dist/core/dev/dev.js +1 -1
  44. package/dist/core/errors/dev/utils.js +6 -2
  45. package/dist/core/errors/errors-data.d.ts +76 -3
  46. package/dist/core/errors/errors-data.js +76 -3
  47. package/dist/core/errors/overlay.js +8 -6
  48. package/dist/core/messages.js +2 -2
  49. package/dist/core/render/dev/index.js +1 -1
  50. package/dist/core/render/dev/scripts.d.ts +1 -1
  51. package/dist/core/render/dev/scripts.js +7 -6
  52. package/dist/core/render/paginate.js +15 -8
  53. package/dist/core/render/result.js +6 -0
  54. package/dist/core/render/ssr-element.d.ts +7 -6
  55. package/dist/core/render/ssr-element.js +28 -20
  56. package/dist/core/sync/index.js +9 -2
  57. package/dist/core/util.d.ts +1 -1
  58. package/dist/core/util.js +2 -2
  59. package/dist/runtime/server/render/common.d.ts +1 -1
  60. package/dist/vite-plugin-astro-server/response.d.ts +1 -1
  61. package/dist/vite-plugin-astro-server/response.js +2 -1
  62. package/dist/vite-plugin-astro-server/route.js +1 -1
  63. package/dist/vite-plugin-env/index.js +9 -0
  64. package/dist/vite-plugin-markdown/index.js +31 -14
  65. package/package.json +3 -3
  66. package/src/content/template/types.d.ts +23 -3
  67. package/src/content/template/virtual-mod.mjs +7 -0
  68. package/dist/content/template/virtual-mod-assets.d.mts +0 -1
  69. package/dist/vite-plugin-integrations-container/index.d.ts +0 -8
  70. package/dist/vite-plugin-integrations-container/index.js +0 -15
  71. package/src/content/template/virtual-mod-assets.mjs +0 -7
package/config.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  type ViteUserConfig = import('vite').UserConfig;
2
+ type ViteUserConfigFn = import('vite').UserConfigFn;
2
3
  type AstroUserConfig = import('./dist/@types/astro.js').AstroUserConfig;
3
4
 
4
5
  /**
@@ -10,4 +11,4 @@ export function defineConfig(config: AstroUserConfig): AstroUserConfig;
10
11
  /**
11
12
  * Use Astro to generate a fully resolved Vite config
12
13
  */
13
- export function getViteConfig(config: ViteUserConfig): ViteUserConfig;
14
+ export function getViteConfig(config: ViteUserConfig): ViteUserConfigFn;
@@ -18,8 +18,8 @@ import type { LogOptions } from '../core/logger/core';
18
18
  import type { AstroComponentFactory, AstroComponentInstance } from '../runtime/server';
19
19
  import type { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './../core/constants.js';
20
20
  export type { MarkdownHeading, MarkdownMetadata, MarkdownRenderingResult, RehypePlugins, RemarkPlugins, ShikiConfig, } from '@astrojs/markdown-remark';
21
- export type { ExternalImageService, LocalImageService } from '../assets/services/service';
22
- export type { ImageMetadata, ImageTransform } from '../assets/types';
21
+ export type { ExternalImageService, ImageService, LocalImageService, } from '../assets/services/service';
22
+ export type { GetImageResult, ImageInputFormat, ImageMetadata, ImageOutputFormat, ImageQuality, ImageQualityPreset, ImageTransform, } from '../assets/types';
23
23
  export type { SSRManifest } from '../core/app/types';
24
24
  export type { AstroCookies } from '../core/cookies';
25
25
  export interface AstroBuiltinProps {
@@ -568,6 +568,29 @@ export interface AstroUserConfig {
568
568
  * ```
569
569
  */
570
570
  assets?: string;
571
+ /**
572
+ * @docs
573
+ * @name build.assetsPrefix
574
+ * @type {string}
575
+ * @default `undefined`
576
+ * @version 2.2.0
577
+ * @description
578
+ * Specifies the prefix for Astro-generated asset links. This can be used if assets are served from a different domain than the current site.
579
+ *
580
+ * For example, if this is set to `https://cdn.example.com`, assets will be fetched from `https://cdn.example.com/_astro/...` (regardless of the `base` option).
581
+ * You would need to upload the files in `./dist/_astro/` to `https://cdn.example.com/_astro/` to serve the assets.
582
+ * The process varies depending on how the third-party domain is hosted.
583
+ * To rename the `_astro` path, specify a new directory in `build.assets`.
584
+ *
585
+ * ```js
586
+ * {
587
+ * build: {
588
+ * assetsPrefix: 'https://cdn.example.com'
589
+ * }
590
+ * }
591
+ * ```
592
+ */
593
+ assetsPrefix?: string;
571
594
  /**
572
595
  * @docs
573
596
  * @name build.serverEntry
@@ -1086,11 +1109,13 @@ export type GetStaticPaths = (options: GetStaticPathsOptions) => Promise<GetStat
1086
1109
  *
1087
1110
  * @example
1088
1111
  * ```ts
1089
- * export async function getStaticPaths() {
1112
+ * import type { GetStaticPaths } from 'astro';
1113
+ *
1114
+ * export const getStaticPaths = (() => {
1090
1115
  * return results.map((entry) => ({
1091
1116
  * params: { slug: entry.slug },
1092
1117
  * }));
1093
- * }
1118
+ * }) satisfies GetStaticPaths;
1094
1119
  *
1095
1120
  * type Params = InferGetStaticParamsType<typeof getStaticPaths>;
1096
1121
  * // ^? { slug: string; }
@@ -1098,7 +1123,7 @@ export type GetStaticPaths = (options: GetStaticPathsOptions) => Promise<GetStat
1098
1123
  * const { slug } = Astro.params as Params;
1099
1124
  * ```
1100
1125
  */
1101
- export type InferGetStaticParamsType<T> = T extends () => Promise<infer R> ? R extends Array<infer U> ? U extends {
1126
+ export type InferGetStaticParamsType<T> = T extends () => infer R | Promise<infer R> ? R extends Array<infer U> ? U extends {
1102
1127
  params: infer P;
1103
1128
  } ? P : never : never : never;
1104
1129
  /**
@@ -1106,7 +1131,9 @@ export type InferGetStaticParamsType<T> = T extends () => Promise<infer R> ? R e
1106
1131
  *
1107
1132
  * @example
1108
1133
  * ```ts
1109
- * export async function getStaticPaths() {
1134
+ * import type { GetStaticPaths } from 'astro';
1135
+ *
1136
+ * export const getStaticPaths = (() => {
1110
1137
  * return results.map((entry) => ({
1111
1138
  * params: { slug: entry.slug },
1112
1139
  * props: {
@@ -1114,15 +1141,15 @@ export type InferGetStaticParamsType<T> = T extends () => Promise<infer R> ? R e
1114
1141
  * propB: 42
1115
1142
  * },
1116
1143
  * }));
1117
- * }
1144
+ * }) satisfies GetStaticPaths;
1118
1145
  *
1119
1146
  * type Props = InferGetStaticPropsType<typeof getStaticPaths>;
1120
1147
  * // ^? { propA: boolean; propB: number; }
1121
1148
  *
1122
- * const { propA, propB } = Astro.props as Props;
1149
+ * const { propA, propB } = Astro.props;
1123
1150
  * ```
1124
1151
  */
1125
- export type InferGetStaticPropsType<T> = T extends () => Promise<infer R> ? R extends Array<infer U> ? U extends {
1152
+ export type InferGetStaticPropsType<T> = T extends () => infer R | Promise<infer R> ? R extends Array<infer U> ? U extends {
1126
1153
  props: infer P;
1127
1154
  } ? P : never : never : never;
1128
1155
  export interface HydrateOptions {
@@ -1,4 +1,4 @@
1
- import mime from "mime";
1
+ import mime from "mime/lite.js";
2
2
  import { isRemotePath } from "../core/path.js";
3
3
  import { getConfiguredImageService } from "./internal.js";
4
4
  import { isLocalService } from "./services/service.js";
@@ -35,7 +35,7 @@ const get = async ({ request }) => {
35
35
  return new Response(data, {
36
36
  status: 200,
37
37
  headers: {
38
- "Content-Type": mime.getType(format) || "",
38
+ "Content-Type": mime.getType(format) ?? `image/${format}`,
39
39
  "Cache-Control": "public, max-age=31536000",
40
40
  ETag: etag(data.toString()),
41
41
  Date: (/* @__PURE__ */ new Date()).toUTCString()
@@ -1,5 +1,5 @@
1
1
  export { getConfiguredImageService, getImage } from './internal.js';
2
- export { baseService } from './services/service.js';
2
+ export { baseService, isLocalService } from './services/service.js';
3
3
  export { type LocalImageProps, type RemoteImageProps } from './types.js';
4
4
  export { emitESMImage } from './utils/emitAsset.js';
5
5
  export { imageMetadata } from './utils/metadata.js';
@@ -1,5 +1,5 @@
1
1
  import { getConfiguredImageService, getImage } from "./internal.js";
2
- import { baseService } from "./services/service.js";
2
+ import { baseService, isLocalService } from "./services/service.js";
3
3
  import {} from "./types.js";
4
4
  import { emitESMImage } from "./utils/emitAsset.js";
5
5
  import { imageMetadata } from "./utils/metadata.js";
@@ -8,5 +8,6 @@ export {
8
8
  emitESMImage,
9
9
  getConfiguredImageService,
10
10
  getImage,
11
- imageMetadata
11
+ imageMetadata,
12
+ isLocalService
12
13
  };
@@ -1,14 +1,8 @@
1
1
  import type { StaticBuildOptions } from '../core/build/types.js';
2
2
  import { type ImageService } from './services/service.js';
3
- import type { ImageMetadata, ImageTransform } from './types.js';
3
+ import type { GetImageResult, ImageMetadata, ImageTransform } from './types.js';
4
4
  export declare function isESMImportedImage(src: ImageMetadata | string): src is ImageMetadata;
5
5
  export declare function getConfiguredImageService(): Promise<ImageService>;
6
- interface GetImageResult {
7
- rawOptions: ImageTransform;
8
- options: ImageTransform;
9
- src: string;
10
- attributes: Record<string, any>;
11
- }
12
6
  /**
13
7
  * Get an optimized image and the necessary attributes to render it.
14
8
  *
@@ -18,7 +12,7 @@ interface GetImageResult {
18
12
  * import { getImage } from 'astro:assets';
19
13
  * import originalImage from '../assets/image.png';
20
14
  *
21
- * const optimizedImage = await getImage({src: originalImage, width: 1280 })
15
+ * const optimizedImage = await getImage({src: originalImage, width: 1280 });
22
16
  * ---
23
17
  * <img src={optimizedImage.src} {...optimizedImage.attributes} />
24
18
  * ```
@@ -26,7 +20,13 @@ interface GetImageResult {
26
20
  * This is functionally equivalent to using the `<Image />` component, as the component calls this function internally.
27
21
  */
28
22
  export declare function getImage(options: ImageTransform): Promise<GetImageResult>;
29
- export declare function getStaticImageList(): Iterable<[ImageTransform, string]>;
23
+ export declare function getStaticImageList(): Iterable<[
24
+ string,
25
+ {
26
+ path: string;
27
+ options: ImageTransform;
28
+ }
29
+ ]>;
30
30
  interface GenerationData {
31
31
  weight: {
32
32
  before: number;
@@ -7,7 +7,8 @@ function isESMImportedImage(src) {
7
7
  return typeof src === "object";
8
8
  }
9
9
  async function getConfiguredImageService() {
10
- if (!globalThis.astroAsset.imageService) {
10
+ var _a;
11
+ if (!((_a = globalThis == null ? void 0 : globalThis.astroAsset) == null ? void 0 : _a.imageService)) {
11
12
  const { default: service } = await import(
12
13
  // @ts-expect-error
13
14
  "virtual:image-service"
@@ -16,12 +17,20 @@ async function getConfiguredImageService() {
16
17
  error.cause = e;
17
18
  throw error;
18
19
  });
20
+ if (!globalThis.astroAsset)
21
+ globalThis.astroAsset = {};
19
22
  globalThis.astroAsset.imageService = service;
20
23
  return service;
21
24
  }
22
25
  return globalThis.astroAsset.imageService;
23
26
  }
24
27
  async function getImage(options) {
28
+ if (!options || typeof options !== "object") {
29
+ throw new AstroError({
30
+ ...AstroErrorData.ExpectedImageOptions,
31
+ message: AstroErrorData.ExpectedImageOptions.message(JSON.stringify(options))
32
+ });
33
+ }
25
34
  const service = await getConfiguredImageService();
26
35
  const validatedOptions = service.validateOptions ? service.validateOptions(options) : options;
27
36
  let imageURL = service.getURL(validatedOptions);
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import type { ImageTransform, OutputFormat } from '../types.js';
2
+ import type { ImageOutputFormat, ImageTransform } from '../types.js';
3
3
  export type ImageService = LocalImageService | ExternalImageService;
4
4
  export declare function isLocalService(service: ImageService | undefined): service is LocalImageService;
5
5
  export declare function parseQuality(quality: string): string | number;
@@ -48,7 +48,7 @@ export interface LocalImageService extends SharedServiceProps {
48
48
  */
49
49
  transform: (inputBuffer: Buffer, transform: LocalImageTransform) => Promise<{
50
50
  data: Buffer;
51
- format: OutputFormat;
51
+ format: ImageOutputFormat;
52
52
  }>;
53
53
  }
54
54
  export type BaseServiceTransform = {
@@ -16,6 +16,12 @@ function parseQuality(quality) {
16
16
  }
17
17
  const baseService = {
18
18
  validateOptions(options) {
19
+ if (!options.src || typeof options.src !== "string" && typeof options.src !== "object") {
20
+ throw new AstroError({
21
+ ...AstroErrorData.ExpectedImage,
22
+ message: AstroErrorData.ExpectedImage.message(JSON.stringify(options.src))
23
+ });
24
+ }
19
25
  if (!isESMImportedImage(options.src)) {
20
26
  let missingDimension;
21
27
  if (!options.width && !options.height) {
@@ -1 +1,2 @@
1
1
  export declare function copyWasmFiles(dir: URL): Promise<void>;
2
+ export declare function deleteWasmFiles(dir: URL): Promise<void>;
@@ -3,22 +3,35 @@ import path from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  async function copyWasmFiles(dir) {
5
5
  const src = new URL("./", import.meta.url);
6
- await copyDir(fileURLToPath(src), fileURLToPath(dir));
6
+ const fileList = await listFiles(fileURLToPath(src), fileURLToPath(dir));
7
+ for (let file of fileList) {
8
+ await fs.mkdir(path.dirname(file.dest), { recursive: true });
9
+ await fs.copyFile(file.src, file.dest);
10
+ }
7
11
  }
8
- async function copyDir(src, dest) {
12
+ async function deleteWasmFiles(dir) {
13
+ const src = new URL("./", import.meta.url);
14
+ const fileList = await listFiles(fileURLToPath(src), fileURLToPath(dir));
15
+ for (let file of fileList) {
16
+ await fs.rm(file.dest);
17
+ }
18
+ }
19
+ async function listFiles(src, dest) {
9
20
  const itemNames = await fs.readdir(src);
21
+ const copiedFiles = [];
10
22
  await Promise.all(itemNames.map(async (srcName) => {
11
23
  const srcPath = path.join(src, srcName);
12
24
  const destPath = path.join(dest, srcName);
13
25
  const s = await fs.stat(srcPath);
14
26
  if (s.isFile() && /.wasm$/.test(srcPath)) {
15
- await fs.mkdir(path.dirname(destPath), { recursive: true });
16
- await fs.copyFile(srcPath, destPath);
27
+ copiedFiles.push({ src: srcPath, dest: destPath });
17
28
  } else if (s.isDirectory()) {
18
- await copyDir(srcPath, destPath);
29
+ copiedFiles.push(...await listFiles(srcPath, destPath));
19
30
  }
20
31
  }));
32
+ return copiedFiles;
21
33
  }
22
34
  export {
23
- copyWasmFiles
35
+ copyWasmFiles,
36
+ deleteWasmFiles
24
37
  };
@@ -1,4 +1,4 @@
1
1
  /// <reference types="node" />
2
- import type { OutputFormat } from '../../../types.js';
2
+ import type { ImageOutputFormat } from '../../../types.js';
3
3
  import type { Operation } from './image.js';
4
- export declare function processBuffer(buffer: Buffer, operations: Operation[], encoding: OutputFormat, quality?: number): Promise<Uint8Array>;
4
+ export declare function processBuffer(buffer: Buffer, operations: Operation[], encoding: ImageOutputFormat, quality?: number): Promise<Uint8Array>;
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import type { OutputFormat } from '../../../types.js';
2
+ import type { ImageOutputFormat } from '../../../types.js';
3
3
  type RotateOperation = {
4
4
  type: 'rotate';
5
5
  numRotations: number;
@@ -10,5 +10,5 @@ type ResizeOperation = {
10
10
  height?: number;
11
11
  };
12
12
  export type Operation = RotateOperation | ResizeOperation;
13
- export declare function processBuffer(buffer: Buffer, operations: Operation[], encoding: OutputFormat, quality?: number): Promise<Uint8Array>;
13
+ export declare function processBuffer(buffer: Buffer, operations: Operation[], encoding: ImageOutputFormat, quality?: number): Promise<Uint8Array>;
14
14
  export {};
@@ -2,13 +2,16 @@ import type { VALID_INPUT_FORMATS, VALID_OUTPUT_FORMATS } from './consts.js';
2
2
  import type { ImageService } from './services/service.js';
3
3
  export type ImageQualityPreset = 'low' | 'mid' | 'high' | 'max' | (string & {});
4
4
  export type ImageQuality = ImageQualityPreset | number;
5
- export type InputFormat = (typeof VALID_INPUT_FORMATS)[number] | 'svg';
6
- export type OutputFormat = (typeof VALID_OUTPUT_FORMATS)[number] | (string & {});
5
+ export type ImageInputFormat = (typeof VALID_INPUT_FORMATS)[number] | 'svg';
6
+ export type ImageOutputFormat = (typeof VALID_OUTPUT_FORMATS)[number] | (string & {});
7
7
  declare global {
8
8
  var astroAsset: {
9
9
  imageService?: ImageService;
10
10
  addStaticImage?: ((options: ImageTransform) => string) | undefined;
11
- staticImages?: Map<ImageTransform, string>;
11
+ staticImages?: Map<string, {
12
+ path: string;
13
+ options: ImageTransform;
14
+ }>;
12
15
  };
13
16
  }
14
17
  /**
@@ -18,19 +21,25 @@ export interface ImageMetadata {
18
21
  src: string;
19
22
  width: number;
20
23
  height: number;
21
- format: InputFormat;
24
+ format: ImageInputFormat;
22
25
  }
23
26
  /**
24
27
  * Options accepted by the image transformation service.
25
28
  */
26
29
  export type ImageTransform = {
27
30
  src: ImageMetadata | string;
28
- width?: number;
29
- height?: number;
30
- quality?: ImageQuality;
31
- format?: OutputFormat;
31
+ width?: number | undefined;
32
+ height?: number | undefined;
33
+ quality?: ImageQuality | undefined;
34
+ format?: ImageOutputFormat | undefined;
32
35
  [key: string]: any;
33
36
  };
37
+ export interface GetImageResult {
38
+ rawOptions: ImageTransform;
39
+ options: ImageTransform;
40
+ src: string;
41
+ attributes: Record<string, any>;
42
+ }
34
43
  type WithRequired<T, K extends keyof T> = T & {
35
44
  [P in K]-?: T[P];
36
45
  };
@@ -88,11 +97,11 @@ export type LocalImageProps<T> = ImageSharedProps<T> & {
88
97
  * <Image src={...} format="avif" alt="..." />
89
98
  * ```
90
99
  */
91
- format?: OutputFormat;
100
+ format?: ImageOutputFormat;
92
101
  /**
93
102
  * Desired quality for the image. Value can either be a preset such as `low` or `high`, or a numeric value from 0 to 100.
94
103
  *
95
- * The perceptual quality of the output image is loader-specific.
104
+ * The perceptual quality of the output image is service-specific.
96
105
  * For instance, a certain service might decide that `high` results in a very beautiful image, but another could choose for it to be at best passable.
97
106
  *
98
107
  * **Example**:
@@ -1,3 +1,4 @@
1
1
  import type { AstroSettings } from '../../@types/astro';
2
- export declare function emitESMImage(id: string, watchMode: boolean, fileEmitter: any, settings: Pick<AstroSettings, 'config'>): Promise<import("./metadata.js").Metadata | undefined>;
2
+ import { type Metadata } from './metadata.js';
3
+ export declare function emitESMImage(id: string | undefined, watchMode: boolean, fileEmitter: any, settings: Pick<AstroSettings, 'config'>): Promise<Metadata | undefined>;
3
4
  export declare function emoji(char: string, fallback: string): string;
@@ -4,10 +4,13 @@ import { fileURLToPath, pathToFileURL } from "node:url";
4
4
  import slash from "slash";
5
5
  import { imageMetadata } from "./metadata.js";
6
6
  async function emitESMImage(id, watchMode, fileEmitter, settings) {
7
+ if (!id) {
8
+ return void 0;
9
+ }
7
10
  const url = pathToFileURL(id);
8
11
  const meta = await imageMetadata(url);
9
12
  if (!meta) {
10
- return;
13
+ return void 0;
11
14
  }
12
15
  if (!watchMode) {
13
16
  const pathname = decodeURI(url.pathname);
@@ -1,2 +1,3 @@
1
1
  import type { ImageTransform } from '../types.js';
2
- export declare function propsToFilename(transform: ImageTransform, imageService: string): string;
2
+ export declare function propsToFilename(transform: ImageTransform, hash: string): string;
3
+ export declare function hashTransform(transform: ImageTransform, imageService: string): string;
@@ -2,18 +2,22 @@ import { basename, extname } from "path";
2
2
  import { removeQueryString } from "../../core/path.js";
3
3
  import { shorthash } from "../../runtime/server/shorthash.js";
4
4
  import { isESMImportedImage } from "../internal.js";
5
- function propsToFilename(transform, imageService) {
5
+ function propsToFilename(transform, hash) {
6
6
  if (!isESMImportedImage(transform.src)) {
7
7
  return transform.src;
8
8
  }
9
9
  let filename = removeQueryString(transform.src.src);
10
10
  const ext = extname(filename);
11
11
  filename = basename(filename, ext);
12
+ const outputExt = transform.format ? `.${transform.format}` : ext;
13
+ return `/${filename}_${hash}${outputExt}`;
14
+ }
15
+ function hashTransform(transform, imageService) {
12
16
  const { alt, ...rest } = transform;
13
17
  const hashFields = { ...rest, imageService };
14
- const outputExt = transform.format ? `.${transform.format}` : ext;
15
- return `/${filename}_${shorthash(JSON.stringify(hashFields))}${outputExt}`;
18
+ return shorthash(JSON.stringify(hashFields));
16
19
  }
17
20
  export {
21
+ hashTransform,
18
22
  propsToFilename
19
23
  };
@@ -1,12 +1,12 @@
1
1
  import { bold } from "kleur/colors";
2
2
  import MagicString from "magic-string";
3
- import mime from "mime";
3
+ import mime from "mime/lite.js";
4
4
  import fs from "node:fs/promises";
5
5
  import { Readable } from "node:stream";
6
6
  import { fileURLToPath } from "node:url";
7
7
  import { normalizePath } from "vite";
8
8
  import { error } from "../core/logger/core.js";
9
- import { joinPaths, prependForwardSlash } from "../core/path.js";
9
+ import { appendForwardSlash, joinPaths, prependForwardSlash } from "../core/path.js";
10
10
  import { VIRTUAL_MODULE_ID, VIRTUAL_SERVICE_ID } from "./consts.js";
11
11
  import { isESMImportedImage } from "./internal.js";
12
12
  import { isLocalService } from "./services/service.js";
@@ -14,7 +14,7 @@ import { copyWasmFiles } from "./services/vendor/squoosh/copy-wasm.js";
14
14
  import { emitESMImage } from "./utils/emitAsset.js";
15
15
  import { imageMetadata } from "./utils/metadata.js";
16
16
  import { getOrigQueryParams } from "./utils/queryParams.js";
17
- import { propsToFilename } from "./utils/transformToPath.js";
17
+ import { hashTransform, propsToFilename } from "./utils/transformToPath.js";
18
18
  const resolvedVirtualModuleId = "\0" + VIRTUAL_MODULE_ID;
19
19
  function assets({
20
20
  settings,
@@ -69,7 +69,7 @@ function assets({
69
69
  load(id) {
70
70
  if (id === resolvedVirtualModuleId) {
71
71
  return `
72
- export { getImage, getConfiguredImageService } from "astro/assets";
72
+ export { getImage, getConfiguredImageService, isLocalService } from "astro/assets";
73
73
  export { default as Image } from "astro/components/Image.astro";
74
74
  `;
75
75
  }
@@ -107,10 +107,7 @@ function assets({
107
107
  data = result.data;
108
108
  format = result.format;
109
109
  }
110
- res.setHeader(
111
- "Content-Type",
112
- mime.getType(fileURLToPath(filePathURL)) || `image/${format}`
113
- );
110
+ res.setHeader("Content-Type", mime.getType(format) ?? `image/${format}`);
114
111
  res.setHeader("Cache-Control", "max-age=360000");
115
112
  const stream = Readable.from(data);
116
113
  return stream.pipe(res);
@@ -126,30 +123,34 @@ function assets({
126
123
  if (!globalThis.astroAsset.staticImages) {
127
124
  globalThis.astroAsset.staticImages = /* @__PURE__ */ new Map();
128
125
  }
126
+ const hash = hashTransform(options, settings.config.image.service);
129
127
  let filePath;
130
- if (globalThis.astroAsset.staticImages.has(options)) {
131
- filePath = globalThis.astroAsset.staticImages.get(options);
128
+ if (globalThis.astroAsset.staticImages.has(hash)) {
129
+ filePath = globalThis.astroAsset.staticImages.get(hash).path;
132
130
  } else {
133
131
  if (!isESMImportedImage(options.src)) {
134
132
  return options.src;
135
133
  }
136
134
  filePath = prependForwardSlash(
137
- joinPaths(
138
- settings.config.build.assets,
139
- propsToFilename(options, settings.config.image.service)
140
- )
135
+ joinPaths(settings.config.build.assets, propsToFilename(options, hash))
141
136
  );
142
- globalThis.astroAsset.staticImages.set(options, filePath);
137
+ globalThis.astroAsset.staticImages.set(hash, { path: filePath, options });
138
+ }
139
+ if (settings.config.build.assetsPrefix) {
140
+ return joinPaths(settings.config.build.assetsPrefix, filePath);
141
+ } else {
142
+ return prependForwardSlash(joinPaths(settings.config.base, filePath));
143
143
  }
144
- return prependForwardSlash(joinPaths(settings.config.base, filePath));
145
144
  };
146
145
  },
147
146
  async buildEnd() {
148
147
  if (mode != "build") {
149
148
  return;
150
149
  }
151
- const dir = settings.config.output === "server" ? settings.config.build.server : settings.config.outDir;
152
- await copyWasmFiles(new URL("./chunks", dir));
150
+ if (settings.config.image.service === "astro/assets/services/squoosh") {
151
+ const dir = settings.config.output === "server" ? settings.config.build.server : settings.config.outDir;
152
+ await copyWasmFiles(new URL("./chunks", dir));
153
+ }
153
154
  },
154
155
  // In build, rewrite paths to ESM imported images in code to their final location
155
156
  async renderChunk(code) {
@@ -160,7 +161,8 @@ function assets({
160
161
  s = s || (s = new MagicString(code));
161
162
  const [full, hash, postfix = ""] = match;
162
163
  const file = this.getFileName(hash);
163
- const outputFilepath = normalizePath(resolvedConfig.base + file + postfix);
164
+ const prefix = settings.config.build.assetsPrefix ? appendForwardSlash(settings.config.build.assetsPrefix) : resolvedConfig.base;
165
+ const outputFilepath = prefix + normalizePath(file + postfix);
164
166
  s.overwrite(match.index, match.index + full.length, outputFilepath);
165
167
  }
166
168
  if (s) {
package/dist/cli/index.js CHANGED
@@ -16,7 +16,6 @@ import { enableVerboseLogging, nodeLogDestination } from "../core/logger/node.js
16
16
  import { formatConfigErrorMessage, formatErrorMessage, printHelp } from "../core/messages.js";
17
17
  import * as event from "../events/index.js";
18
18
  import { eventConfigError, eventError, telemetry } from "../events/index.js";
19
- import { check } from "./check/index.js";
20
19
  import { openInBrowser } from "./open.js";
21
20
  function printAstroHelp() {
22
21
  printHelp({
@@ -174,6 +173,7 @@ async function runCommand(cmd, flags) {
174
173
  });
175
174
  }
176
175
  case "check": {
176
+ const { check } = await import("./check/index.js");
177
177
  const checkServer = await check(settings, { flags, logging });
178
178
  if (checkServer) {
179
179
  if (checkServer.isWatchMode) {
@@ -1,8 +1,4 @@
1
+ import type { PluginContext } from 'rollup';
1
2
  import { z } from 'zod';
2
- import { type Metadata } from '../assets/utils/metadata.js';
3
- export declare function createImage(options: {
4
- assetsDir: string;
5
- relAssetsDir: string;
6
- }): () => z.ZodEffects<z.ZodString, (Metadata & {
7
- __astro_asset: true;
8
- }) | undefined, string>;
3
+ import type { AstroSettings } from '../@types/astro.js';
4
+ export declare function createImage(settings: AstroSettings, pluginContext: PluginContext, entryFilePath: string): () => z.ZodEffects<z.ZodString, import("../assets/utils/metadata.js").Metadata, string>;
@@ -1,24 +1,28 @@
1
- import { pathToFileURL } from "url";
2
1
  import { z } from "zod";
3
- import { imageMetadata } from "../assets/utils/metadata.js";
4
- function createImage(options) {
2
+ import { emitESMImage } from "../assets/index.js";
3
+ function createImage(settings, pluginContext, entryFilePath) {
5
4
  return () => {
6
- if (options.assetsDir === "undefined") {
7
- throw new Error("Enable `experimental.assets` in your Astro config to use image()");
8
- }
9
- return z.string({ description: "__image" }).transform(async (imagePath) => {
10
- return await getImageMetadata(pathToFileURL(imagePath));
5
+ return z.string().transform(async (imagePath, ctx) => {
6
+ var _a;
7
+ const resolvedFilePath = (_a = await pluginContext.resolve(imagePath, entryFilePath)) == null ? void 0 : _a.id;
8
+ const metadata = await emitESMImage(
9
+ resolvedFilePath,
10
+ pluginContext.meta.watchMode,
11
+ pluginContext.emitFile,
12
+ settings
13
+ );
14
+ if (!metadata) {
15
+ ctx.addIssue({
16
+ code: "custom",
17
+ message: `Image ${imagePath} does not exist. Is the path correct?`,
18
+ fatal: true
19
+ });
20
+ return z.NEVER;
21
+ }
22
+ return metadata;
11
23
  });
12
24
  };
13
25
  }
14
- async function getImageMetadata(imagePath) {
15
- const meta = await imageMetadata(imagePath);
16
- if (!meta) {
17
- return void 0;
18
- }
19
- delete meta.orientation;
20
- return { ...meta, __astro_asset: true };
21
- }
22
26
  export {
23
27
  createImage
24
28
  };
@@ -1,3 +1,4 @@
1
1
  export function defineCollection(config: any): any;
2
+ export function image(): never;
2
3
  export const getCollection: any;
3
4
  export const getEntryBySlug: any;
@@ -1,7 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import matter from 'gray-matter';
3
3
  import fsMod from 'node:fs';
4
- import type { EmitFile, PluginContext } from 'rollup';
4
+ import type { PluginContext } from 'rollup';
5
5
  import { type ViteDevServer } from 'vite';
6
6
  import { z } from 'zod';
7
7
  import type { AstroConfig, AstroSettings } from '../@types/astro.js';
@@ -47,17 +47,13 @@ export type EntryInfo = {
47
47
  export declare const msg: {
48
48
  collectionConfigMissing: (collection: string) => string;
49
49
  };
50
- /**
51
- * Mutate (arf) the entryData to reroute assets to their final paths
52
- */
53
- export declare function patchAssets(frontmatterEntry: Record<string, any>, watchMode: boolean, fileEmitter: EmitFile, astroSettings: AstroSettings): Promise<void>;
54
50
  export declare function getEntrySlug({ id, collection, slug, unvalidatedSlug, }: EntryInfo & {
55
51
  unvalidatedSlug?: unknown;
56
52
  }): string;
57
53
  export declare function getEntryData(entry: EntryInfo & {
58
54
  unvalidatedData: Record<string, unknown>;
59
55
  _internal: EntryInternal;
60
- }, collectionConfig: CollectionConfig, resolver: (idToResolve: string) => ReturnType<PluginContext['resolve']>): Promise<{
56
+ }, collectionConfig: CollectionConfig, pluginContext: PluginContext, settings: AstroSettings): Promise<{
61
57
  [x: string]: unknown;
62
58
  }>;
63
59
  export declare function getContentEntryExts(settings: Pick<AstroSettings, 'contentEntryTypes'>): string[];