astro 3.5.4 → 3.5.6

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 (42) hide show
  1. package/components/ViewTransitions.astro +16 -8
  2. package/dist/@types/astro.d.ts +11 -1
  3. package/dist/cli/add/index.js +9 -1
  4. package/dist/core/app/index.js +24 -6
  5. package/dist/core/build/buildPipeline.js +5 -7
  6. package/dist/core/build/generate.js +83 -73
  7. package/dist/core/build/internal.d.ts +0 -6
  8. package/dist/core/build/internal.js +3 -16
  9. package/dist/core/build/page-data.js +18 -46
  10. package/dist/core/build/static-build.js +7 -9
  11. package/dist/core/build/types.d.ts +1 -1
  12. package/dist/core/constants.js +1 -1
  13. package/dist/core/dev/dev.js +1 -1
  14. package/dist/core/endpoint/index.d.ts +4 -2
  15. package/dist/core/endpoint/index.js +22 -4
  16. package/dist/core/messages.js +2 -2
  17. package/dist/core/middleware/index.js +3 -1
  18. package/dist/core/pipeline.d.ts +6 -0
  19. package/dist/core/pipeline.js +17 -8
  20. package/dist/core/render/context.d.ts +3 -0
  21. package/dist/core/render/context.js +18 -1
  22. package/dist/core/render/core.js +3 -1
  23. package/dist/core/render/result.d.ts +2 -0
  24. package/dist/core/render/result.js +23 -1
  25. package/dist/core/routing/manifest/create.js +25 -20
  26. package/dist/core/routing/manifest/serialization.js +7 -1
  27. package/dist/core/routing/match.js +4 -1
  28. package/dist/core/routing/params.js +1 -1
  29. package/dist/i18n/middleware.d.ts +5 -0
  30. package/dist/i18n/middleware.js +14 -3
  31. package/dist/runtime/client/dev-overlay/entrypoint.js +147 -6
  32. package/dist/runtime/client/dev-overlay/overlay.d.ts +4 -0
  33. package/dist/runtime/client/dev-overlay/overlay.js +20 -8
  34. package/dist/runtime/client/dev-overlay/plugins/settings.js +2 -2
  35. package/dist/runtime/client/dev-overlay/settings.d.ts +2 -2
  36. package/dist/runtime/client/dev-overlay/settings.js +1 -1
  37. package/dist/runtime/client/dev-overlay/ui-library/icons.d.ts +1 -0
  38. package/dist/runtime/client/dev-overlay/ui-library/icons.js +2 -1
  39. package/dist/runtime/client/dev-overlay/ui-library/toggle.d.ts +2 -0
  40. package/dist/runtime/client/dev-overlay/ui-library/toggle.js +6 -0
  41. package/dist/vite-plugin-astro-server/route.js +11 -4
  42. package/package.json +2 -2
@@ -30,6 +30,7 @@ const { fallback = 'animate', handleForms } = Astro.props;
30
30
  import type { Options } from 'astro:transitions/client';
31
31
  import { supportsViewTransitions, navigate } from 'astro:transitions/client';
32
32
  // NOTE: import from `astro/prefetch` as `astro:prefetch` requires the `prefetch` config to be enabled
33
+ // @ts-ignore
33
34
  import { init } from 'astro/prefetch';
34
35
 
35
36
  export type Fallback = 'none' | 'animate' | 'swap';
@@ -42,27 +43,34 @@ const { fallback = 'animate', handleForms } = Astro.props;
42
43
  return 'animate';
43
44
  }
44
45
 
45
- function isReloadEl(el: HTMLElement): boolean {
46
+ function isReloadEl(el: HTMLElement | SVGAElement): boolean {
46
47
  return el.dataset.astroReload !== undefined;
47
48
  }
48
49
 
49
50
  if (supportsViewTransitions || getFallback() !== 'none') {
50
51
  document.addEventListener('click', (ev) => {
51
52
  let link = ev.target;
52
- if (link instanceof Element && link.tagName !== 'A') {
53
- link = link.closest('a');
53
+ if (link instanceof Element) {
54
+ link = link.closest('a, area');
54
55
  }
56
+ if (
57
+ !(link instanceof HTMLAnchorElement) &&
58
+ !(link instanceof SVGAElement) &&
59
+ !(link instanceof HTMLAreaElement)
60
+ )
61
+ return;
55
62
  // This check verifies that the click is happening on an anchor
56
63
  // that is going to another page within the same origin. Basically it determines
57
64
  // same-origin navigation, but omits special key combos for new tabs, etc.
65
+ const linkTarget = link instanceof HTMLElement ? link.target : link.target.baseVal;
66
+ const href = link instanceof HTMLElement ? link.href : link.href.baseVal;
67
+ const origin = new URL(href, location.href).origin;
58
68
  if (
59
- !link ||
60
- !(link instanceof HTMLAnchorElement) ||
61
69
  isReloadEl(link) ||
62
70
  link.hasAttribute('download') ||
63
71
  !link.href ||
64
- (link.target && link.target !== '_self') ||
65
- link.origin !== location.origin ||
72
+ (linkTarget && linkTarget !== '_self') ||
73
+ origin !== location.origin ||
66
74
  ev.button !== 0 || // left clicks only
67
75
  ev.metaKey || // new tab (mac)
68
76
  ev.ctrlKey || // new tab (windows)
@@ -75,7 +83,7 @@ const { fallback = 'animate', handleForms } = Astro.props;
75
83
  return;
76
84
  }
77
85
  ev.preventDefault();
78
- navigate(link.href, {
86
+ navigate(href, {
79
87
  history: link.dataset.astroHistory === 'replace' ? 'replace' : 'auto',
80
88
  });
81
89
  });
@@ -1903,6 +1903,10 @@ interface AstroSharedContext<Props extends Record<string, any> = Record<string,
1903
1903
  * The list of locales computed from the `Accept-Language` header of the browser, sorted by quality value (**SSR Only**).
1904
1904
  */
1905
1905
  preferredLocaleList: string[] | undefined;
1906
+ /**
1907
+ * The current locale computed from the URL of the request. It matches the locales in `i18n.locales`, and returns `undefined` otherwise.
1908
+ */
1909
+ currentLocale: string | undefined;
1906
1910
  }
1907
1911
  export interface APIContext<Props extends Record<string, any> = Record<string, any>, APIParams extends Record<string, string | undefined> = Record<string, string | undefined>> extends AstroSharedContext<Props, Params> {
1908
1912
  site: URL | undefined;
@@ -2025,6 +2029,10 @@ export interface APIContext<Props extends Record<string, any> = Record<string, a
2025
2029
  * [quality value]: https://developer.mozilla.org/en-US/docs/Glossary/Quality_values
2026
2030
  */
2027
2031
  preferredLocaleList: string[] | undefined;
2032
+ /**
2033
+ * The current locale computed from the URL of the request. It matches the locales in `i18n.locales`, and returns `undefined` otherwise.
2034
+ */
2035
+ currentLocale: string | undefined;
2028
2036
  }
2029
2037
  export type EndpointOutput = {
2030
2038
  body: Body;
@@ -2178,14 +2186,16 @@ export interface RouteData {
2178
2186
  prerender: boolean;
2179
2187
  redirect?: RedirectConfig;
2180
2188
  redirectRoute?: RouteData;
2189
+ fallbackRoutes: RouteData[];
2181
2190
  }
2182
2191
  export type RedirectRouteData = RouteData & {
2183
2192
  redirect: string;
2184
2193
  };
2185
- export type SerializedRouteData = Omit<RouteData, 'generate' | 'pattern' | 'redirectRoute'> & {
2194
+ export type SerializedRouteData = Omit<RouteData, 'generate' | 'pattern' | 'redirectRoute' | 'fallbackRoutes'> & {
2186
2195
  generate: undefined;
2187
2196
  pattern: string;
2188
2197
  redirectRoute: SerializedRouteData | undefined;
2198
+ fallbackRoutes: SerializedRouteData[];
2189
2199
  _meta: {
2190
2200
  trailingSlash: AstroConfig['trailingSlash'];
2191
2201
  };
@@ -608,8 +608,10 @@ async function fetchPackageJson(scope, name, tag) {
608
608
  const res = await fetch(`${registry}/${packageName}/${tag}`);
609
609
  if (res.status >= 200 && res.status < 300) {
610
610
  return await res.json();
611
- } else {
611
+ } else if (res.status === 404) {
612
612
  return new Error();
613
+ } else {
614
+ return new Error(`Failed to fetch ${registry}/${packageName}/${tag} - GET ${res.status}`);
613
615
  }
614
616
  }
615
617
  async function validateIntegrations(integrations) {
@@ -629,6 +631,9 @@ async function validateIntegrations(integrations) {
629
631
  } else {
630
632
  const firstPartyPkgCheck = await fetchPackageJson("@astrojs", name, tag);
631
633
  if (firstPartyPkgCheck instanceof Error) {
634
+ if (firstPartyPkgCheck.message) {
635
+ spinner.warn(yellow(firstPartyPkgCheck.message));
636
+ }
632
637
  spinner.warn(
633
638
  yellow(`${bold(integration)} is not an official Astro package. Use at your own risk!`)
634
639
  );
@@ -655,6 +660,9 @@ async function validateIntegrations(integrations) {
655
660
  if (pkgType === "third-party") {
656
661
  const thirdPartyPkgCheck = await fetchPackageJson(scope, name, tag);
657
662
  if (thirdPartyPkgCheck instanceof Error) {
663
+ if (thirdPartyPkgCheck.message) {
664
+ spinner.warn(yellow(thirdPartyPkgCheck.message));
665
+ }
658
666
  throw new Error(`Unable to fetch ${bold(integration)}. Does the package exist?`);
659
667
  } else {
660
668
  pkgJson = thirdPartyPkgCheck;
@@ -1,4 +1,4 @@
1
- import { createI18nMiddleware } from "../../i18n/middleware.js";
1
+ import { createI18nMiddleware, i18nPipelineHook } from "../../i18n/middleware.js";
2
2
  import { getSetCookiesFromResponse } from "../cookies/index.js";
3
3
  import { consoleLogDestination } from "../logger/console.js";
4
4
  import { AstroIntegrationLogger, Logger } from "../logger/core.js";
@@ -96,6 +96,11 @@ class App {
96
96
  }
97
97
  return pathname;
98
98
  }
99
+ #getPathnameFromRequest(request) {
100
+ const url = new URL(request.url);
101
+ const pathname = prependForwardSlash(this.removeBase(url.pathname));
102
+ return pathname;
103
+ }
99
104
  match(request, _opts = {}) {
100
105
  const url = new URL(request.url);
101
106
  if (this.#manifest.assets.has(url.pathname))
@@ -117,7 +122,8 @@ class App {
117
122
  return this.#renderError(request, { status: 404 });
118
123
  }
119
124
  Reflect.set(request, clientLocalsSymbol, locals ?? {});
120
- const defaultStatus = this.#getDefaultStatusCode(routeData.route);
125
+ const pathname = this.#getPathnameFromRequest(request);
126
+ const defaultStatus = this.#getDefaultStatusCode(routeData, pathname);
121
127
  const mod = await this.#getModuleForRoute(routeData);
122
128
  const pageModule = await mod.page();
123
129
  const url = new URL(request.url);
@@ -143,6 +149,7 @@ class App {
143
149
  } else {
144
150
  this.#pipeline.setMiddlewareFunction(i18nMiddleware);
145
151
  }
152
+ this.#pipeline.onBeforeRenderRoute(i18nPipelineHook);
146
153
  } else {
147
154
  if (mod.onRequest) {
148
155
  this.#pipeline.setMiddlewareFunction(mod.onRequest);
@@ -187,7 +194,9 @@ class App {
187
194
  status,
188
195
  env: this.#pipeline.env,
189
196
  mod: handler,
190
- locales: this.#manifest.i18n ? this.#manifest.i18n.locales : void 0
197
+ locales: this.#manifest.i18n?.locales,
198
+ routingStrategy: this.#manifest.i18n?.routingStrategy,
199
+ defaultLocale: this.#manifest.i18n?.defaultLocale
191
200
  });
192
201
  } else {
193
202
  const pathname = prependForwardSlash(this.removeBase(url.pathname));
@@ -219,7 +228,9 @@ class App {
219
228
  status,
220
229
  mod,
221
230
  env: this.#pipeline.env,
222
- locales: this.#manifest.i18n ? this.#manifest.i18n.locales : void 0
231
+ locales: this.#manifest.i18n?.locales,
232
+ routingStrategy: this.#manifest.i18n?.routingStrategy,
233
+ defaultLocale: this.#manifest.i18n?.defaultLocale
223
234
  });
224
235
  }
225
236
  }
@@ -292,8 +303,15 @@ class App {
292
303
  headers: new Headers(Array.from(headers))
293
304
  });
294
305
  }
295
- #getDefaultStatusCode(route) {
296
- route = removeTrailingForwardSlash(route);
306
+ #getDefaultStatusCode(routeData, pathname) {
307
+ if (!routeData.pattern.exec(pathname)) {
308
+ for (const fallbackRoute of routeData.fallbackRoutes) {
309
+ if (fallbackRoute.pattern.test(pathname)) {
310
+ return 302;
311
+ }
312
+ }
313
+ }
314
+ const route = removeTrailingForwardSlash(routeData.route);
297
315
  if (route.endsWith("/404"))
298
316
  return 404;
299
317
  if (route.endsWith("/500"))
@@ -128,13 +128,11 @@ class BuildPipeline extends Pipeline {
128
128
  pages.set(pageData, filePath);
129
129
  }
130
130
  }
131
- for (const [path, pageDataList] of this.#internals.pagesByComponents.entries()) {
132
- for (const pageData of pageDataList) {
133
- if (routeIsRedirect(pageData.route)) {
134
- pages.set(pageData, path);
135
- } else if (routeIsFallback(pageData.route) && (i18nHasFallback(this.getConfig()) || routeIsFallback(pageData.route) && pageData.route.route === "/")) {
136
- pages.set(pageData, path);
137
- }
131
+ for (const [path, pageData] of this.#internals.pagesByComponent.entries()) {
132
+ if (routeIsRedirect(pageData.route)) {
133
+ pages.set(pageData, path);
134
+ } else if (routeIsFallback(pageData.route) && (i18nHasFallback(this.getConfig()) || routeIsFallback(pageData.route) && pageData.route.route === "/")) {
135
+ pages.set(pageData, path);
138
136
  }
139
137
  }
140
138
  return pages;
@@ -17,7 +17,7 @@ import {
17
17
  removeLeadingForwardSlash,
18
18
  removeTrailingForwardSlash
19
19
  } from "../../core/path.js";
20
- import { createI18nMiddleware } from "../../i18n/middleware.js";
20
+ import { createI18nMiddleware, i18nPipelineHook } from "../../i18n/middleware.js";
21
21
  import { runHookBuildGenerated } from "../../integrations/index.js";
22
22
  import { getOutputDirectory, isServerLikeOutput } from "../../prerender/utils.js";
23
23
  import { PAGE_SCRIPT_ID } from "../../vite-plugin-scripts/index.js";
@@ -194,15 +194,40 @@ ${bgGreen(black(` generating optimized images `))}`);
194
194
  });
195
195
  }
196
196
  async function generatePage(pageData, ssrEntry, builtPaths, pipeline) {
197
- let timeStart = performance.now();
198
197
  const logger = pipeline.getLogger();
199
198
  const config = pipeline.getConfig();
200
- const pageInfo = getPageDataByComponent(pipeline.getInternals(), pageData.route.component);
201
- const linkIds = [];
202
- const scripts = pageInfo?.hoistedScript ?? null;
203
- const styles = pageData.styles.sort(cssOrder).map(({ sheet }) => sheet).reduce(mergeInlineCss, []);
199
+ const manifest = pipeline.getManifest();
204
200
  const pageModulePromise = ssrEntry.page;
205
201
  const onRequest = ssrEntry.onRequest;
202
+ const pageInfo = getPageDataByComponent(pipeline.getInternals(), pageData.route.component);
203
+ const hoistedScripts = pageInfo?.hoistedScript ?? null;
204
+ const moduleStyles = pageData.styles.sort(cssOrder).map(({ sheet }) => sheet).reduce(mergeInlineCss, []);
205
+ const links = /* @__PURE__ */ new Set();
206
+ const styles = createStylesheetElementSet(moduleStyles, manifest.base, manifest.assetsPrefix);
207
+ const scripts = createModuleScriptsSet(
208
+ hoistedScripts ? [hoistedScripts] : [],
209
+ manifest.base,
210
+ manifest.assetsPrefix
211
+ );
212
+ if (pipeline.getSettings().scripts.some((script) => script.stage === "page")) {
213
+ const hashedFilePath = pipeline.getInternals().entrySpecifierToBundleMap.get(PAGE_SCRIPT_ID);
214
+ if (typeof hashedFilePath !== "string") {
215
+ throw new Error(`Cannot find the built path for ${PAGE_SCRIPT_ID}`);
216
+ }
217
+ const src = createAssetLink(hashedFilePath, manifest.base, manifest.assetsPrefix);
218
+ scripts.add({
219
+ props: { type: "module", src },
220
+ children: ""
221
+ });
222
+ }
223
+ for (const script of pipeline.getSettings().scripts) {
224
+ if (script.stage === "head-inline") {
225
+ scripts.add({
226
+ props: {},
227
+ children: script.content
228
+ });
229
+ }
230
+ }
206
231
  const i18nMiddleware = createI18nMiddleware(
207
232
  pipeline.getManifest().i18n,
208
233
  pipeline.getManifest().base,
@@ -216,6 +241,7 @@ async function generatePage(pageData, ssrEntry, builtPaths, pipeline) {
216
241
  } else {
217
242
  pipeline.setMiddlewareFunction(i18nMiddleware);
218
243
  }
244
+ pipeline.onBeforeRenderRoute(i18nPipelineHook);
219
245
  } else if (onRequest) {
220
246
  pipeline.setMiddlewareFunction(onRequest);
221
247
  }
@@ -233,42 +259,44 @@ async function generatePage(pageData, ssrEntry, builtPaths, pipeline) {
233
259
  );
234
260
  return;
235
261
  }
236
- const generationOptions = {
237
- pageData,
238
- linkIds,
239
- scripts,
240
- styles,
241
- mod: pageModule
242
- };
243
- const icon = pageData.route.type === "page" || pageData.route.type === "redirect" || pageData.route.type === "fallback" ? green("\u25B6") : magenta("\u03BB");
244
- if (isRelativePath(pageData.route.component)) {
245
- logger.info(null, `${icon} ${pageData.route.route}`);
246
- } else {
247
- logger.info(null, `${icon} ${pageData.route.component}`);
262
+ for (const route of eachRouteInRouteData(pageData)) {
263
+ const paths = await getPathsForRoute(route, pageModule, pipeline, builtPaths);
264
+ let timeStart = performance.now();
265
+ let prevTimeEnd = timeStart;
266
+ for (let i = 0; i < paths.length; i++) {
267
+ const path = paths[i];
268
+ pipeline.getEnvironment().logger.debug("build", `Generating: ${path}`);
269
+ await generatePath(path, pipeline, route, links, scripts, styles, pageModule);
270
+ const timeEnd = performance.now();
271
+ const timeChange = getTimeStat(prevTimeEnd, timeEnd);
272
+ const timeIncrease = `(+${timeChange})`;
273
+ const filePath = getOutputFilename(pipeline.getConfig(), path, pageData.route.type);
274
+ const lineIcon = i === paths.length - 1 ? "\u2514\u2500" : "\u251C\u2500";
275
+ logger.info(null, ` ${cyan(lineIcon)} ${dim(filePath)} ${dim(timeIncrease)}`);
276
+ prevTimeEnd = timeEnd;
277
+ }
248
278
  }
249
- const paths = await getPathsForRoute(pageData, pageModule, pipeline, builtPaths);
250
- let prevTimeEnd = timeStart;
251
- for (let i = 0; i < paths.length; i++) {
252
- const path = paths[i];
253
- await generatePath(path, generationOptions, pipeline);
254
- const timeEnd = performance.now();
255
- const timeChange = getTimeStat(prevTimeEnd, timeEnd);
256
- const timeIncrease = `(+${timeChange})`;
257
- const filePath = getOutputFilename(pipeline.getConfig(), path, pageData.route.type);
258
- const lineIcon = i === paths.length - 1 ? "\u2514\u2500" : "\u251C\u2500";
259
- logger.info(null, ` ${cyan(lineIcon)} ${dim(filePath)} ${dim(timeIncrease)}`);
260
- prevTimeEnd = timeEnd;
279
+ }
280
+ function* eachRouteInRouteData(data) {
281
+ yield data.route;
282
+ for (const fallbackRoute of data.route.fallbackRoutes) {
283
+ yield fallbackRoute;
261
284
  }
262
285
  }
263
- async function getPathsForRoute(pageData, mod, pipeline, builtPaths) {
286
+ async function getPathsForRoute(route, mod, pipeline, builtPaths) {
264
287
  const opts = pipeline.getStaticBuildOptions();
265
288
  const logger = pipeline.getLogger();
266
289
  let paths = [];
267
- if (pageData.route.pathname) {
268
- paths.push(pageData.route.pathname);
269
- builtPaths.add(pageData.route.pathname);
290
+ if (route.pathname) {
291
+ paths.push(route.pathname);
292
+ builtPaths.add(route.pathname);
293
+ for (const virtualRoute of route.fallbackRoutes) {
294
+ if (virtualRoute.pathname) {
295
+ paths.push(virtualRoute.pathname);
296
+ builtPaths.add(virtualRoute.pathname);
297
+ }
298
+ }
270
299
  } else {
271
- const route = pageData.route;
272
300
  const staticPaths = await callGetStaticPaths({
273
301
  mod,
274
302
  route,
@@ -352,38 +380,18 @@ function getUrlForPath(pathname, base, origin, format, routeType) {
352
380
  const url = new URL(buildPathname, origin);
353
381
  return url;
354
382
  }
355
- async function generatePath(pathname, gopts, pipeline) {
383
+ async function generatePath(pathname, pipeline, route, links, scripts, styles, mod) {
356
384
  const manifest = pipeline.getManifest();
357
- const { mod, scripts: hoistedScripts, styles: _styles, pageData } = gopts;
358
- if (pageData.route.type === "page") {
359
- addPageName(pathname, pipeline.getStaticBuildOptions());
360
- }
385
+ const logger = pipeline.getLogger();
361
386
  pipeline.getEnvironment().logger.debug("build", `Generating: ${pathname}`);
362
- const links = /* @__PURE__ */ new Set();
363
- const scripts = createModuleScriptsSet(
364
- hoistedScripts ? [hoistedScripts] : [],
365
- manifest.base,
366
- manifest.assetsPrefix
367
- );
368
- const styles = createStylesheetElementSet(_styles, manifest.base, manifest.assetsPrefix);
369
- if (pipeline.getSettings().scripts.some((script) => script.stage === "page")) {
370
- const hashedFilePath = pipeline.getInternals().entrySpecifierToBundleMap.get(PAGE_SCRIPT_ID);
371
- if (typeof hashedFilePath !== "string") {
372
- throw new Error(`Cannot find the built path for ${PAGE_SCRIPT_ID}`);
373
- }
374
- const src = createAssetLink(hashedFilePath, manifest.base, manifest.assetsPrefix);
375
- scripts.add({
376
- props: { type: "module", src },
377
- children: ""
378
- });
387
+ const icon = route.type === "page" || route.type === "redirect" || route.type === "fallback" ? green("\u25B6") : magenta("\u03BB");
388
+ if (isRelativePath(route.component)) {
389
+ logger.info(null, `${icon} ${route.route}`);
390
+ } else {
391
+ logger.info(null, `${icon} ${route.component}`);
379
392
  }
380
- for (const script of pipeline.getSettings().scripts) {
381
- if (script.stage === "head-inline") {
382
- scripts.add({
383
- props: {},
384
- children: script.content
385
- });
386
- }
393
+ if (route.type === "page") {
394
+ addPageName(pathname, pipeline.getStaticBuildOptions());
387
395
  }
388
396
  const ssr = isServerLikeOutput(pipeline.getConfig());
389
397
  const url = getUrlForPath(
@@ -391,7 +399,7 @@ async function generatePath(pathname, gopts, pipeline) {
391
399
  pipeline.getConfig().base,
392
400
  pipeline.getStaticBuildOptions().origin,
393
401
  pipeline.getConfig().build.format,
394
- pageData.route.type
402
+ route.type
395
403
  );
396
404
  const request = createRequest({
397
405
  url,
@@ -407,10 +415,12 @@ async function generatePath(pathname, gopts, pipeline) {
407
415
  scripts,
408
416
  styles,
409
417
  links,
410
- route: pageData.route,
418
+ route,
411
419
  env: pipeline.getEnvironment(),
412
420
  mod,
413
- locales: i18n ? i18n.locales : void 0
421
+ locales: i18n?.locales,
422
+ routingStrategy: i18n?.routingStrategy,
423
+ defaultLocale: i18n?.defaultLocale
414
424
  });
415
425
  let body;
416
426
  let encoding;
@@ -419,7 +429,7 @@ async function generatePath(pathname, gopts, pipeline) {
419
429
  response = await pipeline.renderRoute(renderContext, mod);
420
430
  } catch (err) {
421
431
  if (!AstroError.is(err) && !err.id && typeof err === "object") {
422
- err.id = pageData.component;
432
+ err.id = route.component;
423
433
  }
424
434
  throw err;
425
435
  }
@@ -443,8 +453,8 @@ async function generatePath(pathname, gopts, pipeline) {
443
453
  if (pipeline.getConfig().compressHTML === true) {
444
454
  body = body.replaceAll("\n", "");
445
455
  }
446
- if (pageData.route.type !== "redirect") {
447
- pageData.route.redirect = location.toString();
456
+ if (route.type !== "redirect") {
457
+ route.redirect = location.toString();
448
458
  }
449
459
  } else {
450
460
  if (!response.body)
@@ -452,9 +462,9 @@ async function generatePath(pathname, gopts, pipeline) {
452
462
  body = Buffer.from(await response.arrayBuffer());
453
463
  encoding = response.headers.get("X-Astro-Encoding") ?? "utf-8";
454
464
  }
455
- const outFolder = getOutFolder(pipeline.getConfig(), pathname, pageData.route.type);
456
- const outFile = getOutFile(pipeline.getConfig(), outFolder, pathname, pageData.route.type);
457
- pageData.route.distURL = outFile;
465
+ const outFolder = getOutFolder(pipeline.getConfig(), pathname, route.type);
466
+ const outFile = getOutFile(pipeline.getConfig(), outFolder, pathname, route.type);
467
+ route.distURL = outFile;
458
468
  await fs.promises.mkdir(outFolder, { recursive: true });
459
469
  await fs.promises.writeFile(outFile, body, encoding);
460
470
  }
@@ -20,14 +20,8 @@ export interface BuildInternals {
20
20
  pageToBundleMap: Map<string, string>;
21
21
  /**
22
22
  * A map for page-specific information.
23
- * // TODO: Remove in Astro 4.0
24
- * @deprecated
25
23
  */
26
24
  pagesByComponent: Map<string, PageBuildData>;
27
- /**
28
- * TODO: Use this in Astro 4.0
29
- */
30
- pagesByComponents: Map<string, PageBuildData[]>;
31
25
  /**
32
26
  * A map for page-specific output.
33
27
  */
@@ -1,5 +1,4 @@
1
1
  import { prependForwardSlash, removeFileExtension } from "../path.js";
2
- import { routeIsFallback } from "../redirects/helpers.js";
3
2
  import { viteID } from "../util.js";
4
3
  import {
5
4
  ASTRO_PAGE_RESOLVED_MODULE_ID,
@@ -18,7 +17,6 @@ function createBuildInternals() {
18
17
  entrySpecifierToBundleMap: /* @__PURE__ */ new Map(),
19
18
  pageToBundleMap: /* @__PURE__ */ new Map(),
20
19
  pagesByComponent: /* @__PURE__ */ new Map(),
21
- pagesByComponents: /* @__PURE__ */ new Map(),
22
20
  pageOptionsByPage: /* @__PURE__ */ new Map(),
23
21
  pagesByViteID: /* @__PURE__ */ new Map(),
24
22
  pagesByClientOnly: /* @__PURE__ */ new Map(),
@@ -35,16 +33,7 @@ function createBuildInternals() {
35
33
  }
36
34
  function trackPageData(internals, component, pageData, componentModuleId, componentURL) {
37
35
  pageData.moduleSpecifier = componentModuleId;
38
- if (!routeIsFallback(pageData.route)) {
39
- internals.pagesByComponent.set(component, pageData);
40
- }
41
- const list = internals.pagesByComponents.get(component);
42
- if (list) {
43
- list.push(pageData);
44
- internals.pagesByComponents.set(component, list);
45
- } else {
46
- internals.pagesByComponents.set(component, [pageData]);
47
- }
36
+ internals.pagesByComponent.set(component, pageData);
48
37
  internals.pagesByViteID.set(viteID(componentURL), pageData);
49
38
  }
50
39
  function trackClientOnlyPageDatas(internals, pageData, clientOnlys) {
@@ -105,10 +94,8 @@ function* eachPageData(internals) {
105
94
  yield* internals.pagesByComponent.values();
106
95
  }
107
96
  function* eachPageFromAllPages(allPages) {
108
- for (const [path, list] of Object.entries(allPages)) {
109
- for (const pageData of list) {
110
- yield [path, pageData];
111
- }
97
+ for (const [path, pageData] of Object.entries(allPages)) {
98
+ yield [path, pageData];
112
99
  }
113
100
  }
114
101
  function* eachPageDataFromEntryPoint(internals) {
@@ -21,29 +21,15 @@ async function collectPagesData(opts) {
21
21
  clearInterval(routeCollectionLogTimeout);
22
22
  }, 1e4);
23
23
  builtPaths.add(route.pathname);
24
- if (allPages[route.component]) {
25
- allPages[route.component].push({
26
- component: route.component,
27
- route,
28
- moduleSpecifier: "",
29
- styles: [],
30
- propagatedStyles: /* @__PURE__ */ new Map(),
31
- propagatedScripts: /* @__PURE__ */ new Map(),
32
- hoistedScript: void 0
33
- });
34
- } else {
35
- allPages[route.component] = [
36
- {
37
- component: route.component,
38
- route,
39
- moduleSpecifier: "",
40
- styles: [],
41
- propagatedStyles: /* @__PURE__ */ new Map(),
42
- propagatedScripts: /* @__PURE__ */ new Map(),
43
- hoistedScript: void 0
44
- }
45
- ];
46
- }
24
+ allPages[route.component] = {
25
+ component: route.component,
26
+ route,
27
+ moduleSpecifier: "",
28
+ styles: [],
29
+ propagatedStyles: /* @__PURE__ */ new Map(),
30
+ propagatedScripts: /* @__PURE__ */ new Map(),
31
+ hoistedScript: void 0
32
+ };
47
33
  clearInterval(routeCollectionLogTimeout);
48
34
  if (settings.config.output === "static") {
49
35
  const html = `${route.pathname}`.replace(/\/?$/, "/index.html");
@@ -56,29 +42,15 @@ async function collectPagesData(opts) {
56
42
  }
57
43
  continue;
58
44
  }
59
- if (allPages[route.component]) {
60
- allPages[route.component].push({
61
- component: route.component,
62
- route,
63
- moduleSpecifier: "",
64
- styles: [],
65
- propagatedStyles: /* @__PURE__ */ new Map(),
66
- propagatedScripts: /* @__PURE__ */ new Map(),
67
- hoistedScript: void 0
68
- });
69
- } else {
70
- allPages[route.component] = [
71
- {
72
- component: route.component,
73
- route,
74
- moduleSpecifier: "",
75
- styles: [],
76
- propagatedStyles: /* @__PURE__ */ new Map(),
77
- propagatedScripts: /* @__PURE__ */ new Map(),
78
- hoistedScript: void 0
79
- }
80
- ];
81
- }
45
+ allPages[route.component] = {
46
+ component: route.component,
47
+ route,
48
+ moduleSpecifier: "",
49
+ styles: [],
50
+ propagatedStyles: /* @__PURE__ */ new Map(),
51
+ propagatedScripts: /* @__PURE__ */ new Map(),
52
+ hoistedScript: void 0
53
+ };
82
54
  }
83
55
  clearInterval(dataCollectionLogTimeout);
84
56
  return { assets, allPages };
@@ -39,14 +39,12 @@ async function viteBuild(opts) {
39
39
  settings.timer.start("SSR build");
40
40
  const pageInput = /* @__PURE__ */ new Set();
41
41
  const internals = createBuildInternals();
42
- for (const [component, pageDataList] of Object.entries(allPages)) {
43
- for (const pageData of pageDataList) {
44
- const astroModuleURL = new URL("./" + component, settings.config.root);
45
- const astroModuleId = prependForwardSlash(component);
46
- trackPageData(internals, component, pageData, astroModuleId, astroModuleURL);
47
- if (!routeIsRedirect(pageData.route)) {
48
- pageInput.add(astroModuleId);
49
- }
42
+ for (const [component, pageData] of Object.entries(allPages)) {
43
+ const astroModuleURL = new URL("./" + component, settings.config.root);
44
+ const astroModuleId = prependForwardSlash(component);
45
+ trackPageData(internals, component, pageData, astroModuleId, astroModuleURL);
46
+ if (!routeIsRedirect(pageData.route)) {
47
+ pageInput.add(astroModuleId);
50
48
  }
51
49
  }
52
50
  if (settings.config?.vite?.build?.emptyOutDir !== false) {
@@ -108,7 +106,7 @@ async function ssrBuild(opts, internals, input, container) {
108
106
  const { allPages, settings, viteConfig } = opts;
109
107
  const ssr = isServerLikeOutput(settings.config);
110
108
  const out = getOutputDirectory(settings.config);
111
- const routes = Object.values(allPages).flat().map((pageData) => pageData.route);
109
+ const routes = Object.values(allPages).flatMap((pageData) => pageData.route);
112
110
  const isContentCache = !ssr && settings.config.experimental.contentCollectionCache;
113
111
  const { lastVitePlugins, vitePlugins } = await container.runBeforeHook("server", input);
114
112
  const viteBuildConfig = {
@@ -29,7 +29,7 @@ export interface PageBuildData {
29
29
  sheet: StylesheetAsset;
30
30
  }>;
31
31
  }
32
- export type AllPagesData = Record<ComponentPath, PageBuildData[]>;
32
+ export type AllPagesData = Record<ComponentPath, PageBuildData>;
33
33
  /** Options for the static build */
34
34
  export interface StaticBuildOptions {
35
35
  allPages: AllPagesData;
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "3.5.4";
1
+ const ASTRO_VERSION = "3.5.6";
2
2
  const SUPPORTED_MARKDOWN_FILE_EXTENSIONS = [
3
3
  ".markdown",
4
4
  ".mdown",
@@ -20,7 +20,7 @@ async function dev(inlineConfig) {
20
20
  base: restart.container.settings.config.base
21
21
  })
22
22
  );
23
- const currentVersion = "3.5.4";
23
+ const currentVersion = "3.5.6";
24
24
  if (currentVersion.includes("-")) {
25
25
  logger.warn(null, msg.prerelease({ currentVersion }));
26
26
  }