astro 3.4.4 → 3.5.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 (143) hide show
  1. package/client.d.ts +86 -0
  2. package/components/Code.astro +15 -2
  3. package/components/Picture.astro +2 -1
  4. package/components/ViewTransitions.astro +39 -38
  5. package/content-module.template.mjs +4 -14
  6. package/dist/@types/astro.d.ts +227 -5
  7. package/dist/assets/build/generate.d.ts +2 -1
  8. package/dist/assets/build/generate.js +16 -5
  9. package/dist/assets/consts.d.ts +1 -0
  10. package/dist/assets/consts.js +2 -0
  11. package/dist/assets/endpoint/generic.js +6 -2
  12. package/dist/assets/internal.js +9 -2
  13. package/dist/assets/services/service.d.ts +8 -3
  14. package/dist/assets/services/service.js +2 -1
  15. package/dist/assets/services/vendor/squoosh/image-pool.d.ts +1 -2
  16. package/dist/assets/types.d.ts +9 -5
  17. package/dist/assets/utils/emitAsset.js +5 -0
  18. package/dist/assets/utils/metadata.d.ts +1 -2
  19. package/dist/assets/utils/proxy.d.ts +1 -0
  20. package/dist/assets/utils/proxy.js +16 -0
  21. package/dist/assets/utils/queryParams.d.ts +1 -1
  22. package/dist/assets/utils/transformToPath.d.ts +1 -1
  23. package/dist/assets/utils/transformToPath.js +8 -3
  24. package/dist/assets/vite-plugin-assets.js +33 -12
  25. package/dist/cli/build/index.js +1 -1
  26. package/dist/cli/info/index.js +7 -3
  27. package/dist/content/consts.d.ts +1 -0
  28. package/dist/content/consts.js +2 -0
  29. package/dist/content/runtime-assets.d.ts +9 -1
  30. package/dist/content/runtime-assets.js +1 -1
  31. package/dist/content/runtime.d.ts +1 -0
  32. package/dist/content/runtime.js +8 -2
  33. package/dist/content/utils.d.ts +1 -0
  34. package/dist/content/utils.js +9 -0
  35. package/dist/content/vite-plugin-content-assets.js +49 -23
  36. package/dist/content/vite-plugin-content-imports.js +9 -3
  37. package/dist/content/vite-plugin-content-virtual-mod.d.ts +17 -12
  38. package/dist/content/vite-plugin-content-virtual-mod.js +136 -57
  39. package/dist/core/app/index.js +19 -4
  40. package/dist/core/app/types.d.ts +7 -1
  41. package/dist/core/build/buildPipeline.js +17 -4
  42. package/dist/core/build/common.js +2 -0
  43. package/dist/core/build/generate.js +64 -34
  44. package/dist/core/build/index.d.ts +0 -8
  45. package/dist/core/build/index.js +9 -2
  46. package/dist/core/build/internal.d.ts +11 -1
  47. package/dist/core/build/internal.js +23 -1
  48. package/dist/core/build/page-data.js +46 -18
  49. package/dist/core/build/plugin.d.ts +12 -10
  50. package/dist/core/build/plugin.js +14 -22
  51. package/dist/core/build/plugins/index.js +4 -0
  52. package/dist/core/build/plugins/plugin-alias-resolve.js +1 -1
  53. package/dist/core/build/plugins/plugin-analyzer.js +1 -1
  54. package/dist/core/build/plugins/plugin-chunks.d.ts +4 -0
  55. package/dist/core/build/plugins/plugin-chunks.js +31 -0
  56. package/dist/core/build/plugins/plugin-component-entry.js +1 -1
  57. package/dist/core/build/plugins/plugin-content.d.ts +4 -0
  58. package/dist/core/build/plugins/plugin-content.js +273 -0
  59. package/dist/core/build/plugins/plugin-css.js +9 -4
  60. package/dist/core/build/plugins/plugin-hoisted-scripts.js +1 -1
  61. package/dist/core/build/plugins/plugin-internals.js +1 -1
  62. package/dist/core/build/plugins/plugin-manifest.js +14 -5
  63. package/dist/core/build/plugins/plugin-middleware.d.ts +1 -3
  64. package/dist/core/build/plugins/plugin-middleware.js +5 -57
  65. package/dist/core/build/plugins/plugin-pages.js +3 -3
  66. package/dist/core/build/plugins/plugin-prerender.js +2 -5
  67. package/dist/core/build/plugins/plugin-renderers.js +1 -1
  68. package/dist/core/build/plugins/plugin-ssr.js +6 -5
  69. package/dist/core/build/plugins/util.d.ts +3 -3
  70. package/dist/core/build/static-build.d.ts +2 -1
  71. package/dist/core/build/static-build.js +52 -28
  72. package/dist/core/build/types.d.ts +1 -1
  73. package/dist/core/build/util.d.ts +7 -0
  74. package/dist/core/build/util.js +37 -1
  75. package/dist/core/compile/compile.js +1 -0
  76. package/dist/core/config/config.js +3 -0
  77. package/dist/core/config/schema.d.ts +208 -0
  78. package/dist/core/config/schema.js +55 -2
  79. package/dist/core/config/settings.js +1 -0
  80. package/dist/core/constants.js +1 -1
  81. package/dist/core/create-vite.js +9 -3
  82. package/dist/core/dev/dev.js +1 -1
  83. package/dist/core/endpoint/index.d.ts +4 -3
  84. package/dist/core/endpoint/index.js +29 -3
  85. package/dist/core/errors/errors-data.d.ts +11 -0
  86. package/dist/core/errors/errors-data.js +17 -0
  87. package/dist/core/logger/node.js +1 -0
  88. package/dist/core/messages.js +2 -2
  89. package/dist/core/middleware/index.d.ts +7 -3
  90. package/dist/core/middleware/index.js +3 -2
  91. package/dist/core/middleware/loadMiddleware.d.ts +1 -2
  92. package/dist/core/middleware/loadMiddleware.js +3 -4
  93. package/dist/core/middleware/sequence.d.ts +2 -2
  94. package/dist/core/middleware/sequence.js +3 -2
  95. package/dist/core/middleware/vite-plugin.d.ts +9 -0
  96. package/dist/core/middleware/vite-plugin.js +101 -0
  97. package/dist/core/pipeline.d.ts +1 -1
  98. package/dist/core/pipeline.js +6 -4
  99. package/dist/core/redirects/helpers.d.ts +1 -0
  100. package/dist/core/redirects/helpers.js +4 -0
  101. package/dist/core/render/context.d.ts +24 -1
  102. package/dist/core/render/context.js +96 -2
  103. package/dist/core/render/core.d.ts +2 -14
  104. package/dist/core/render/core.js +12 -52
  105. package/dist/core/render/index.d.ts +2 -3
  106. package/dist/core/render/index.js +3 -4
  107. package/dist/core/render/params-and-props.d.ts +1 -1
  108. package/dist/core/render/params-and-props.js +5 -2
  109. package/dist/core/render/result.d.ts +1 -0
  110. package/dist/core/render/result.js +23 -0
  111. package/dist/core/render/route-cache.d.ts +1 -1
  112. package/dist/core/render/route-cache.js +6 -2
  113. package/dist/core/routing/manifest/create.js +117 -4
  114. package/dist/core/sync/index.d.ts +2 -24
  115. package/dist/i18n/index.d.ts +54 -0
  116. package/dist/i18n/index.js +91 -0
  117. package/dist/i18n/middleware.d.ts +2 -0
  118. package/dist/i18n/middleware.js +62 -0
  119. package/dist/i18n/vite-plugin-i18n.d.ts +7 -0
  120. package/dist/i18n/vite-plugin-i18n.js +62 -0
  121. package/dist/integrations/astroFeaturesValidation.js +4 -1
  122. package/dist/integrations/index.js +12 -0
  123. package/dist/prefetch/index.d.ts +31 -0
  124. package/dist/prefetch/index.js +176 -0
  125. package/dist/prefetch/vite-plugin-prefetch.d.ts +5 -0
  126. package/dist/prefetch/vite-plugin-prefetch.js +43 -0
  127. package/dist/runtime/client/dev-overlay/plugins/audit.js +17 -9
  128. package/dist/runtime/server/index.d.ts +0 -2
  129. package/dist/runtime/server/render/component.js +3 -5
  130. package/dist/transitions/router.d.ts +1 -0
  131. package/dist/transitions/router.js +9 -4
  132. package/dist/transitions/vite-plugin-transitions.d.ts +4 -1
  133. package/dist/transitions/vite-plugin-transitions.js +7 -1
  134. package/dist/vite-plugin-astro-server/devPipeline.d.ts +1 -0
  135. package/dist/vite-plugin-astro-server/devPipeline.js +2 -0
  136. package/dist/vite-plugin-astro-server/plugin.js +11 -1
  137. package/dist/vite-plugin-astro-server/route.js +113 -51
  138. package/dist/vite-plugin-head/index.js +1 -1
  139. package/dist/vite-plugin-markdown/index.js +1 -0
  140. package/package.json +8 -6
  141. package/tsconfigs/base.json +1 -1
  142. package/dist/core/endpoint/dev/index.d.ts +0 -2
  143. package/dist/core/endpoint/dev/index.js +0 -17
package/client.d.ts CHANGED
@@ -119,6 +119,92 @@ declare module 'astro:transitions/client' {
119
119
  export const supportsViewTransitions: TransitionRouterModule['supportsViewTransitions'];
120
120
  export const transitionEnabledOnThisPage: TransitionRouterModule['transitionEnabledOnThisPage'];
121
121
  export const navigate: TransitionRouterModule['navigate'];
122
+ export type Options = import('./dist/transitions/router.js').Options;
123
+ }
124
+
125
+ declare module 'astro:prefetch' {
126
+ export { prefetch, PrefetchOptions } from 'astro/prefetch';
127
+ }
128
+
129
+ declare module 'astro:i18n' {
130
+ export type GetLocaleOptions = import('./dist/i18n/index.js').GetLocaleOptions;
131
+
132
+ /**
133
+ * @param {string} locale A locale
134
+ * @param {string} [path=""] An optional path to add after the `locale`.
135
+ * @param {import('./dist/i18n/index.js').GetLocaleOptions} options Customise the generated path
136
+ * @return {string}
137
+ *
138
+ * Returns a _relative_ path with passed locale.
139
+ *
140
+ * ## Errors
141
+ *
142
+ * Throws an error if the locale doesn't exist in the list of locales defined in the configuration.
143
+ *
144
+ * ## Examples
145
+ *
146
+ * ```js
147
+ * import { getRelativeLocaleUrl } from "astro:i18n";
148
+ * getRelativeLocaleUrl("es"); // /es
149
+ * getRelativeLocaleUrl("es", "getting-started"); // /es/getting-started
150
+ * getRelativeLocaleUrl("es_US", "getting-started", { prependWith: "blog" }); // /blog/es-us/getting-started
151
+ * getRelativeLocaleUrl("es_US", "getting-started", { prependWith: "blog", normalizeLocale: false }); // /blog/es_US/getting-started
152
+ * ```
153
+ */
154
+ export const getRelativeLocaleUrl: (
155
+ locale: string,
156
+ path?: string,
157
+ options?: GetLocaleOptions
158
+ ) => string;
159
+
160
+ /**
161
+ *
162
+ * @param {string} locale A locale
163
+ * @param {string} [path=""] An optional path to add after the `locale`.
164
+ * @param {import('./dist/i18n/index.js').GetLocaleOptions} options Customise the generated path
165
+ * @return {string}
166
+ *
167
+ * Returns an absolute path with the passed locale. The behaviour is subject to change based on `site` configuration.
168
+ * If _not_ provided, the function will return a _relative_ URL.
169
+ *
170
+ * ## Errors
171
+ *
172
+ * Throws an error if the locale doesn't exist in the list of locales defined in the configuration.
173
+ *
174
+ * ## Examples
175
+ *
176
+ * If `site` is `https://example.com`:
177
+ *
178
+ * ```js
179
+ * import { getAbsoluteLocaleUrl } from "astro:i18n";
180
+ * getAbsoluteLocaleUrl("es"); // https://example.com/es
181
+ * getAbsoluteLocaleUrl("es", "getting-started"); // https://example.com/es/getting-started
182
+ * getAbsoluteLocaleUrl("es_US", "getting-started", { prependWith: "blog" }); // https://example.com/blog/es-us/getting-started
183
+ * getAbsoluteLocaleUrl("es_US", "getting-started", { prependWith: "blog", normalizeLocale: false }); // https://example.com/blog/es_US/getting-started
184
+ * ```
185
+ */
186
+ export const getAbsoluteLocaleUrl: (
187
+ locale: string,
188
+ path?: string,
189
+ options?: GetLocaleOptions
190
+ ) => string;
191
+
192
+ /**
193
+ * @param {string} [path=""] An optional path to add after the `locale`.
194
+ * @param {import('./dist/i18n/index.js').GetLocaleOptions} options Customise the generated path
195
+ * @return {string[]}
196
+ *
197
+ * Works like `getRelativeLocaleUrl` but it emits the relative URLs for ALL locales:
198
+ */
199
+ export const getRelativeLocaleUrlList: (path?: string, options?: GetLocaleOptions) => string[];
200
+ /**
201
+ * @param {string} [path=""] An optional path to add after the `locale`.
202
+ * @param {import('./dist/i18n/index.js').GetLocaleOptions} options Customise the generated path
203
+ * @return {string[]}
204
+ *
205
+ * Works like `getAbsoluteLocaleUrl` but it emits the absolute URLs for ALL locales:
206
+ */
207
+ export const getAbsoluteLocaleUrlList: (path?: string, options?: GetLocaleOptions) => string[];
122
208
  }
123
209
 
124
210
  declare module 'astro:middleware' {
@@ -32,6 +32,11 @@ interface Props {
32
32
  * @default "github-dark"
33
33
  */
34
34
  theme?: BuiltinTheme | ThemeRegistration | ThemeRegistrationRaw;
35
+ /**
36
+ * Multiple themes to style with -- alternative to "theme" option.
37
+ * Supports all themes found above; see https://github.com/antfu/shikiji#lightdark-dual-themes for more information.
38
+ */
39
+ experimentalThemes?: Record<string, BuiltinTheme | ThemeRegistration | ThemeRegistrationRaw>;
35
40
  /**
36
41
  * Enable word wrapping.
37
42
  * - true: enabled.
@@ -53,6 +58,7 @@ const {
53
58
  code,
54
59
  lang = 'plaintext',
55
60
  theme = 'github-dark',
61
+ experimentalThemes = {},
56
62
  wrap = false,
57
63
  inline = false,
58
64
  } = Astro.props;
@@ -88,12 +94,15 @@ if (typeof lang === 'object') {
88
94
 
89
95
  const highlighter = await getCachedHighlighter({
90
96
  langs: [lang],
91
- themes: [theme],
97
+ themes: Object.values(experimentalThemes).length ? Object.values(experimentalThemes) : [theme],
92
98
  });
93
99
 
100
+ const themeOptions = Object.values(experimentalThemes).length
101
+ ? { themes: experimentalThemes }
102
+ : { theme };
94
103
  const html = highlighter.codeToHtml(code, {
95
104
  lang: typeof lang === 'string' ? lang : lang.name,
96
- theme,
105
+ ...themeOptions,
97
106
  transforms: {
98
107
  pre(node) {
99
108
  // Swap to `code` tag if inline
@@ -123,6 +132,10 @@ const html = highlighter.codeToHtml(code, {
123
132
  }
124
133
  },
125
134
  root(node) {
135
+ if (Object.values(experimentalThemes).length) {
136
+ return;
137
+ }
138
+
126
139
  // theme.id for shiki -> shikiji compat
127
140
  const themeName = typeof theme === 'string' ? theme : theme.name;
128
141
  if (themeName === 'css-variables') {
@@ -17,8 +17,9 @@ const defaultFallbackFormat = 'png' as const;
17
17
  // Certain formats don't want PNG fallbacks:
18
18
  // - GIF will typically want to stay as a gif, either for animation or for the lower amount of colors
19
19
  // - SVGs can't be converted to raster formats in most cases
20
+ // - JPEGs compress photographs and high-noise images better than PNG in most cases
20
21
  // For those, we'll use the original format as the fallback instead.
21
- const specialFormatsFallback = ['gif', 'svg'] as const;
22
+ const specialFormatsFallback = ['gif', 'svg', 'jpg', 'jpeg'] as const;
22
23
 
23
24
  const { formats = defaultFormats, pictureAttributes = {}, fallbackFormat, ...props } = Astro.props;
24
25
 
@@ -3,9 +3,10 @@ type Fallback = 'none' | 'animate' | 'swap';
3
3
 
4
4
  export interface Props {
5
5
  fallback?: Fallback;
6
+ handleForms?: boolean;
6
7
  }
7
8
 
8
- const { fallback = 'animate' } = Astro.props;
9
+ const { fallback = 'animate', handleForms } = Astro.props;
9
10
  ---
10
11
 
11
12
  <style is:global>
@@ -24,12 +25,13 @@ const { fallback = 'animate' } = Astro.props;
24
25
  </style>
25
26
  <meta name="astro-view-transitions-enabled" content="true" />
26
27
  <meta name="astro-view-transitions-fallback" content={fallback} />
28
+ {handleForms ? <meta name="astro-view-transitions-forms" content="true" /> : ''}
27
29
  <script>
28
- import {
29
- supportsViewTransitions,
30
- transitionEnabledOnThisPage,
31
- navigate,
32
- } from 'astro:transitions/client';
30
+ import type { Options } from 'astro:transitions/client';
31
+ import { supportsViewTransitions, navigate } from 'astro:transitions/client';
32
+ // NOTE: import from `astro/prefetch` as `astro:prefetch` requires the `prefetch` config to be enabled
33
+ import { init } from 'astro/prefetch';
34
+
33
35
  export type Fallback = 'none' | 'animate' | 'swap';
34
36
 
35
37
  function getFallback(): Fallback {
@@ -40,19 +42,8 @@ const { fallback = 'animate' } = Astro.props;
40
42
  return 'animate';
41
43
  }
42
44
 
43
- // Prefetching
44
- function maybePrefetch(pathname: string) {
45
- if (document.querySelector(`link[rel=prefetch][href="${pathname}"]`)) return;
46
- // @ts-expect-error: connection might exist
47
- if (navigator.connection) {
48
- // @ts-expect-error: connection does exist
49
- let conn = navigator.connection;
50
- if (conn.saveData || /(2|3)g/.test(conn.effectiveType || '')) return;
51
- }
52
- let link = document.createElement('link');
53
- link.setAttribute('rel', 'prefetch');
54
- link.setAttribute('href', pathname);
55
- document.head.append(link);
45
+ function isReloadEl(el: HTMLElement): boolean {
46
+ return el.dataset.astroReload !== undefined;
56
47
  }
57
48
 
58
49
  if (supportsViewTransitions || getFallback() !== 'none') {
@@ -67,7 +58,7 @@ const { fallback = 'animate' } = Astro.props;
67
58
  if (
68
59
  !link ||
69
60
  !(link instanceof HTMLAnchorElement) ||
70
- link.dataset.astroReload !== undefined ||
61
+ isReloadEl(link) ||
71
62
  link.hasAttribute('download') ||
72
63
  !link.href ||
73
64
  (link.target && link.target !== '_self') ||
@@ -89,23 +80,33 @@ const { fallback = 'animate' } = Astro.props;
89
80
  });
90
81
  });
91
82
 
92
- ['mouseenter', 'touchstart', 'focus'].forEach((evName) => {
93
- document.addEventListener(
94
- evName,
95
- (ev) => {
96
- if (ev.target instanceof HTMLAnchorElement) {
97
- let el = ev.target;
98
- if (
99
- el.origin === location.origin &&
100
- el.pathname !== location.pathname &&
101
- transitionEnabledOnThisPage()
102
- ) {
103
- maybePrefetch(el.pathname);
104
- }
105
- }
106
- },
107
- { passive: true, capture: true }
108
- );
109
- });
83
+ if (document.querySelector('[name="astro-view-transitions-forms"]')) {
84
+ document.addEventListener('submit', (ev) => {
85
+ let el = ev.target as HTMLElement;
86
+ if (el.tagName !== 'FORM' || isReloadEl(el)) {
87
+ return;
88
+ }
89
+
90
+ const form = el as HTMLFormElement;
91
+ const formData = new FormData(form);
92
+ let action = form.action;
93
+ const options: Options = {};
94
+ if (form.method === 'get') {
95
+ const params = new URLSearchParams(formData as any);
96
+ const url = new URL(action);
97
+ url.search = params.toString();
98
+ action = url.toString();
99
+ } else {
100
+ options.formData = formData;
101
+ }
102
+ ev.preventDefault();
103
+ navigate(action, options);
104
+ });
105
+ }
106
+
107
+ // @ts-expect-error injected by vite-plugin-transitions for treeshaking
108
+ if (!__PREFETCH_DISABLED__) {
109
+ init({ prefetchAll: true });
110
+ }
110
111
  }
111
112
  </script>
@@ -9,21 +9,18 @@ import {
9
9
  createReference,
10
10
  } from 'astro/content/runtime';
11
11
 
12
+ export { defineCollection } from 'astro/content/runtime';
12
13
  export { z } from 'astro/zod';
13
14
 
14
15
  const contentDir = '@@CONTENT_DIR@@';
15
16
 
16
- const contentEntryGlob = import.meta.glob('@@CONTENT_ENTRY_GLOB_PATH@@', {
17
- query: { astroContentCollectionEntry: true },
18
- });
17
+ const contentEntryGlob = '@@CONTENT_ENTRY_GLOB_PATH@@';
19
18
  const contentCollectionToEntryMap = createCollectionToGlobResultMap({
20
19
  globResult: contentEntryGlob,
21
20
  contentDir,
22
21
  });
23
22
 
24
- const dataEntryGlob = import.meta.glob('@@DATA_ENTRY_GLOB_PATH@@', {
25
- query: { astroDataCollectionEntry: true },
26
- });
23
+ const dataEntryGlob = '@@DATA_ENTRY_GLOB_PATH@@';
27
24
  const dataCollectionToEntryMap = createCollectionToGlobResultMap({
28
25
  globResult: dataEntryGlob,
29
26
  contentDir,
@@ -45,19 +42,12 @@ function createGlobLookup(glob) {
45
42
  };
46
43
  }
47
44
 
48
- const renderEntryGlob = import.meta.glob('@@RENDER_ENTRY_GLOB_PATH@@', {
49
- query: { astroRenderContent: true },
50
- });
45
+ const renderEntryGlob = '@@RENDER_ENTRY_GLOB_PATH@@';
51
46
  const collectionToRenderEntryMap = createCollectionToGlobResultMap({
52
47
  globResult: renderEntryGlob,
53
48
  contentDir,
54
49
  });
55
50
 
56
- export function defineCollection(config) {
57
- if (!config.type) config.type = 'content';
58
- return config;
59
- }
60
-
61
51
  export const getCollection = createGetCollection({
62
52
  contentCollectionToEntryMap,
63
53
  dataCollectionToEntryMap,
@@ -464,6 +464,67 @@ export interface AstroUserConfig {
464
464
  * ```
465
465
  */
466
466
  redirects?: Record<string, RedirectConfig>;
467
+ /**
468
+ * @docs
469
+ * @name prefetch
470
+ * @type {boolean | object}
471
+ * @description
472
+ * Enable prefetching for links on your site to provide faster page transitions.
473
+ * (Enabled by default on pages using the `<ViewTransitions />` router. Set `prefetch: false` to opt out of this behaviour.)
474
+ *
475
+ * This configuration automatically adds a prefetch script to every page in the project
476
+ * giving you access to the `data-astro-prefetch` attribute.
477
+ * Add this attribute to any `<a />` link on your page to enable prefetching for that page.
478
+ *
479
+ * ```html
480
+ * <a href="/about" data-astro-prefetch>About</a>
481
+ * ```
482
+ * Further customize the default prefetching behavior using the [`prefetch.defaultStrategy`](#prefetchdefaultstrategy) and [`prefetch.prefetchAll`](#prefetchprefetchall) options.
483
+ *
484
+ * See the [Prefetch guide](https://docs.astro.build/en/guides/prefetch/) for more information.
485
+ */
486
+ prefetch?: boolean | {
487
+ /**
488
+ * @docs
489
+ * @name prefetch.prefetchAll
490
+ * @type {boolean}
491
+ * @description
492
+ * Enable prefetching for all links, including those without the `data-astro-prefetch` attribute.
493
+ * This value defaults to `true` when using the `<ViewTransitions />` router. Otherwise, the default value is `false`.
494
+ *
495
+ * ```js
496
+ * prefetch: {
497
+ * prefetchAll: true
498
+ * }
499
+ * ```
500
+ *
501
+ * When set to `true`, you can disable prefetching individually by setting `data-astro-prefetch="false"` on any individual links.
502
+ *
503
+ * ```html
504
+ * <a href="/about" data-astro-prefetch="false">About</a>
505
+ *```
506
+ */
507
+ prefetchAll?: boolean;
508
+ /**
509
+ * @docs
510
+ * @name prefetch.defaultStrategy
511
+ * @type {'tap' | 'hover' | 'viewport'}
512
+ * @default `'hover'`
513
+ * @description
514
+ * The default prefetch strategy to use when the `data-astro-prefetch` attribute is set on a link with no value.
515
+ *
516
+ * - `'tap'`: Prefetch just before you click on the link.
517
+ * - `'hover'`: Prefetch when you hover over or focus on the link. (default)
518
+ * - `'viewport'`: Prefetch as the links enter the viewport.
519
+ *
520
+ * You can override this default value and select a different strategy for any individual link by setting a value on the attribute.
521
+ *
522
+ * ```html
523
+ * <a href="/about" data-astro-prefetch="viewport">About</a>
524
+ * ```
525
+ */
526
+ defaultStrategy?: 'tap' | 'hover' | 'viewport';
527
+ };
467
528
  /**
468
529
  * @docs
469
530
  * @name site
@@ -1275,6 +1336,112 @@ export interface AstroUserConfig {
1275
1336
  * ```
1276
1337
  */
1277
1338
  devOverlay?: boolean;
1339
+ /**
1340
+ * @docs
1341
+ * @name experimental.i18n
1342
+ * @type {object}
1343
+ * @version 3.5.0
1344
+ * @type {object}
1345
+ * @description
1346
+ *
1347
+ * Configures experimental i18n routing and allows you to specify some customization options.
1348
+ *
1349
+ * See our guide for more information on [internationalization in Astro](/en/guides/internationalization/)
1350
+ */
1351
+ i18n?: {
1352
+ /**
1353
+ * @docs
1354
+ * @name experimental.i18n.defaultLocale
1355
+ * @type {string}
1356
+ * @version 3.5.0
1357
+ * @description
1358
+ *
1359
+ * The default locale of your website/application. This is a required field.
1360
+ *
1361
+ * No particular language format or syntax is enforced, but we suggest using lower-case and hyphens as needed (e.g. "es", "pt-br") for greatest compatibility.
1362
+ */
1363
+ defaultLocale: string;
1364
+ /**
1365
+ * @docs
1366
+ * @name experimental.i18n.locales
1367
+ * @type {string[]}
1368
+ * @version 3.5.0
1369
+ * @description
1370
+ *
1371
+ * A list of all locales supported by the website (e.g. `['en', 'es', 'pt-br']`). This list should also include the `defaultLocale`. This is a required field.
1372
+ *
1373
+ * No particular language format or syntax is enforced, but your folder structure must match exactly the locales in the list.
1374
+ */
1375
+ locales: string[];
1376
+ /**
1377
+ * @docs
1378
+ * @name experimental.i18n.fallback
1379
+ * @type {Record<string, string>}
1380
+ * @version 3.5.0
1381
+ * @description
1382
+ *
1383
+ * The fallback strategy when navigating to pages that do not exist (e.g. a translated page has not been created).
1384
+ *
1385
+ * Use this object to declare a fallback `locale` route for each language you support. If no fallback is specified, then unavailable pages will return a 404.
1386
+ *
1387
+ * #### Example
1388
+ *
1389
+ * The following example configures your content fallback strategy to redirect unavailable pages in `/pt-br/` to their `es` version, and unavailable pages in `/fr/` to their `en` version. Unavailable `/es/` pages will return a 404.
1390
+ *
1391
+ * ```js
1392
+ * export defualt defineConfig({
1393
+ * experimental: {
1394
+ * i18n: {
1395
+ * defaultLocale: "en",
1396
+ * locales: ["en", "fr", "pt-br", "es"],
1397
+ * fallback: {
1398
+ * pt: "es",
1399
+ * fr: "en"
1400
+ * }
1401
+ * }
1402
+ * }
1403
+ * })
1404
+ * ```
1405
+ */
1406
+ fallback?: Record<string, string>;
1407
+ /**
1408
+ * @docs
1409
+ * @name experimental.i18n.routingStrategy
1410
+ * @type {'prefix-always' | 'prefix-other-locales'}
1411
+ * @default 'prefix-other-locales'
1412
+ * @version 3.5.0
1413
+ * @description
1414
+ *
1415
+ * Controls the routing strategy to determine your site URLs. Set this based on your folder/URL path configuration for your default language:
1416
+ *
1417
+ * - `prefix-other-locales`(default): Only non-default languages will display a language prefix.
1418
+ * The `defaultLocale` will not show a language prefix and content files do not exist in a localized folder.
1419
+ * URLs will be of the form `example.com/[locale]/content/` for all non-default languages, but `example.com/content/` for the default locale.
1420
+ * - `prefix-always`: All URLs will display a language prefix.
1421
+ * URLs will be of the form `example.com/[locale]/content/` for every route, including the default language.
1422
+ * Localized folders are used for every language, including the default.
1423
+ *
1424
+ */
1425
+ routingStrategy?: 'prefix-always' | 'prefix-other-locales';
1426
+ };
1427
+ /**
1428
+ * @docs
1429
+ * @name experimental.contentCollectionCache
1430
+ * @type {boolean}
1431
+ * @default `false`
1432
+ * @version 3.5.0
1433
+ * @description
1434
+ * Enables a persistent cache for content collections when building in static mode.
1435
+ *
1436
+ * ```js
1437
+ * {
1438
+ * experimental: {
1439
+ * contentCollectionCache: true,
1440
+ * },
1441
+ * }
1442
+ * ```
1443
+ */
1444
+ contentCollectionCache?: boolean;
1278
1445
  };
1279
1446
  }
1280
1447
  /**
@@ -1332,10 +1499,6 @@ export interface AstroInlineOnlyConfig {
1332
1499
  * @default "info"
1333
1500
  */
1334
1501
  logLevel?: LoggerLevel;
1335
- /**
1336
- * @internal for testing only, use `logLevel` instead.
1337
- */
1338
- logger?: Logger;
1339
1502
  }
1340
1503
  export type ContentEntryModule = {
1341
1504
  id: string;
@@ -1426,6 +1589,10 @@ export interface AstroSettings {
1426
1589
  */
1427
1590
  clientDirectives: Map<string, string>;
1428
1591
  devOverlayPlugins: string[];
1592
+ middlewares: {
1593
+ pre: string[];
1594
+ post: string[];
1595
+ };
1429
1596
  tsConfig: TSConfig | undefined;
1430
1597
  tsConfigPath: string | undefined;
1431
1598
  watchFiles: string[];
@@ -1651,6 +1818,10 @@ export type AstroFeatureMap = {
1651
1818
  * The adapter can emit static assets
1652
1819
  */
1653
1820
  assets?: AstroAssetsFeature;
1821
+ /**
1822
+ * List of features that orbit around the i18n routing
1823
+ */
1824
+ i18n?: AstroInternationalizationFeature;
1654
1825
  };
1655
1826
  export interface AstroAssetsFeature {
1656
1827
  supportKind?: SupportsKind;
@@ -1663,6 +1834,12 @@ export interface AstroAssetsFeature {
1663
1834
  */
1664
1835
  isSquooshCompatible?: boolean;
1665
1836
  }
1837
+ export interface AstroInternationalizationFeature {
1838
+ /**
1839
+ * Whether the adapter is able to detect the language of the browser, usually using the `Accept-Language` header.
1840
+ */
1841
+ detectBrowserLanguage?: SupportsKind;
1842
+ }
1666
1843
  export interface AstroAdapter {
1667
1844
  name: string;
1668
1845
  serverEntrypoint?: string;
@@ -1712,6 +1889,14 @@ interface AstroSharedContext<Props extends Record<string, any> = Record<string,
1712
1889
  * Object accessed via Astro middleware
1713
1890
  */
1714
1891
  locals: App.Locals;
1892
+ /**
1893
+ * The current locale that is computed from the `Accept-Language` header of the browser (**SSR Only**).
1894
+ */
1895
+ preferredLocale: string | undefined;
1896
+ /**
1897
+ * The list of locales computed from the `Accept-Language` header of the browser, sorted by quality value (**SSR Only**).
1898
+ */
1899
+ preferredLocaleList: string[] | undefined;
1715
1900
  }
1716
1901
  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> {
1717
1902
  site: URL | undefined;
@@ -1808,6 +1993,32 @@ export interface APIContext<Props extends Record<string, any> = Record<string, a
1808
1993
  */
1809
1994
  locals: App.Locals;
1810
1995
  ResponseWithEncoding: typeof ResponseWithEncoding;
1996
+ /**
1997
+ * Available only when `experimental.i18n` enabled and in SSR.
1998
+ *
1999
+ * It represents the preferred locale of the user. It's computed by checking the supported locales in `i18n.locales`
2000
+ * and locales supported by the users's browser via the header `Accept-Language`
2001
+ *
2002
+ * For example, given `i18n.locales` equals to `['fr', 'de']`, and the `Accept-Language` value equals to `en, de;q=0.2, fr;q=0.6`, the
2003
+ * `Astro.preferredLanguage` will be `fr` because `en` is not supported, its [quality value] is the highest.
2004
+ *
2005
+ * [quality value]: https://developer.mozilla.org/en-US/docs/Glossary/Quality_values
2006
+ */
2007
+ preferredLocale: string | undefined;
2008
+ /**
2009
+ * Available only when `experimental.i18n` enabled and in SSR.
2010
+ *
2011
+ * It represents the list of the preferred locales that are supported by the application. The list is sorted via [quality value].
2012
+ *
2013
+ * For example, given `i18n.locales` equals to `['fr', 'pt', 'de']`, and the `Accept-Language` value equals to `en, de;q=0.2, fr;q=0.6`, the
2014
+ * `Astro.preferredLocaleList` will be equal to `['fs', 'de']` because `en` isn't supported, and `pt` isn't part of the locales contained in the
2015
+ * header.
2016
+ *
2017
+ * When the `Accept-Header` is `*`, the original `i18n.locales` are returned. The value `*` means no preferences, so Astro returns all the supported locales.
2018
+ *
2019
+ * [quality value]: https://developer.mozilla.org/en-US/docs/Glossary/Quality_values
2020
+ */
2021
+ preferredLocaleList: string[] | undefined;
1811
2022
  }
1812
2023
  export type EndpointOutput = {
1813
2024
  body: Body;
@@ -1860,6 +2071,7 @@ export interface AstroIntegration {
1860
2071
  injectRoute: (injectRoute: InjectedRoute) => void;
1861
2072
  addClientDirective: (directive: ClientDirectiveConfig) => void;
1862
2073
  addDevOverlayPlugin: (entrypoint: string) => void;
2074
+ addMiddleware: (mid: AstroIntegrationMiddleware) => void;
1863
2075
  logger: AstroIntegrationLogger;
1864
2076
  }) => void | Promise<void>;
1865
2077
  'astro:config:done'?: (options: {
@@ -1923,11 +2135,21 @@ export type MiddlewareNextResponse = MiddlewareNext<Response>;
1923
2135
  export type AstroMiddlewareInstance<R> = {
1924
2136
  onRequest?: MiddlewareHandler<R>;
1925
2137
  };
2138
+ export type AstroIntegrationMiddleware = {
2139
+ order: 'pre' | 'post';
2140
+ entrypoint: string;
2141
+ };
1926
2142
  export interface AstroPluginOptions {
1927
2143
  settings: AstroSettings;
1928
2144
  logger: Logger;
1929
2145
  }
1930
- export type RouteType = 'page' | 'endpoint' | 'redirect';
2146
+ /**
2147
+ * - page: a route that lives in the file system, usually an Astro component
2148
+ * - endpoint: a route that lives in the file system, usually a JS file that exposes endpoints methods
2149
+ * - redirect: a route points to another route that lives in the file system
2150
+ * - fallback: a route that doesn't exist in the file system that needs to be handled with other means, usually the middleware
2151
+ */
2152
+ export type RouteType = 'page' | 'endpoint' | 'redirect' | 'fallback';
1931
2153
  export interface RoutePart {
1932
2154
  content: string;
1933
2155
  dynamic: boolean;
@@ -6,6 +6,7 @@ import type { MapValue } from '../../type-utils.js';
6
6
  import type { AssetsGlobalStaticImagesList } from '../types.js';
7
7
  type AssetEnv = {
8
8
  logger: Logger;
9
+ isSSR: boolean;
9
10
  count: {
10
11
  total: number;
11
12
  current: number;
@@ -18,6 +19,6 @@ type AssetEnv = {
18
19
  assetsFolder: AstroConfig['build']['assets'];
19
20
  };
20
21
  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 generateImagesForPath(originalFilePath: string, transformsAndPath: MapValue<AssetsGlobalStaticImagesList>, env: AssetEnv, queue: PQueue): Promise<void>;
22
23
  export declare function getStaticImageList(): AssetsGlobalStaticImagesList;
23
24
  export {};
@@ -33,6 +33,7 @@ async function prepareAssetsGenerationEnv(pipeline, totalCount) {
33
33
  }
34
34
  return {
35
35
  logger,
36
+ isSSR: isServerLikeOutput(config),
36
37
  count,
37
38
  useCache,
38
39
  assetsCacheDir,
@@ -42,13 +43,25 @@ async function prepareAssetsGenerationEnv(pipeline, totalCount) {
42
43
  assetsFolder: config.build.assets
43
44
  };
44
45
  }
45
- async function generateImagesForPath(originalFilePath, transforms, env, queue) {
46
+ function getFullImagePath(originalFilePath, env) {
47
+ return new URL(
48
+ "." + prependForwardSlash(join(env.assetsFolder, basename(originalFilePath))),
49
+ env.serverRoot
50
+ );
51
+ }
52
+ async function generateImagesForPath(originalFilePath, transformsAndPath, env, queue) {
46
53
  const originalImageData = await loadImage(originalFilePath, env);
47
- for (const [_, transform] of transforms) {
54
+ for (const [_, transform] of transformsAndPath.transforms) {
48
55
  queue.add(
49
56
  async () => generateImage(originalImageData, transform.finalPath, transform.transform)
50
57
  );
51
58
  }
59
+ if (!env.isSSR && !isRemotePath(originalFilePath) && !globalThis.astroAsset.referencedImages?.has(transformsAndPath.originalSrcPath)) {
60
+ try {
61
+ await fs.promises.unlink(getFullImagePath(originalFilePath, env));
62
+ } catch (e) {
63
+ }
64
+ }
52
65
  async function generateImage(originalImage, filepath, options) {
53
66
  const timeStart = performance.now();
54
67
  const generationData = await generateImageInternal(originalImage, filepath, options);
@@ -156,9 +169,7 @@ async function loadImage(path, env) {
156
169
  };
157
170
  }
158
171
  return {
159
- data: await fs.promises.readFile(
160
- new URL("." + prependForwardSlash(join(env.assetsFolder, basename(path))), env.serverRoot)
161
- ),
172
+ data: await fs.promises.readFile(getFullImagePath(path, env)),
162
173
  expires: 0
163
174
  };
164
175
  }