astro 3.3.4 → 3.4.1

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 (53) hide show
  1. package/components/viewtransitions.css +13 -0
  2. package/dist/@types/astro.d.ts +48 -1
  3. package/dist/assets/build/generate.d.ts +20 -16
  4. package/dist/assets/build/generate.js +125 -72
  5. package/dist/assets/types.d.ts +5 -4
  6. package/dist/assets/vite-plugin-assets.js +15 -7
  7. package/dist/cli/add/babel.d.ts +1 -1
  8. package/dist/content/utils.d.ts +9 -9
  9. package/dist/core/build/generate.js +21 -33
  10. package/dist/core/config/schema.d.ts +224 -187
  11. package/dist/core/config/schema.js +5 -2
  12. package/dist/core/config/settings.js +1 -0
  13. package/dist/core/constants.js +1 -1
  14. package/dist/core/create-vite.js +3 -1
  15. package/dist/core/dev/dev.js +1 -1
  16. package/dist/core/errors/errors-data.d.ts +2 -3
  17. package/dist/core/errors/errors-data.js +2 -2
  18. package/dist/core/messages.js +2 -2
  19. package/dist/core/render/core.js +1 -0
  20. package/dist/core/render/result.d.ts +1 -0
  21. package/dist/core/render/result.js +1 -0
  22. package/dist/integrations/index.js +3 -10
  23. package/dist/runtime/client/dev-overlay/entrypoint.d.ts +1 -0
  24. package/dist/runtime/client/dev-overlay/entrypoint.js +66 -0
  25. package/dist/runtime/client/dev-overlay/overlay.d.ts +33 -0
  26. package/dist/runtime/client/dev-overlay/overlay.js +415 -0
  27. package/dist/runtime/client/dev-overlay/plugins/astro.d.ts +7 -0
  28. package/dist/runtime/client/dev-overlay/plugins/astro.js +66 -0
  29. package/dist/runtime/client/dev-overlay/plugins/audit.d.ts +7 -0
  30. package/dist/runtime/client/dev-overlay/plugins/audit.js +85 -0
  31. package/dist/runtime/client/dev-overlay/plugins/utils/highlight.d.ts +5 -0
  32. package/dist/runtime/client/dev-overlay/plugins/utils/highlight.js +44 -0
  33. package/dist/runtime/client/dev-overlay/plugins/xray.d.ts +7 -0
  34. package/dist/runtime/client/dev-overlay/plugins/xray.js +82 -0
  35. package/dist/runtime/client/dev-overlay/ui-library/card.d.ts +9 -0
  36. package/dist/runtime/client/dev-overlay/ui-library/card.js +67 -0
  37. package/dist/runtime/client/dev-overlay/ui-library/highlight.d.ts +7 -0
  38. package/dist/runtime/client/dev-overlay/ui-library/highlight.js +60 -0
  39. package/dist/runtime/client/dev-overlay/ui-library/icons.d.ts +10 -0
  40. package/dist/runtime/client/dev-overlay/ui-library/icons.js +21 -0
  41. package/dist/runtime/client/dev-overlay/ui-library/tooltip.d.ts +16 -0
  42. package/dist/runtime/client/dev-overlay/ui-library/tooltip.js +137 -0
  43. package/dist/runtime/client/dev-overlay/ui-library/window.d.ts +9 -0
  44. package/dist/runtime/client/dev-overlay/ui-library/window.js +70 -0
  45. package/dist/runtime/server/render/astro/render.js +2 -2
  46. package/dist/runtime/server/render/common.js +2 -2
  47. package/dist/runtime/server/render/component.js +1 -1
  48. package/dist/transitions/router.js +8 -6
  49. package/dist/type-utils.d.ts +1 -0
  50. package/dist/vite-plugin-astro-server/route.js +17 -1
  51. package/dist/vite-plugin-dev-overlay/vite-plugin-dev-overlay.d.ts +3 -0
  52. package/dist/vite-plugin-dev-overlay/vite-plugin-dev-overlay.js +24 -0
  53. package/package.json +4 -2
@@ -54,3 +54,16 @@
54
54
  animation: none !important;
55
55
  }
56
56
  }
57
+
58
+ /* Route announcer */
59
+ .astro-route-announcer {
60
+ position: absolute;
61
+ left: 0;
62
+ top: 0;
63
+ clip: rect(0 0 0 0);
64
+ clip-path: inset(50%);
65
+ overflow: hidden;
66
+ white-space: nowrap;
67
+ width: 1px;
68
+ height: 1px;
69
+ }
@@ -16,6 +16,11 @@ import type { TSConfig } from '../core/config/tsconfig.js';
16
16
  import type { AstroCookies } from '../core/cookies/index.js';
17
17
  import type { ResponseWithEncoding } from '../core/endpoint/index.js';
18
18
  import type { AstroIntegrationLogger, Logger, LoggerLevel } from '../core/logger/core.js';
19
+ import type { AstroDevOverlay, DevOverlayCanvas } from '../runtime/client/dev-overlay/overlay.js';
20
+ import type { DevOverlayHighlight } from '../runtime/client/dev-overlay/ui-library/highlight.js';
21
+ import type { Icon } from '../runtime/client/dev-overlay/ui-library/icons.js';
22
+ import type { DevOverlayTooltip } from '../runtime/client/dev-overlay/ui-library/tooltip.js';
23
+ import type { DevOverlayWindow } from '../runtime/client/dev-overlay/ui-library/window.js';
19
24
  import type { AstroComponentFactory, AstroComponentInstance } from '../runtime/server/index.js';
20
25
  import type { OmitIndexSignature, Simplify } from '../type-utils.js';
21
26
  import type { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './../core/constants.js';
@@ -166,7 +171,7 @@ export interface AstroGlobal<Props extends Record<string, any> = Record<string,
166
171
  * }
167
172
  * ```
168
173
  *
169
- * [Astro reference](https://docs.astro.build/en/guides/server-side-rendering/#astroredirect)
174
+ * [Astro reference](https://docs.astro.build/en/guides/server-side-rendering/)
170
175
  */
171
176
  redirect: AstroSharedContext['redirect'];
172
177
  /**
@@ -1252,6 +1257,24 @@ export interface AstroUserConfig {
1252
1257
  * ```
1253
1258
  */
1254
1259
  optimizeHoistedScript?: boolean;
1260
+ /**
1261
+ * @docs
1262
+ * @name experimental.devOverlay
1263
+ * @type {boolean}
1264
+ * @default `false`
1265
+ * @version 3.4.0
1266
+ * @description
1267
+ * Enable a dev overlay in development mode. This overlay allows you to inspect your page islands, see helpful audits on performance and accessibility, and more.
1268
+ *
1269
+ * ```js
1270
+ * {
1271
+ * experimental: {
1272
+ * devOverlay: true,
1273
+ * },
1274
+ * }
1275
+ * ```
1276
+ */
1277
+ devOverlay?: boolean;
1255
1278
  };
1256
1279
  }
1257
1280
  /**
@@ -1402,6 +1425,7 @@ export interface AstroSettings {
1402
1425
  * Map of directive name (e.g. `load`) to the directive script code
1403
1426
  */
1404
1427
  clientDirectives: Map<string, string>;
1428
+ devOverlayPlugins: string[];
1405
1429
  tsConfig: TSConfig | undefined;
1406
1430
  tsConfigPath: string | undefined;
1407
1431
  watchFiles: string[];
@@ -1412,6 +1436,7 @@ export type AsyncRendererComponentFn<U> = (Component: any, props: any, slots: Re
1412
1436
  export interface ComponentInstance {
1413
1437
  default: AstroComponentFactory;
1414
1438
  css?: string[];
1439
+ partial?: boolean;
1415
1440
  prerender?: boolean;
1416
1441
  /**
1417
1442
  * Only used for logging if deprecated drafts feature is used
@@ -1834,6 +1859,7 @@ export interface AstroIntegration {
1834
1859
  injectScript: (stage: InjectedScriptStage, content: string) => void;
1835
1860
  injectRoute: (injectRoute: InjectedRoute) => void;
1836
1861
  addClientDirective: (directive: ClientDirectiveConfig) => void;
1862
+ addDevOverlayPlugin: (entrypoint: string) => void;
1837
1863
  logger: AstroIntegrationLogger;
1838
1864
  }) => void | Promise<void>;
1839
1865
  'astro:config:done'?: (options: {
@@ -1971,6 +1997,7 @@ export interface SSRResult {
1971
1997
  */
1972
1998
  clientDirectives: Map<string, string>;
1973
1999
  compressHTML: boolean;
2000
+ partial: boolean;
1974
2001
  /**
1975
2002
  * Only used for logging
1976
2003
  */
@@ -2026,3 +2053,23 @@ export interface ClientDirectiveConfig {
2026
2053
  name: string;
2027
2054
  entrypoint: string;
2028
2055
  }
2056
+ export interface DevOverlayPlugin {
2057
+ id: string;
2058
+ name: string;
2059
+ icon: Icon;
2060
+ init?(canvas: ShadowRoot, eventTarget: EventTarget): void | Promise<void>;
2061
+ }
2062
+ export type DevOverlayMetadata = Window & typeof globalThis & {
2063
+ __astro_dev_overlay__: {
2064
+ root: string;
2065
+ };
2066
+ };
2067
+ declare global {
2068
+ interface HTMLElementTagNameMap {
2069
+ 'astro-dev-overlay': AstroDevOverlay;
2070
+ 'astro-dev-overlay-window': DevOverlayWindow;
2071
+ 'astro-dev-overlay-plugin-canvas': DevOverlayCanvas;
2072
+ 'astro-dev-overlay-tooltip': DevOverlayTooltip;
2073
+ 'astro-dev-overlay-highlight': DevOverlayHighlight;
2074
+ }
2075
+ }
@@ -1,19 +1,23 @@
1
+ import PQueue from 'p-queue';
2
+ import type { AstroConfig } from '../../@types/astro.js';
1
3
  import type { BuildPipeline } from '../../core/build/buildPipeline.js';
2
- import type { ImageTransform } from '../types.js';
3
- interface GenerationDataUncached {
4
- cached: false;
5
- weight: {
6
- before: number;
7
- after: number;
4
+ import type { Logger } from '../../core/logger/core.js';
5
+ import type { MapValue } from '../../type-utils.js';
6
+ import type { AssetsGlobalStaticImagesList } from '../types.js';
7
+ type AssetEnv = {
8
+ logger: Logger;
9
+ count: {
10
+ total: number;
11
+ current: number;
8
12
  };
9
- }
10
- interface GenerationDataCached {
11
- cached: true;
12
- }
13
- type GenerationData = GenerationDataUncached | GenerationDataCached;
14
- export declare function generateImage(pipeline: BuildPipeline, options: ImageTransform, filepath: string): Promise<GenerationData | undefined>;
15
- export declare function getStaticImageList(): Map<string, {
16
- path: string;
17
- options: ImageTransform;
18
- }>;
13
+ useCache: boolean;
14
+ assetsCacheDir: URL;
15
+ serverRoot: URL;
16
+ clientRoot: URL;
17
+ imageConfig: AstroConfig['image'];
18
+ assetsFolder: AstroConfig['build']['assets'];
19
+ };
20
+ export declare function prepareAssetsGenerationEnv(pipeline: BuildPipeline, totalCount: number): Promise<AssetEnv>;
21
+ export declare function generateImagesForPath(originalFilePath: string, transforms: MapValue<AssetsGlobalStaticImagesList>, env: AssetEnv, queue: PQueue): Promise<void>;
22
+ export declare function getStaticImageList(): AssetsGlobalStaticImagesList;
19
23
  export {};
@@ -1,15 +1,19 @@
1
+ import { dim, green } from "kleur/colors";
1
2
  import fs, { readFileSync } from "node:fs";
2
3
  import { basename, join } from "node:path/posix";
4
+ import PQueue from "p-queue";
3
5
  import { getOutDirWithinCwd } from "../../core/build/common.js";
4
- import { prependForwardSlash } from "../../core/path.js";
6
+ import { getTimeStat } from "../../core/build/util.js";
7
+ import { isRemotePath, prependForwardSlash } from "../../core/path.js";
5
8
  import { isServerLikeOutput } from "../../prerender/utils.js";
6
9
  import { getConfiguredImageService, isESMImportedImage } from "../internal.js";
7
10
  import { loadRemoteImage } from "./remote.js";
8
- async function generateImage(pipeline, options, filepath) {
11
+ async function prepareAssetsGenerationEnv(pipeline, totalCount) {
9
12
  const config = pipeline.getConfig();
10
13
  const logger = pipeline.getLogger();
11
14
  let useCache = true;
12
15
  const assetsCacheDir = new URL("assets/", config.cacheDir);
16
+ const count = { total: totalCount, current: 1 };
13
17
  try {
14
18
  await fs.promises.mkdir(assetsCacheDir, { recursive: true });
15
19
  } catch (err) {
@@ -27,82 +31,115 @@ async function generateImage(pipeline, options, filepath) {
27
31
  serverRoot = getOutDirWithinCwd(config.outDir);
28
32
  clientRoot = config.outDir;
29
33
  }
30
- const isLocalImage = isESMImportedImage(options.src);
31
- const finalFileURL = new URL("." + filepath, clientRoot);
32
- const finalFolderURL = new URL("./", finalFileURL);
33
- const cacheFile = basename(filepath) + (isLocalImage ? "" : ".json");
34
- const cachedFileURL = new URL(cacheFile, assetsCacheDir);
35
- await fs.promises.mkdir(finalFolderURL, { recursive: true });
36
- try {
37
- if (isLocalImage) {
38
- await fs.promises.copyFile(cachedFileURL, finalFileURL);
39
- return {
40
- cached: true
41
- };
42
- } else {
43
- const JSONData = JSON.parse(readFileSync(cachedFileURL, "utf-8"));
44
- if (JSONData.expires > Date.now()) {
45
- await fs.promises.writeFile(finalFileURL, Buffer.from(JSONData.data, "base64"));
46
- return {
47
- cached: true
48
- };
49
- }
50
- }
51
- } catch (e) {
52
- if (e.code !== "ENOENT") {
53
- throw new Error(`An error was encountered while reading the cache file. Error: ${e}`);
54
- }
55
- }
56
- const originalImagePath = isLocalImage ? options.src.src : options.src;
57
- let imageData;
58
- let resultData = {
59
- data: void 0,
60
- expires: void 0
34
+ return {
35
+ logger,
36
+ count,
37
+ useCache,
38
+ assetsCacheDir,
39
+ serverRoot,
40
+ clientRoot,
41
+ imageConfig: config.image,
42
+ assetsFolder: config.build.assets
61
43
  };
62
- if (isLocalImage) {
63
- imageData = await fs.promises.readFile(
64
- new URL(
65
- "." + prependForwardSlash(join(config.build.assets, basename(originalImagePath))),
66
- serverRoot
67
- )
44
+ }
45
+ async function generateImagesForPath(originalFilePath, transforms, env, queue) {
46
+ const originalImageData = await loadImage(originalFilePath, env);
47
+ for (const [_, transform] of transforms) {
48
+ queue.add(
49
+ async () => generateImage(originalImageData, transform.finalPath, transform.transform)
68
50
  );
69
- } else {
70
- const remoteImage = await loadRemoteImage(originalImagePath);
71
- resultData.expires = remoteImage.expires;
72
- imageData = remoteImage.data;
73
51
  }
74
- const imageService = await getConfiguredImageService();
75
- resultData.data = (await imageService.transform(imageData, { ...options, src: originalImagePath }, config.image)).data;
76
- try {
77
- if (useCache) {
52
+ async function generateImage(originalImage, filepath, options) {
53
+ const timeStart = performance.now();
54
+ const generationData = await generateImageInternal(originalImage, filepath, options);
55
+ const timeEnd = performance.now();
56
+ const timeChange = getTimeStat(timeStart, timeEnd);
57
+ const timeIncrease = `(+${timeChange})`;
58
+ const statsText = generationData.cached ? `(reused cache entry)` : `(before: ${generationData.weight.before}kB, after: ${generationData.weight.after}kB)`;
59
+ const count = `(${env.count.current}/${env.count.total})`;
60
+ env.logger.info(
61
+ null,
62
+ ` ${green("\u25B6")} ${filepath} ${dim(statsText)} ${dim(timeIncrease)} ${dim(count)}`
63
+ );
64
+ env.count.current++;
65
+ }
66
+ async function generateImageInternal(originalImage, filepath, options) {
67
+ const isLocalImage = isESMImportedImage(options.src);
68
+ const finalFileURL = new URL("." + filepath, env.clientRoot);
69
+ const cacheFile = basename(filepath) + (isLocalImage ? "" : ".json");
70
+ const cachedFileURL = new URL(cacheFile, env.assetsCacheDir);
71
+ try {
78
72
  if (isLocalImage) {
79
- await fs.promises.writeFile(cachedFileURL, resultData.data);
73
+ await fs.promises.copyFile(cachedFileURL, finalFileURL, fs.constants.COPYFILE_FICLONE);
74
+ return {
75
+ cached: true
76
+ };
80
77
  } else {
81
- await fs.promises.writeFile(
82
- cachedFileURL,
83
- JSON.stringify({
84
- data: Buffer.from(resultData.data).toString("base64"),
85
- expires: resultData.expires
86
- })
87
- );
78
+ const JSONData = JSON.parse(readFileSync(cachedFileURL, "utf-8"));
79
+ if (!JSONData.data || !JSONData.expires) {
80
+ await fs.promises.unlink(cachedFileURL);
81
+ throw new Error(
82
+ `Malformed cache entry for ${filepath}, cache will be regenerated for this file.`
83
+ );
84
+ }
85
+ if (JSONData.expires > Date.now()) {
86
+ await fs.promises.writeFile(finalFileURL, Buffer.from(JSONData.data, "base64"));
87
+ return {
88
+ cached: true
89
+ };
90
+ } else {
91
+ await fs.promises.unlink(cachedFileURL);
92
+ }
93
+ }
94
+ } catch (e) {
95
+ if (e.code !== "ENOENT") {
96
+ throw new Error(`An error was encountered while reading the cache file. Error: ${e}`);
88
97
  }
89
98
  }
90
- } catch (e) {
91
- logger.warn(
92
- "astro:assets",
93
- `An error was encountered while creating the cache directory. Proceeding without caching. Error: ${e}`
94
- );
95
- } finally {
96
- await fs.promises.writeFile(finalFileURL, resultData.data);
97
- }
98
- return {
99
- cached: false,
100
- weight: {
101
- // Divide by 1024 to get size in kilobytes
102
- before: Math.trunc(imageData.byteLength / 1024),
103
- after: Math.trunc(Buffer.from(resultData.data).byteLength / 1024)
99
+ const finalFolderURL = new URL("./", finalFileURL);
100
+ await fs.promises.mkdir(finalFolderURL, { recursive: true });
101
+ const originalImagePath = isLocalImage ? options.src.src : options.src;
102
+ let resultData = {
103
+ data: void 0,
104
+ expires: originalImage.expires
105
+ };
106
+ const imageService = await getConfiguredImageService();
107
+ resultData.data = (await imageService.transform(
108
+ originalImage.data,
109
+ { ...options, src: originalImagePath },
110
+ env.imageConfig
111
+ )).data;
112
+ try {
113
+ if (env.useCache) {
114
+ if (isLocalImage) {
115
+ await fs.promises.writeFile(cachedFileURL, resultData.data);
116
+ } else {
117
+ await fs.promises.writeFile(
118
+ cachedFileURL,
119
+ JSON.stringify({
120
+ data: Buffer.from(resultData.data).toString("base64"),
121
+ expires: resultData.expires
122
+ })
123
+ );
124
+ }
125
+ }
126
+ } catch (e) {
127
+ env.logger.warn(
128
+ "astro:assets",
129
+ `An error was encountered while creating the cache directory. Proceeding without caching. Error: ${e}`
130
+ );
131
+ } finally {
132
+ await fs.promises.writeFile(finalFileURL, resultData.data);
104
133
  }
105
- };
134
+ return {
135
+ cached: false,
136
+ weight: {
137
+ // Divide by 1024 to get size in kilobytes
138
+ before: Math.trunc(originalImage.data.byteLength / 1024),
139
+ after: Math.trunc(Buffer.from(resultData.data).byteLength / 1024)
140
+ }
141
+ };
142
+ }
106
143
  }
107
144
  function getStaticImageList() {
108
145
  if (!globalThis?.astroAsset?.staticImages) {
@@ -110,7 +147,23 @@ function getStaticImageList() {
110
147
  }
111
148
  return globalThis.astroAsset.staticImages;
112
149
  }
150
+ async function loadImage(path, env) {
151
+ if (isRemotePath(path)) {
152
+ const remoteImage = await loadRemoteImage(path);
153
+ return {
154
+ data: remoteImage.data,
155
+ expires: remoteImage.expires
156
+ };
157
+ }
158
+ return {
159
+ data: await fs.promises.readFile(
160
+ new URL("." + prependForwardSlash(join(env.assetsFolder, basename(path))), env.serverRoot)
161
+ ),
162
+ expires: 0
163
+ };
164
+ }
113
165
  export {
114
- generateImage,
115
- getStaticImageList
166
+ generateImagesForPath,
167
+ getStaticImageList,
168
+ prepareAssetsGenerationEnv
116
169
  };
@@ -5,14 +5,15 @@ export type ImageQualityPreset = 'low' | 'mid' | 'high' | 'max' | (string & {});
5
5
  export type ImageQuality = ImageQualityPreset | number;
6
6
  export type ImageInputFormat = (typeof VALID_INPUT_FORMATS)[number];
7
7
  export type ImageOutputFormat = (typeof VALID_OUTPUT_FORMATS)[number] | (string & {});
8
+ export type AssetsGlobalStaticImagesList = Map<string, Map<string, {
9
+ finalPath: string;
10
+ transform: ImageTransform;
11
+ }>>;
8
12
  declare global {
9
13
  var astroAsset: {
10
14
  imageService?: ImageService;
11
15
  addStaticImage?: ((options: ImageTransform) => string) | undefined;
12
- staticImages?: Map<string, {
13
- path: string;
14
- options: ImageTransform;
15
- }>;
16
+ staticImages?: AssetsGlobalStaticImagesList;
16
17
  };
17
18
  }
18
19
  /**
@@ -10,6 +10,7 @@ import {
10
10
  } from "../core/path.js";
11
11
  import { isServerLikeOutput } from "../prerender/utils.js";
12
12
  import { VALID_INPUT_FORMATS, VIRTUAL_MODULE_ID, VIRTUAL_SERVICE_ID } from "./consts.js";
13
+ import { isESMImportedImage } from "./internal.js";
13
14
  import { emitESMImage } from "./utils/emitAsset.js";
14
15
  import { hashTransform, propsToFilename } from "./utils/transformToPath.js";
15
16
  const resolvedVirtualModuleId = "\0" + VIRTUAL_MODULE_ID;
@@ -67,20 +68,27 @@ function assets({
67
68
  if (!globalThis.astroAsset.staticImages) {
68
69
  globalThis.astroAsset.staticImages = /* @__PURE__ */ new Map();
69
70
  }
71
+ const originalImagePath = (isESMImportedImage(options.src) ? options.src.src : options.src).replace(settings.config.build.assetsPrefix || "", "");
70
72
  const hash = hashTransform(options, settings.config.image.service.entrypoint);
71
- let filePath;
72
- if (globalThis.astroAsset.staticImages.has(hash)) {
73
- filePath = globalThis.astroAsset.staticImages.get(hash).path;
73
+ let finalFilePath;
74
+ let transformsForPath = globalThis.astroAsset.staticImages.get(originalImagePath);
75
+ let transformForHash = transformsForPath?.get(hash);
76
+ if (transformsForPath && transformForHash) {
77
+ finalFilePath = transformForHash.finalPath;
74
78
  } else {
75
- filePath = prependForwardSlash(
79
+ finalFilePath = prependForwardSlash(
76
80
  joinPaths(settings.config.build.assets, propsToFilename(options, hash))
77
81
  );
78
- globalThis.astroAsset.staticImages.set(hash, { path: filePath, options });
82
+ if (!transformsForPath) {
83
+ globalThis.astroAsset.staticImages.set(originalImagePath, /* @__PURE__ */ new Map());
84
+ transformsForPath = globalThis.astroAsset.staticImages.get(originalImagePath);
85
+ }
86
+ transformsForPath.set(hash, { finalPath: finalFilePath, transform: options });
79
87
  }
80
88
  if (settings.config.build.assetsPrefix) {
81
- return joinPaths(settings.config.build.assetsPrefix, filePath);
89
+ return joinPaths(settings.config.build.assetsPrefix, finalFilePath);
82
90
  } else {
83
- return prependForwardSlash(joinPaths(settings.config.base, filePath));
91
+ return prependForwardSlash(joinPaths(settings.config.base, finalFilePath));
84
92
  }
85
93
  };
86
94
  },
@@ -11,7 +11,7 @@ export declare const visit: {
11
11
  node: (node: traverse.Node, opts: traverse.TraverseOptions<traverse.Node>, scope?: traverse.Scope | undefined, state?: any, path?: traverse.NodePath<traverse.Node> | undefined, skipKeys?: Record<string, boolean> | undefined) => void;
12
12
  clearNode: (node: traverse.Node, opts?: traverse.RemovePropertiesOptions | undefined) => void;
13
13
  removeProperties: (tree: traverse.Node, opts?: traverse.RemovePropertiesOptions | undefined) => traverse.Node;
14
- hasType: (tree: traverse.Node, type: "CatchClause" | "ClassBody" | "Identifier" | "Program" | "SpreadElement" | "Super" | "SwitchCase" | "TemplateElement" | "VariableDeclarator" | "ArrayExpression" | "ArrowFunctionExpression" | "AssignmentExpression" | "AwaitExpression" | "BinaryExpression" | "CallExpression" | "ClassExpression" | "ConditionalExpression" | "FunctionExpression" | "LogicalExpression" | "MemberExpression" | "MetaProperty" | "NewExpression" | "ObjectExpression" | "SequenceExpression" | "TaggedTemplateExpression" | "TemplateLiteral" | "ThisExpression" | "UnaryExpression" | "UpdateExpression" | "YieldExpression" | "AnyTypeAnnotation" | "ArgumentPlaceholder" | "ArrayPattern" | "ArrayTypeAnnotation" | "AssignmentPattern" | "BigIntLiteral" | "BindExpression" | "BlockStatement" | "BooleanLiteral" | "BooleanLiteralTypeAnnotation" | "BooleanTypeAnnotation" | "BreakStatement" | "ClassAccessorProperty" | "ClassDeclaration" | "ClassImplements" | "ClassMethod" | "ClassPrivateMethod" | "ClassPrivateProperty" | "ClassProperty" | "ContinueStatement" | "DebuggerStatement" | "DecimalLiteral" | "DeclareClass" | "DeclareExportAllDeclaration" | "DeclareExportDeclaration" | "DeclareFunction" | "DeclareInterface" | "DeclareModule" | "DeclareModuleExports" | "DeclareOpaqueType" | "DeclareTypeAlias" | "DeclareVariable" | "DeclaredPredicate" | "Decorator" | "Directive" | "DirectiveLiteral" | "DoExpression" | "DoWhileStatement" | "EmptyStatement" | "EmptyTypeAnnotation" | "EnumBooleanBody" | "EnumBooleanMember" | "EnumDeclaration" | "EnumDefaultedMember" | "EnumNumberBody" | "EnumNumberMember" | "EnumStringBody" | "EnumStringMember" | "EnumSymbolBody" | "ExistsTypeAnnotation" | "ExportAllDeclaration" | "ExportDefaultDeclaration" | "ExportDefaultSpecifier" | "ExportNamedDeclaration" | "ExportNamespaceSpecifier" | "ExportSpecifier" | "ExpressionStatement" | "File" | "ForInStatement" | "ForOfStatement" | "ForStatement" | "FunctionDeclaration" | "FunctionTypeAnnotation" | "FunctionTypeParam" | "GenericTypeAnnotation" | "IfStatement" | "Import" | "ImportAttribute" | "ImportDeclaration" | "ImportDefaultSpecifier" | "ImportNamespaceSpecifier" | "ImportSpecifier" | "IndexedAccessType" | "InferredPredicate" | "InterfaceDeclaration" | "InterfaceExtends" | "InterfaceTypeAnnotation" | "InterpreterDirective" | "IntersectionTypeAnnotation" | "JSXAttribute" | "JSXClosingElement" | "JSXClosingFragment" | "JSXElement" | "JSXEmptyExpression" | "JSXExpressionContainer" | "JSXFragment" | "JSXIdentifier" | "JSXMemberExpression" | "JSXNamespacedName" | "JSXOpeningElement" | "JSXOpeningFragment" | "JSXSpreadAttribute" | "JSXSpreadChild" | "JSXText" | "LabeledStatement" | "MixedTypeAnnotation" | "ModuleExpression" | "Noop" | "NullLiteral" | "NullLiteralTypeAnnotation" | "NullableTypeAnnotation" | "NumberLiteral" | "NumberLiteralTypeAnnotation" | "NumberTypeAnnotation" | "NumericLiteral" | "ObjectMethod" | "ObjectPattern" | "ObjectProperty" | "ObjectTypeAnnotation" | "ObjectTypeCallProperty" | "ObjectTypeIndexer" | "ObjectTypeInternalSlot" | "ObjectTypeProperty" | "ObjectTypeSpreadProperty" | "OpaqueType" | "OptionalCallExpression" | "OptionalIndexedAccessType" | "OptionalMemberExpression" | "ParenthesizedExpression" | "PipelineBareFunction" | "PipelinePrimaryTopicReference" | "PipelineTopicExpression" | "Placeholder" | "PrivateName" | "QualifiedTypeIdentifier" | "RecordExpression" | "RegExpLiteral" | "RegexLiteral" | "RestElement" | "RestProperty" | "ReturnStatement" | "SpreadProperty" | "StaticBlock" | "StringLiteral" | "StringLiteralTypeAnnotation" | "StringTypeAnnotation" | "SwitchStatement" | "SymbolTypeAnnotation" | "TSAnyKeyword" | "TSArrayType" | "TSAsExpression" | "TSBigIntKeyword" | "TSBooleanKeyword" | "TSCallSignatureDeclaration" | "TSConditionalType" | "TSConstructSignatureDeclaration" | "TSConstructorType" | "TSDeclareFunction" | "TSDeclareMethod" | "TSEnumDeclaration" | "TSEnumMember" | "TSExportAssignment" | "TSExpressionWithTypeArguments" | "TSExternalModuleReference" | "TSFunctionType" | "TSImportEqualsDeclaration" | "TSImportType" | "TSIndexSignature" | "TSIndexedAccessType" | "TSInferType" | "TSInstantiationExpression" | "TSInterfaceBody" | "TSInterfaceDeclaration" | "TSIntersectionType" | "TSIntrinsicKeyword" | "TSLiteralType" | "TSMappedType" | "TSMethodSignature" | "TSModuleBlock" | "TSModuleDeclaration" | "TSNamedTupleMember" | "TSNamespaceExportDeclaration" | "TSNeverKeyword" | "TSNonNullExpression" | "TSNullKeyword" | "TSNumberKeyword" | "TSObjectKeyword" | "TSOptionalType" | "TSParameterProperty" | "TSParenthesizedType" | "TSPropertySignature" | "TSQualifiedName" | "TSRestType" | "TSSatisfiesExpression" | "TSStringKeyword" | "TSSymbolKeyword" | "TSThisType" | "TSTupleType" | "TSTypeAliasDeclaration" | "TSTypeAnnotation" | "TSTypeAssertion" | "TSTypeLiteral" | "TSTypeOperator" | "TSTypeParameter" | "TSTypeParameterDeclaration" | "TSTypeParameterInstantiation" | "TSTypePredicate" | "TSTypeQuery" | "TSTypeReference" | "TSUndefinedKeyword" | "TSUnionType" | "TSUnknownKeyword" | "TSVoidKeyword" | "ThisTypeAnnotation" | "ThrowStatement" | "TopicReference" | "TryStatement" | "TupleExpression" | "TupleTypeAnnotation" | "TypeAlias" | "TypeAnnotation" | "TypeCastExpression" | "TypeParameter" | "TypeParameterDeclaration" | "TypeParameterInstantiation" | "TypeofTypeAnnotation" | "UnionTypeAnnotation" | "V8IntrinsicIdentifier" | "VariableDeclaration" | "Variance" | "VoidTypeAnnotation" | "WhileStatement" | "WithStatement", denylistTypes?: string[] | undefined) => boolean;
14
+ hasType: (tree: traverse.Node, type: "CatchClause" | "ClassBody" | "Identifier" | "Program" | "SpreadElement" | "Super" | "SwitchCase" | "TemplateElement" | "VariableDeclarator" | "ArrayExpression" | "ArrowFunctionExpression" | "AssignmentExpression" | "AwaitExpression" | "BinaryExpression" | "CallExpression" | "ClassExpression" | "ConditionalExpression" | "FunctionExpression" | "ImportExpression" | "LogicalExpression" | "MemberExpression" | "MetaProperty" | "NewExpression" | "ObjectExpression" | "SequenceExpression" | "TaggedTemplateExpression" | "TemplateLiteral" | "ThisExpression" | "UnaryExpression" | "UpdateExpression" | "YieldExpression" | "AnyTypeAnnotation" | "ArgumentPlaceholder" | "ArrayPattern" | "ArrayTypeAnnotation" | "AssignmentPattern" | "BigIntLiteral" | "BindExpression" | "BlockStatement" | "BooleanLiteral" | "BooleanLiteralTypeAnnotation" | "BooleanTypeAnnotation" | "BreakStatement" | "ClassAccessorProperty" | "ClassDeclaration" | "ClassImplements" | "ClassMethod" | "ClassPrivateMethod" | "ClassPrivateProperty" | "ClassProperty" | "ContinueStatement" | "DebuggerStatement" | "DecimalLiteral" | "DeclareClass" | "DeclareExportAllDeclaration" | "DeclareExportDeclaration" | "DeclareFunction" | "DeclareInterface" | "DeclareModule" | "DeclareModuleExports" | "DeclareOpaqueType" | "DeclareTypeAlias" | "DeclareVariable" | "DeclaredPredicate" | "Decorator" | "Directive" | "DirectiveLiteral" | "DoExpression" | "DoWhileStatement" | "EmptyStatement" | "EmptyTypeAnnotation" | "EnumBooleanBody" | "EnumBooleanMember" | "EnumDeclaration" | "EnumDefaultedMember" | "EnumNumberBody" | "EnumNumberMember" | "EnumStringBody" | "EnumStringMember" | "EnumSymbolBody" | "ExistsTypeAnnotation" | "ExportAllDeclaration" | "ExportDefaultDeclaration" | "ExportDefaultSpecifier" | "ExportNamedDeclaration" | "ExportNamespaceSpecifier" | "ExportSpecifier" | "ExpressionStatement" | "File" | "ForInStatement" | "ForOfStatement" | "ForStatement" | "FunctionDeclaration" | "FunctionTypeAnnotation" | "FunctionTypeParam" | "GenericTypeAnnotation" | "IfStatement" | "Import" | "ImportAttribute" | "ImportDeclaration" | "ImportDefaultSpecifier" | "ImportNamespaceSpecifier" | "ImportSpecifier" | "IndexedAccessType" | "InferredPredicate" | "InterfaceDeclaration" | "InterfaceExtends" | "InterfaceTypeAnnotation" | "InterpreterDirective" | "IntersectionTypeAnnotation" | "JSXAttribute" | "JSXClosingElement" | "JSXClosingFragment" | "JSXElement" | "JSXEmptyExpression" | "JSXExpressionContainer" | "JSXFragment" | "JSXIdentifier" | "JSXMemberExpression" | "JSXNamespacedName" | "JSXOpeningElement" | "JSXOpeningFragment" | "JSXSpreadAttribute" | "JSXSpreadChild" | "JSXText" | "LabeledStatement" | "MixedTypeAnnotation" | "ModuleExpression" | "Noop" | "NullLiteral" | "NullLiteralTypeAnnotation" | "NullableTypeAnnotation" | "NumberLiteral" | "NumberLiteralTypeAnnotation" | "NumberTypeAnnotation" | "NumericLiteral" | "ObjectMethod" | "ObjectPattern" | "ObjectProperty" | "ObjectTypeAnnotation" | "ObjectTypeCallProperty" | "ObjectTypeIndexer" | "ObjectTypeInternalSlot" | "ObjectTypeProperty" | "ObjectTypeSpreadProperty" | "OpaqueType" | "OptionalCallExpression" | "OptionalIndexedAccessType" | "OptionalMemberExpression" | "ParenthesizedExpression" | "PipelineBareFunction" | "PipelinePrimaryTopicReference" | "PipelineTopicExpression" | "Placeholder" | "PrivateName" | "QualifiedTypeIdentifier" | "RecordExpression" | "RegExpLiteral" | "RegexLiteral" | "RestElement" | "RestProperty" | "ReturnStatement" | "SpreadProperty" | "StaticBlock" | "StringLiteral" | "StringLiteralTypeAnnotation" | "StringTypeAnnotation" | "SwitchStatement" | "SymbolTypeAnnotation" | "TSAnyKeyword" | "TSArrayType" | "TSAsExpression" | "TSBigIntKeyword" | "TSBooleanKeyword" | "TSCallSignatureDeclaration" | "TSConditionalType" | "TSConstructSignatureDeclaration" | "TSConstructorType" | "TSDeclareFunction" | "TSDeclareMethod" | "TSEnumDeclaration" | "TSEnumMember" | "TSExportAssignment" | "TSExpressionWithTypeArguments" | "TSExternalModuleReference" | "TSFunctionType" | "TSImportEqualsDeclaration" | "TSImportType" | "TSIndexSignature" | "TSIndexedAccessType" | "TSInferType" | "TSInstantiationExpression" | "TSInterfaceBody" | "TSInterfaceDeclaration" | "TSIntersectionType" | "TSIntrinsicKeyword" | "TSLiteralType" | "TSMappedType" | "TSMethodSignature" | "TSModuleBlock" | "TSModuleDeclaration" | "TSNamedTupleMember" | "TSNamespaceExportDeclaration" | "TSNeverKeyword" | "TSNonNullExpression" | "TSNullKeyword" | "TSNumberKeyword" | "TSObjectKeyword" | "TSOptionalType" | "TSParameterProperty" | "TSParenthesizedType" | "TSPropertySignature" | "TSQualifiedName" | "TSRestType" | "TSSatisfiesExpression" | "TSStringKeyword" | "TSSymbolKeyword" | "TSThisType" | "TSTupleType" | "TSTypeAliasDeclaration" | "TSTypeAnnotation" | "TSTypeAssertion" | "TSTypeLiteral" | "TSTypeOperator" | "TSTypeParameter" | "TSTypeParameterDeclaration" | "TSTypeParameterInstantiation" | "TSTypePredicate" | "TSTypeQuery" | "TSTypeReference" | "TSUndefinedKeyword" | "TSUnionType" | "TSUnknownKeyword" | "TSVoidKeyword" | "ThisTypeAnnotation" | "ThrowStatement" | "TopicReference" | "TryStatement" | "TupleExpression" | "TupleTypeAnnotation" | "TypeAlias" | "TypeAnnotation" | "TypeCastExpression" | "TypeParameter" | "TypeParameterDeclaration" | "TypeParameterInstantiation" | "TypeofTypeAnnotation" | "UnionTypeAnnotation" | "V8IntrinsicIdentifier" | "VariableDeclaration" | "Variance" | "VoidTypeAnnotation" | "WhileStatement" | "WithStatement", denylistTypes?: string[] | undefined) => boolean;
15
15
  cache: typeof traverse.cache;
16
16
  };
17
17
  export { t };
@@ -23,8 +23,8 @@ export declare const collectionConfigParser: z.ZodUnion<[z.ZodObject<{
23
23
  type: z.ZodDefault<z.ZodOptional<z.ZodLiteral<"content">>>;
24
24
  schema: z.ZodOptional<z.ZodAny>;
25
25
  }, "strip", z.ZodTypeAny, {
26
- schema?: any;
27
26
  type: "content";
27
+ schema?: any;
28
28
  }, {
29
29
  type?: "content" | undefined;
30
30
  schema?: any;
@@ -32,11 +32,11 @@ export declare const collectionConfigParser: z.ZodUnion<[z.ZodObject<{
32
32
  type: z.ZodLiteral<"data">;
33
33
  schema: z.ZodOptional<z.ZodAny>;
34
34
  }, "strip", z.ZodTypeAny, {
35
- schema?: any;
36
35
  type: "data";
37
- }, {
38
36
  schema?: any;
37
+ }, {
39
38
  type: "data";
39
+ schema?: any;
40
40
  }>]>;
41
41
  export declare function getDotAstroTypeReference({ root, srcDir }: {
42
42
  root: URL;
@@ -47,8 +47,8 @@ export declare const contentConfigParser: z.ZodObject<{
47
47
  type: z.ZodDefault<z.ZodOptional<z.ZodLiteral<"content">>>;
48
48
  schema: z.ZodOptional<z.ZodAny>;
49
49
  }, "strip", z.ZodTypeAny, {
50
- schema?: any;
51
50
  type: "content";
51
+ schema?: any;
52
52
  }, {
53
53
  type?: "content" | undefined;
54
54
  schema?: any;
@@ -56,27 +56,27 @@ export declare const contentConfigParser: z.ZodObject<{
56
56
  type: z.ZodLiteral<"data">;
57
57
  schema: z.ZodOptional<z.ZodAny>;
58
58
  }, "strip", z.ZodTypeAny, {
59
- schema?: any;
60
59
  type: "data";
61
- }, {
62
60
  schema?: any;
61
+ }, {
63
62
  type: "data";
63
+ schema?: any;
64
64
  }>]>>;
65
65
  }, "strip", z.ZodTypeAny, {
66
66
  collections: Record<string, {
67
- schema?: any;
68
67
  type: "content";
69
- } | {
70
68
  schema?: any;
69
+ } | {
71
70
  type: "data";
71
+ schema?: any;
72
72
  }>;
73
73
  }, {
74
74
  collections: Record<string, {
75
75
  type?: "content" | undefined;
76
76
  schema?: any;
77
77
  } | {
78
- schema?: any;
79
78
  type: "data";
79
+ schema?: any;
80
80
  }>;
81
81
  }>;
82
82
  export type CollectionConfig = z.infer<typeof collectionConfigParser>;
@@ -1,10 +1,13 @@
1
1
  import * as colors from "kleur/colors";
2
2
  import { bgGreen, black, cyan, dim, green, magenta } from "kleur/colors";
3
3
  import fs from "node:fs";
4
+ import os from "node:os";
4
5
  import { fileURLToPath } from "node:url";
6
+ import PQueue from "p-queue";
5
7
  import {
6
- generateImage as generateImageInternal,
7
- getStaticImageList
8
+ generateImagesForPath,
9
+ getStaticImageList,
10
+ prepareAssetsGenerationEnv
8
11
  } from "../../assets/build/generate.js";
9
12
  import { hasPrerenderedPages } from "../../core/build/internal.js";
10
13
  import {
@@ -145,45 +148,30 @@ ${bgGreen(black(` ${verb} static routes `))}`);
145
148
  }
146
149
  }
147
150
  }
151
+ logger.info(null, dim(`Completed in ${getTimeStat(timer, performance.now())}.
152
+ `));
148
153
  const staticImageList = getStaticImageList();
149
- if (staticImageList.size)
154
+ if (staticImageList.size) {
150
155
  logger.info(null, `
151
156
  ${bgGreen(black(` generating optimized images `))}`);
152
- let count = 0;
153
- for (const imageData of staticImageList.entries()) {
154
- count++;
155
- await generateImage(
156
- pipeline,
157
- imageData[1].options,
158
- imageData[1].path,
159
- count,
160
- staticImageList.size
161
- );
157
+ const totalCount = Array.from(staticImageList.values()).map((x) => x.size).reduce((a, b) => a + b, 0);
158
+ const cpuCount = os.cpus().length;
159
+ const assetsCreationEnvironment = await prepareAssetsGenerationEnv(pipeline, totalCount);
160
+ const queue = new PQueue({ concurrency: cpuCount });
161
+ const assetsTimer = performance.now();
162
+ for (const [originalPath, transforms] of staticImageList) {
163
+ await generateImagesForPath(originalPath, transforms, assetsCreationEnvironment, queue);
164
+ }
165
+ await queue.onIdle();
166
+ const assetsTimeEnd = performance.now();
167
+ logger.info(null, dim(`Completed in ${getTimeStat(assetsTimer, assetsTimeEnd)}.
168
+ `));
169
+ delete globalThis?.astroAsset?.addStaticImage;
162
170
  }
163
- delete globalThis?.astroAsset?.addStaticImage;
164
171
  await runHookBuildGenerated({
165
172
  config: opts.settings.config,
166
173
  logger: pipeline.getLogger()
167
174
  });
168
- logger.info(null, dim(`Completed in ${getTimeStat(timer, performance.now())}.
169
- `));
170
- }
171
- async function generateImage(pipeline, transform, path, count, totalCount) {
172
- const logger = pipeline.getLogger();
173
- let timeStart = performance.now();
174
- const generationData = await generateImageInternal(pipeline, transform, path);
175
- if (!generationData) {
176
- return;
177
- }
178
- const timeEnd = performance.now();
179
- const timeChange = getTimeStat(timeStart, timeEnd);
180
- const timeIncrease = `(+${timeChange})`;
181
- const statsText = generationData.cached ? `(reused cache entry)` : `(before: ${generationData.weight.before}kB, after: ${generationData.weight.after}kB)`;
182
- const counter = `(${count}/${totalCount})`;
183
- logger.info(
184
- null,
185
- ` ${green("\u25B6")} ${path} ${dim(statsText)} ${dim(timeIncrease)} ${dim(counter)}`
186
- );
187
175
  }
188
176
  async function generatePage(pageData, ssrEntry, builtPaths, pipeline) {
189
177
  let timeStart = performance.now();