astro 3.3.4 → 3.4.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 (46) hide show
  1. package/dist/@types/astro.d.ts +34 -0
  2. package/dist/assets/build/generate.d.ts +20 -16
  3. package/dist/assets/build/generate.js +125 -72
  4. package/dist/assets/types.d.ts +5 -4
  5. package/dist/assets/vite-plugin-assets.js +15 -7
  6. package/dist/cli/add/babel.d.ts +1 -1
  7. package/dist/core/build/generate.js +21 -33
  8. package/dist/core/config/schema.d.ts +14 -0
  9. package/dist/core/config/schema.js +4 -2
  10. package/dist/core/config/settings.js +1 -0
  11. package/dist/core/constants.js +1 -1
  12. package/dist/core/create-vite.js +3 -1
  13. package/dist/core/dev/dev.js +1 -1
  14. package/dist/core/messages.js +2 -2
  15. package/dist/core/render/core.js +1 -0
  16. package/dist/core/render/result.d.ts +1 -0
  17. package/dist/core/render/result.js +1 -0
  18. package/dist/integrations/index.js +3 -10
  19. package/dist/runtime/client/dev-overlay/overlay.d.ts +1 -0
  20. package/dist/runtime/client/dev-overlay/overlay.js +446 -0
  21. package/dist/runtime/client/dev-overlay/plugins/astro.d.ts +7 -0
  22. package/dist/runtime/client/dev-overlay/plugins/astro.js +66 -0
  23. package/dist/runtime/client/dev-overlay/plugins/audit.d.ts +7 -0
  24. package/dist/runtime/client/dev-overlay/plugins/audit.js +75 -0
  25. package/dist/runtime/client/dev-overlay/plugins/utils/highlight.d.ts +5 -0
  26. package/dist/runtime/client/dev-overlay/plugins/utils/highlight.js +39 -0
  27. package/dist/runtime/client/dev-overlay/plugins/xray.d.ts +7 -0
  28. package/dist/runtime/client/dev-overlay/plugins/xray.js +75 -0
  29. package/dist/runtime/client/dev-overlay/ui-library/card.d.ts +9 -0
  30. package/dist/runtime/client/dev-overlay/ui-library/card.js +67 -0
  31. package/dist/runtime/client/dev-overlay/ui-library/highlight.d.ts +7 -0
  32. package/dist/runtime/client/dev-overlay/ui-library/highlight.js +60 -0
  33. package/dist/runtime/client/dev-overlay/ui-library/icons.d.ts +10 -0
  34. package/dist/runtime/client/dev-overlay/ui-library/icons.js +21 -0
  35. package/dist/runtime/client/dev-overlay/ui-library/tooltip.d.ts +16 -0
  36. package/dist/runtime/client/dev-overlay/ui-library/tooltip.js +132 -0
  37. package/dist/runtime/client/dev-overlay/ui-library/window.d.ts +9 -0
  38. package/dist/runtime/client/dev-overlay/ui-library/window.js +70 -0
  39. package/dist/runtime/server/render/astro/render.js +2 -2
  40. package/dist/runtime/server/render/common.js +2 -2
  41. package/dist/runtime/server/render/component.js +1 -1
  42. package/dist/type-utils.d.ts +1 -0
  43. package/dist/vite-plugin-astro-server/route.js +17 -1
  44. package/dist/vite-plugin-dev-overlay/vite-plugin-dev-overlay.d.ts +3 -0
  45. package/dist/vite-plugin-dev-overlay/vite-plugin-dev-overlay.js +24 -0
  46. package/package.json +2 -1
@@ -16,6 +16,7 @@ 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 { Icon } from '../runtime/client/dev-overlay/ui-library/icons.js';
19
20
  import type { AstroComponentFactory, AstroComponentInstance } from '../runtime/server/index.js';
20
21
  import type { OmitIndexSignature, Simplify } from '../type-utils.js';
21
22
  import type { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './../core/constants.js';
@@ -1252,6 +1253,24 @@ export interface AstroUserConfig {
1252
1253
  * ```
1253
1254
  */
1254
1255
  optimizeHoistedScript?: boolean;
1256
+ /**
1257
+ * @docs
1258
+ * @name experimental.devOverlay
1259
+ * @type {boolean}
1260
+ * @default `false`
1261
+ * @version 3.4.0
1262
+ * @description
1263
+ * 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.
1264
+ *
1265
+ * ```js
1266
+ * {
1267
+ * experimental: {
1268
+ * devOverlay: true,
1269
+ * },
1270
+ * }
1271
+ * ```
1272
+ */
1273
+ devOverlay?: boolean;
1255
1274
  };
1256
1275
  }
1257
1276
  /**
@@ -1402,6 +1421,7 @@ export interface AstroSettings {
1402
1421
  * Map of directive name (e.g. `load`) to the directive script code
1403
1422
  */
1404
1423
  clientDirectives: Map<string, string>;
1424
+ devOverlayPlugins: string[];
1405
1425
  tsConfig: TSConfig | undefined;
1406
1426
  tsConfigPath: string | undefined;
1407
1427
  watchFiles: string[];
@@ -1412,6 +1432,7 @@ export type AsyncRendererComponentFn<U> = (Component: any, props: any, slots: Re
1412
1432
  export interface ComponentInstance {
1413
1433
  default: AstroComponentFactory;
1414
1434
  css?: string[];
1435
+ partial?: boolean;
1415
1436
  prerender?: boolean;
1416
1437
  /**
1417
1438
  * Only used for logging if deprecated drafts feature is used
@@ -1834,6 +1855,7 @@ export interface AstroIntegration {
1834
1855
  injectScript: (stage: InjectedScriptStage, content: string) => void;
1835
1856
  injectRoute: (injectRoute: InjectedRoute) => void;
1836
1857
  addClientDirective: (directive: ClientDirectiveConfig) => void;
1858
+ addDevOverlayPlugin: (entrypoint: string) => void;
1837
1859
  logger: AstroIntegrationLogger;
1838
1860
  }) => void | Promise<void>;
1839
1861
  'astro:config:done'?: (options: {
@@ -1971,6 +1993,7 @@ export interface SSRResult {
1971
1993
  */
1972
1994
  clientDirectives: Map<string, string>;
1973
1995
  compressHTML: boolean;
1996
+ partial: boolean;
1974
1997
  /**
1975
1998
  * Only used for logging
1976
1999
  */
@@ -2026,3 +2049,14 @@ export interface ClientDirectiveConfig {
2026
2049
  name: string;
2027
2050
  entrypoint: string;
2028
2051
  }
2052
+ export interface DevOverlayPlugin {
2053
+ id: string;
2054
+ name: string;
2055
+ icon: Icon;
2056
+ init?(canvas: ShadowRoot, eventTarget: EventTarget): void | Promise<void>;
2057
+ }
2058
+ export type DevOverlayMetadata = Window & typeof globalThis & {
2059
+ __astro_dev_overlay__: {
2060
+ root: string;
2061
+ };
2062
+ };
@@ -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 };
@@ -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();
@@ -228,10 +228,13 @@ export declare const AstroConfigSchema: z.ZodObject<{
228
228
  vite: z.ZodDefault<z.ZodType<ViteUserConfig, z.ZodTypeDef, ViteUserConfig>>;
229
229
  experimental: z.ZodDefault<z.ZodObject<{
230
230
  optimizeHoistedScript: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
231
+ devOverlay: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
231
232
  }, "strict", z.ZodTypeAny, {
232
233
  optimizeHoistedScript: boolean;
234
+ devOverlay: boolean;
233
235
  }, {
234
236
  optimizeHoistedScript?: boolean | undefined;
237
+ devOverlay?: boolean | undefined;
235
238
  }>>;
236
239
  legacy: z.ZodDefault<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
237
240
  }, "strip", z.ZodTypeAny, {
@@ -307,6 +310,7 @@ export declare const AstroConfigSchema: z.ZodObject<{
307
310
  vite: ViteUserConfig;
308
311
  experimental: {
309
312
  optimizeHoistedScript: boolean;
313
+ devOverlay: boolean;
310
314
  };
311
315
  legacy: {};
312
316
  }, {
@@ -376,6 +380,7 @@ export declare const AstroConfigSchema: z.ZodObject<{
376
380
  vite?: ViteUserConfig | undefined;
377
381
  experimental?: {
378
382
  optimizeHoistedScript?: boolean | undefined;
383
+ devOverlay?: boolean | undefined;
379
384
  } | undefined;
380
385
  legacy?: {} | undefined;
381
386
  }>;
@@ -534,10 +539,13 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
534
539
  vite: z.ZodDefault<z.ZodType<ViteUserConfig, z.ZodTypeDef, ViteUserConfig>>;
535
540
  experimental: z.ZodDefault<z.ZodObject<{
536
541
  optimizeHoistedScript: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
542
+ devOverlay: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
537
543
  }, "strict", z.ZodTypeAny, {
538
544
  optimizeHoistedScript: boolean;
545
+ devOverlay: boolean;
539
546
  }, {
540
547
  optimizeHoistedScript?: boolean | undefined;
548
+ devOverlay?: boolean | undefined;
541
549
  }>>;
542
550
  legacy: z.ZodDefault<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
543
551
  root: z.ZodEffects<z.ZodDefault<z.ZodString>, import("url").URL, string | undefined>;
@@ -679,6 +687,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
679
687
  vite: ViteUserConfig;
680
688
  experimental: {
681
689
  optimizeHoistedScript: boolean;
690
+ devOverlay: boolean;
682
691
  };
683
692
  legacy: {};
684
693
  }, {
@@ -748,6 +757,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
748
757
  vite?: ViteUserConfig | undefined;
749
758
  experimental?: {
750
759
  optimizeHoistedScript?: boolean | undefined;
760
+ devOverlay?: boolean | undefined;
751
761
  } | undefined;
752
762
  legacy?: {} | undefined;
753
763
  }>, {
@@ -824,6 +834,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
824
834
  vite: ViteUserConfig;
825
835
  experimental: {
826
836
  optimizeHoistedScript: boolean;
837
+ devOverlay: boolean;
827
838
  };
828
839
  legacy: {};
829
840
  }, {
@@ -893,6 +904,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
893
904
  vite?: ViteUserConfig | undefined;
894
905
  experimental?: {
895
906
  optimizeHoistedScript?: boolean | undefined;
907
+ devOverlay?: boolean | undefined;
896
908
  } | undefined;
897
909
  legacy?: {} | undefined;
898
910
  }>, {
@@ -969,6 +981,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
969
981
  vite: ViteUserConfig;
970
982
  experimental: {
971
983
  optimizeHoistedScript: boolean;
984
+ devOverlay: boolean;
972
985
  };
973
986
  legacy: {};
974
987
  }, {
@@ -1038,6 +1051,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
1038
1051
  vite?: ViteUserConfig | undefined;
1039
1052
  experimental?: {
1040
1053
  optimizeHoistedScript?: boolean | undefined;
1054
+ devOverlay?: boolean | undefined;
1041
1055
  } | undefined;
1042
1056
  legacy?: {} | undefined;
1043
1057
  }>;
@@ -41,7 +41,8 @@ const ASTRO_CONFIG_DEFAULTS = {
41
41
  legacy: {},
42
42
  redirects: {},
43
43
  experimental: {
44
- optimizeHoistedScript: false
44
+ optimizeHoistedScript: false,
45
+ devOverlay: false
45
46
  }
46
47
  };
47
48
  const AstroConfigSchema = z.object({
@@ -179,7 +180,8 @@ const AstroConfigSchema = z.object({
179
180
  }).default({}),
180
181
  vite: z.custom((data) => data instanceof Object && !Array.isArray(data)).default(ASTRO_CONFIG_DEFAULTS.vite),
181
182
  experimental: z.object({
182
- optimizeHoistedScript: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.optimizeHoistedScript)
183
+ optimizeHoistedScript: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.optimizeHoistedScript),
184
+ devOverlay: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.devOverlay)
183
185
  }).strict(
184
186
  `Invalid or outdated experimental feature.
185
187
  Check for incorrect spelling or outdated Astro version.
@@ -87,6 +87,7 @@ function createBaseSettings(config) {
87
87
  scripts: [],
88
88
  clientDirectives: getDefaultClientDirectives(),
89
89
  watchFiles: [],
90
+ devOverlayPlugins: [],
90
91
  timer: new AstroTimer()
91
92
  };
92
93
  }
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "3.3.4";
1
+ const ASTRO_VERSION = "3.4.0";
2
2
  const SUPPORTED_MARKDOWN_FILE_EXTENSIONS = [
3
3
  ".markdown",
4
4
  ".mdown",