astro 2.1.7 → 2.1.8

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.
package/astro-jsx.d.ts CHANGED
@@ -789,9 +789,9 @@ declare namespace astroHTML.JSX {
789
789
  fetchpriority?: 'auto' | 'high' | 'low' | undefined | null;
790
790
  integrity?: string | undefined | null;
791
791
  media?: string | undefined | null;
792
- imageSrcSet?: string | undefined | null;
793
- imageSizes?: string | undefined | null;
794
- referrerPolicy?: HTMLAttributeReferrerPolicy | undefined | null;
792
+ imagesrcset?: string | undefined | null;
793
+ imagesizes?: string | undefined | null;
794
+ referrerpolicy?: HTMLAttributeReferrerPolicy | undefined | null;
795
795
  rel?: string | undefined | null;
796
796
  sizes?: string | undefined | null;
797
797
  type?: string | undefined | null;
@@ -68,6 +68,7 @@ export interface CLIFlags {
68
68
  port?: number;
69
69
  config?: string;
70
70
  drafts?: boolean;
71
+ open?: boolean;
71
72
  experimentalAssets?: boolean;
72
73
  }
73
74
  export interface BuildConfig {
@@ -975,6 +976,7 @@ export interface ContentEntryType {
975
976
  contents: string;
976
977
  }): GetEntryInfoReturnType | Promise<GetEntryInfoReturnType>;
977
978
  getRenderModule?(this: rollup.PluginContext, params: {
979
+ viteId: string;
978
980
  entry: ContentEntryModule;
979
981
  }): rollup.LoadResult | Promise<rollup.LoadResult>;
980
982
  contentModuleTypes?: string;
@@ -1,5 +1,7 @@
1
1
  import fs from "node:fs";
2
+ import { basename, join } from "node:path/posix";
2
3
  import { AstroError, AstroErrorData } from "../core/errors/index.js";
4
+ import { prependForwardSlash } from "../core/path.js";
3
5
  import { isLocalService } from "./services/service.js";
4
6
  function isESMImportedImage(src) {
5
7
  return typeof src === "object";
@@ -53,8 +55,16 @@ async function generateImage(buildOpts, options, filepath) {
53
55
  serverRoot = buildOpts.settings.config.outDir;
54
56
  clientRoot = buildOpts.settings.config.outDir;
55
57
  }
56
- const fileData = await fs.promises.readFile(new URL("." + options.src.src, serverRoot));
57
- const resultData = await imageService.transform(fileData, { ...options, src: options.src.src });
58
+ const originalImagePath = options.src.src;
59
+ const fileData = await fs.promises.readFile(
60
+ new URL(
61
+ "." + prependForwardSlash(
62
+ join(buildOpts.settings.config.build.assets, basename(originalImagePath))
63
+ ),
64
+ serverRoot
65
+ )
66
+ );
67
+ const resultData = await imageService.transform(fileData, { ...options, src: originalImagePath });
58
68
  const finalFileURL = new URL("." + filepath, clientRoot);
59
69
  const finalFolderURL = new URL("./", finalFileURL);
60
70
  await fs.promises.mkdir(finalFolderURL, { recursive: true });
@@ -1,2 +1,2 @@
1
1
  import type { ImageTransform } from '../types.js';
2
- export declare function propsToFilename(transform: ImageTransform): string;
2
+ export declare function propsToFilename(transform: ImageTransform, imageService: string): string;
@@ -2,15 +2,17 @@ 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) {
5
+ function propsToFilename(transform, imageService) {
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 { alt, ...rest } = transform;
13
+ const hashFields = { ...rest, imageService };
12
14
  const outputExt = transform.format ? `.${transform.format}` : ext;
13
- return `/${filename}_${shorthash(JSON.stringify(transform))}${outputExt}`;
15
+ return `/${filename}_${shorthash(JSON.stringify(hashFields))}${outputExt}`;
14
16
  }
15
17
  export {
16
18
  propsToFilename
@@ -135,14 +135,13 @@ function assets({
135
135
  }
136
136
  filePath = prependForwardSlash(
137
137
  joinPaths(
138
- settings.config.base,
139
138
  settings.config.build.assets,
140
- propsToFilename(options)
139
+ propsToFilename(options, settings.config.image.service)
141
140
  )
142
141
  );
143
142
  globalThis.astroAsset.staticImages.set(options, filePath);
144
143
  }
145
- return filePath;
144
+ return prependForwardSlash(joinPaths(settings.config.base, filePath));
146
145
  };
147
146
  },
148
147
  async buildEnd() {
@@ -173,8 +173,14 @@ async function createContentTypesGenerator({
173
173
  return;
174
174
  events.push(event);
175
175
  debounceTimeout && clearTimeout(debounceTimeout);
176
+ const runEventsSafe = async () => {
177
+ try {
178
+ await runEvents(opts);
179
+ } catch {
180
+ }
181
+ };
176
182
  debounceTimeout = setTimeout(
177
- async () => runEvents(opts),
183
+ runEventsSafe,
178
184
  50
179
185
  /* debounce to batch chokidar events */
180
186
  );
@@ -106,7 +106,7 @@ export const _internal = {
106
106
  )}. Did you import this module directly without using a content collection query?`
107
107
  });
108
108
  }
109
- return contentRenderer.bind(this)({ entry });
109
+ return contentRenderer.bind(this)({ entry, viteId });
110
110
  }
111
111
  });
112
112
  }
@@ -34,7 +34,7 @@ class NodeApp extends App {
34
34
  routeData
35
35
  );
36
36
  }
37
- if (typeof req.body === "object" && Object.keys(req.body).length > 0) {
37
+ if (typeof req.body === "object" && req.body !== null && Object.keys(req.body).length > 0) {
38
38
  return super.render(
39
39
  req instanceof Request ? req : createRequestFromNodeRequest(req, Buffer.from(JSON.stringify(req.body))),
40
40
  routeData
@@ -71,6 +71,7 @@ function resolveFlags(flags) {
71
71
  site: typeof flags.site === "string" ? flags.site : void 0,
72
72
  base: typeof flags.base === "string" ? flags.base : void 0,
73
73
  port: typeof flags.port === "number" ? flags.port : void 0,
74
+ open: typeof flags.open === "boolean" ? flags.open : void 0,
74
75
  config: typeof flags.config === "string" ? flags.config : void 0,
75
76
  host: typeof flags.host === "string" || typeof flags.host === "boolean" ? flags.host : void 0,
76
77
  drafts: typeof flags.drafts === "boolean" ? flags.drafts : void 0,
@@ -99,6 +100,9 @@ function mergeCLIFlags(astroConfig, flags) {
99
100
  if (typeof flags.host === "string" || typeof flags.host === "boolean") {
100
101
  astroConfig.server.host = flags.host;
101
102
  }
103
+ if (typeof flags.open === "boolean") {
104
+ astroConfig.server.open = flags.open;
105
+ }
102
106
  return astroConfig;
103
107
  }
104
108
  async function search(fsMod, root) {
@@ -56,19 +56,23 @@ export declare const AstroConfigSchema: z.ZodObject<{
56
56
  serverEntry?: string | undefined;
57
57
  }>>>;
58
58
  server: z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodObject<{
59
+ open: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
59
60
  host: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodBoolean]>>>;
60
61
  port: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
61
62
  headers: z.ZodOptional<z.ZodType<OutgoingHttpHeaders, z.ZodTypeDef, OutgoingHttpHeaders>>;
62
63
  }, "strip", z.ZodTypeAny, {
63
64
  headers?: OutgoingHttpHeaders | undefined;
65
+ open: boolean;
64
66
  host: string | boolean;
65
67
  port: number;
66
68
  }, {
69
+ open?: boolean | undefined;
67
70
  host?: string | boolean | undefined;
68
71
  port?: number | undefined;
69
72
  headers?: OutgoingHttpHeaders | undefined;
70
73
  }>>>, {
71
74
  headers?: OutgoingHttpHeaders | undefined;
75
+ open: boolean;
72
76
  host: string | boolean;
73
77
  port: number;
74
78
  }, unknown>;
@@ -165,6 +169,7 @@ export declare const AstroConfigSchema: z.ZodObject<{
165
169
  trailingSlash: "never" | "always" | "ignore";
166
170
  server: {
167
171
  headers?: OutgoingHttpHeaders | undefined;
172
+ open: boolean;
168
173
  host: string | boolean;
169
174
  port: number;
170
175
  };
@@ -350,20 +355,24 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: URL)
350
355
  server: z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodObject<{
351
356
  host: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodBoolean]>>>;
352
357
  port: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
358
+ open: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
353
359
  headers: z.ZodOptional<z.ZodType<OutgoingHttpHeaders, z.ZodTypeDef, OutgoingHttpHeaders>>;
354
360
  streaming: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
355
361
  }, "strip", z.ZodTypeAny, {
356
362
  headers?: OutgoingHttpHeaders | undefined;
363
+ open: boolean;
357
364
  host: string | boolean;
358
365
  port: number;
359
366
  streaming: boolean;
360
367
  }, {
368
+ open?: boolean | undefined;
361
369
  host?: string | boolean | undefined;
362
370
  port?: number | undefined;
363
371
  headers?: OutgoingHttpHeaders | undefined;
364
372
  streaming?: boolean | undefined;
365
373
  }>>>, {
366
374
  headers?: OutgoingHttpHeaders | undefined;
375
+ open: boolean;
367
376
  host: string | boolean;
368
377
  port: number;
369
378
  streaming: boolean;
@@ -397,6 +406,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: URL)
397
406
  trailingSlash: "never" | "always" | "ignore";
398
407
  server: {
399
408
  headers?: OutgoingHttpHeaders | undefined;
409
+ open: boolean;
400
410
  host: string | boolean;
401
411
  port: number;
402
412
  streaming: boolean;
@@ -493,6 +503,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: URL)
493
503
  trailingSlash: "never" | "always" | "ignore";
494
504
  server: {
495
505
  headers?: OutgoingHttpHeaders | undefined;
506
+ open: boolean;
496
507
  host: string | boolean;
497
508
  port: number;
498
509
  streaming: boolean;
@@ -19,7 +19,8 @@ const ASTRO_CONFIG_DEFAULTS = {
19
19
  server: {
20
20
  host: false,
21
21
  port: 3e3,
22
- streaming: true
22
+ streaming: true,
23
+ open: false
23
24
  },
24
25
  integrations: [],
25
26
  markdown: {
@@ -62,6 +63,7 @@ const AstroConfigSchema = z.object({
62
63
  (val) => typeof val === "function" ? val({ command: "error" }) : val,
63
64
  // validate
64
65
  z.object({
66
+ open: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.server.open),
65
67
  host: z.union([z.string(), z.boolean()]).optional().default(ASTRO_CONFIG_DEFAULTS.server.host),
66
68
  port: z.number().optional().default(ASTRO_CONFIG_DEFAULTS.server.port),
67
69
  headers: z.custom().optional()
@@ -137,6 +139,7 @@ function createRelativeSchema(cmd, fileProtocolRoot) {
137
139
  z.object({
138
140
  host: z.union([z.string(), z.boolean()]).optional().default(ASTRO_CONFIG_DEFAULTS.server.host),
139
141
  port: z.number().optional().default(ASTRO_CONFIG_DEFAULTS.server.port),
142
+ open: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.server.open),
140
143
  headers: z.custom().optional(),
141
144
  streaming: z.boolean().optional().default(true)
142
145
  }).optional().default({})
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "2.1.7";
1
+ const ASTRO_VERSION = "2.1.8";
2
2
  const SUPPORTED_MARKDOWN_FILE_EXTENSIONS = [
3
3
  ".markdown",
4
4
  ".mdown",
@@ -34,12 +34,12 @@ async function createContainer(params = {}) {
34
34
  logging,
35
35
  isRestart
36
36
  });
37
- const { host, headers } = settings.config.server;
37
+ const { host, headers, open } = settings.config.server;
38
38
  const rendererClientEntries = settings.renderers.map((r) => r.clientEntrypoint).filter(Boolean);
39
39
  const viteConfig = await createVite(
40
40
  {
41
41
  mode: "development",
42
- server: { host, headers },
42
+ server: { host, headers, open },
43
43
  optimizeDeps: {
44
44
  include: rendererClientEntries
45
45
  },
@@ -17,6 +17,7 @@ async function dev(settings, options) {
17
17
  ["--port", `Specify which port to run on. Defaults to 3000.`],
18
18
  ["--host", `Listen on all addresses, including LAN and public addresses.`],
19
19
  ["--host <custom-address>", `Expose on a network IP address at <custom-address>`],
20
+ ["--open", "Automatically open the app in the browser on server start"],
20
21
  ["--help (-h)", "See all available flags."]
21
22
  ]
22
23
  },
@@ -52,7 +53,7 @@ async function dev(settings, options) {
52
53
  isRestart: options.isRestart
53
54
  })
54
55
  );
55
- const currentVersion = "2.1.7";
56
+ const currentVersion = "2.1.8";
56
57
  if (currentVersion.includes("-")) {
57
58
  warn(options.logging, null, msg.prerelease({ currentVersion }));
58
59
  }
@@ -466,6 +466,22 @@ export declare const AstroErrorData: {
466
466
  readonly message: (format: string, imagePath: string, supportedFormats: readonly string[]) => string;
467
467
  readonly hint: "If you do not need optimization, using an `img` tag directly instead of the `Image` component might be what you're looking for.";
468
468
  };
469
+ /**
470
+ * @docs
471
+ * @see
472
+ * - [`getStaticPaths()`](https://docs.astro.build/en/reference/api-reference/#getstaticpaths)
473
+ * - [`params`](https://docs.astro.build/en/reference/api-reference/#params)
474
+ * @description
475
+ * The endpoint is prerendered with an `undefined` param so the generated path will collide with another route.
476
+ *
477
+ * If you cannot prevent passing `undefined`, then an additional extension can be added to the endpoint file name to generate the file with a different name. For example, renaming `pages/api/[slug].ts` to `pages/api/[slug].json.ts`.
478
+ */
479
+ readonly PrerenderDynamicEndpointPathCollide: {
480
+ readonly title: "Prerendered dynamic endpoint has path collision.";
481
+ readonly code: 3026;
482
+ readonly message: (pathname: string) => string;
483
+ readonly hint: (filename: string) => string;
484
+ };
469
485
  /**
470
486
  * @docs
471
487
  * @see
@@ -479,6 +479,22 @@ Expected \`true\` value but got \`${suffix}\`.`;
479
479
  )} are supported for optimization.`,
480
480
  hint: "If you do not need optimization, using an `img` tag directly instead of the `Image` component might be what you're looking for."
481
481
  },
482
+ /**
483
+ * @docs
484
+ * @see
485
+ * - [`getStaticPaths()`](https://docs.astro.build/en/reference/api-reference/#getstaticpaths)
486
+ * - [`params`](https://docs.astro.build/en/reference/api-reference/#params)
487
+ * @description
488
+ * The endpoint is prerendered with an `undefined` param so the generated path will collide with another route.
489
+ *
490
+ * If you cannot prevent passing `undefined`, then an additional extension can be added to the endpoint file name to generate the file with a different name. For example, renaming `pages/api/[slug].ts` to `pages/api/[slug].json.ts`.
491
+ */
492
+ PrerenderDynamicEndpointPathCollide: {
493
+ title: "Prerendered dynamic endpoint has path collision.",
494
+ code: 3026,
495
+ message: (pathname) => `Could not render \`${pathname}\` with an \`undefined\` param as the generated path will collide during prerendering. Prevent passing \`undefined\` as \`params\` for the endpoint's \`getStaticPaths()\` function, or add an additional extension to the endpoint's filename.`,
496
+ hint: (filename) => `Rename \`${filename}\` to \`${filename.replace(/\.(js|ts)/, (m) => `.json` + m)}\``
497
+ },
482
498
  // No headings here, that way Vite errors are merged with Astro ones in the docs, which makes more sense to users.
483
499
  // Vite Errors - 4xxx
484
500
  /**
@@ -47,7 +47,7 @@ function serverStart({
47
47
  base,
48
48
  isRestart = false
49
49
  }) {
50
- const version = "2.1.7";
50
+ const version = "2.1.8";
51
51
  const localPrefix = `${dim("\u2503")} Local `;
52
52
  const networkPrefix = `${dim("\u2503")} Network `;
53
53
  const emptyPrefix = " ".repeat(11);
@@ -233,7 +233,7 @@ function printHelp({
233
233
  message.push(
234
234
  linebreak(),
235
235
  ` ${bgGreen(black(` ${commandName} `))} ${green(
236
- `v${"2.1.7"}`
236
+ `v${"2.1.8"}`
237
237
  )} ${headline}`
238
238
  );
239
239
  }
@@ -11,7 +11,10 @@ async function preview(_settings, { logging, flags }) {
11
11
  commandName: "astro preview",
12
12
  usage: "[...flags]",
13
13
  tables: {
14
- Flags: [["--help (-h)", "See all available flags."]]
14
+ Flags: [
15
+ ["--open", "Automatically open the app in the browser on server start"],
16
+ ["--help (-h)", "See all available flags."]
17
+ ]
15
18
  },
16
19
  description: `Starts a local server to serve your static dist/ directory. Check ${cyan(
17
20
  "https://docs.astro.build/en/reference/cli-reference/#astro-preview"
@@ -20,7 +20,8 @@ async function createStaticPreviewServer(settings, logging) {
20
20
  preview: {
21
21
  host: settings.config.server.host,
22
22
  port: settings.config.server.port,
23
- headers: settings.config.server.headers
23
+ headers: settings.config.server.headers,
24
+ open: settings.config.server.open
24
25
  },
25
26
  plugins: [vitePluginAstroPreview(settings)]
26
27
  });
@@ -17,6 +17,21 @@ async function getParamsAndProps(opts) {
17
17
  const paramsMatch = route.pattern.exec(pathname);
18
18
  if (paramsMatch) {
19
19
  params = getParams(route.params)(paramsMatch);
20
+ if (route.type === "endpoint" && mod.getStaticPaths) {
21
+ const lastSegment = route.segments[route.segments.length - 1];
22
+ const paramValues = Object.values(params);
23
+ const lastParam = paramValues[paramValues.length - 1];
24
+ if (lastSegment.length === 1 && lastSegment[0].dynamic && lastParam === void 0) {
25
+ throw new AstroError({
26
+ ...AstroErrorData.PrerenderDynamicEndpointPathCollide,
27
+ message: AstroErrorData.PrerenderDynamicEndpointPathCollide.message(route.route),
28
+ hint: AstroErrorData.PrerenderDynamicEndpointPathCollide.hint(route.component),
29
+ location: {
30
+ file: route.component
31
+ }
32
+ });
33
+ }
34
+ }
20
35
  }
21
36
  }
22
37
  let routeCacheEntry = routeCache.get(route);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "2.1.7",
3
+ "version": "2.1.8",
4
4
  "description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
5
5
  "type": "module",
6
6
  "author": "withastro",