astro 3.5.5 → 3.5.7
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/components/ViewTransitions.astro +16 -8
- package/dist/@types/astro.d.ts +11 -1
- package/dist/cli/add/index.js +9 -1
- package/dist/core/app/index.js +22 -5
- package/dist/core/build/buildPipeline.js +5 -7
- package/dist/core/build/generate.js +144 -122
- package/dist/core/build/internal.d.ts +0 -6
- package/dist/core/build/internal.js +3 -16
- package/dist/core/build/page-data.js +18 -46
- package/dist/core/build/static-build.js +7 -9
- package/dist/core/build/types.d.ts +1 -1
- package/dist/core/constants.js +1 -1
- package/dist/core/dev/dev.js +1 -1
- package/dist/core/endpoint/index.d.ts +4 -2
- package/dist/core/endpoint/index.js +22 -4
- package/dist/core/messages.js +2 -2
- package/dist/core/middleware/index.js +3 -1
- package/dist/core/pipeline.js +4 -8
- package/dist/core/render/context.d.ts +3 -0
- package/dist/core/render/context.js +18 -1
- package/dist/core/render/core.js +3 -1
- package/dist/core/render/result.d.ts +2 -0
- package/dist/core/render/result.js +23 -1
- package/dist/core/routing/manifest/create.js +20 -11
- package/dist/core/routing/manifest/serialization.js +7 -1
- package/dist/core/routing/match.js +4 -1
- package/dist/vite-plugin-astro-server/route.js +9 -3
- package/package.json +1 -1
|
@@ -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
|
|
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
|
-
(
|
|
65
|
-
|
|
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(
|
|
86
|
+
navigate(href, {
|
|
79
87
|
history: link.dataset.astroHistory === 'replace' ? 'replace' : 'auto',
|
|
80
88
|
});
|
|
81
89
|
});
|
package/dist/@types/astro.d.ts
CHANGED
|
@@ -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
|
};
|
package/dist/cli/add/index.js
CHANGED
|
@@ -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;
|
package/dist/core/app/index.js
CHANGED
|
@@ -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
|
|
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);
|
|
@@ -188,7 +194,9 @@ class App {
|
|
|
188
194
|
status,
|
|
189
195
|
env: this.#pipeline.env,
|
|
190
196
|
mod: handler,
|
|
191
|
-
locales: this.#manifest.i18n
|
|
197
|
+
locales: this.#manifest.i18n?.locales,
|
|
198
|
+
routingStrategy: this.#manifest.i18n?.routingStrategy,
|
|
199
|
+
defaultLocale: this.#manifest.i18n?.defaultLocale
|
|
192
200
|
});
|
|
193
201
|
} else {
|
|
194
202
|
const pathname = prependForwardSlash(this.removeBase(url.pathname));
|
|
@@ -220,7 +228,9 @@ class App {
|
|
|
220
228
|
status,
|
|
221
229
|
mod,
|
|
222
230
|
env: this.#pipeline.env,
|
|
223
|
-
locales: this.#manifest.i18n
|
|
231
|
+
locales: this.#manifest.i18n?.locales,
|
|
232
|
+
routingStrategy: this.#manifest.i18n?.routingStrategy,
|
|
233
|
+
defaultLocale: this.#manifest.i18n?.defaultLocale
|
|
224
234
|
});
|
|
225
235
|
}
|
|
226
236
|
}
|
|
@@ -293,8 +303,15 @@ class App {
|
|
|
293
303
|
headers: new Headers(Array.from(headers))
|
|
294
304
|
});
|
|
295
305
|
}
|
|
296
|
-
#getDefaultStatusCode(
|
|
297
|
-
|
|
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);
|
|
298
315
|
if (route.endsWith("/404"))
|
|
299
316
|
return 404;
|
|
300
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,
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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;
|
|
@@ -244,6 +244,9 @@ async function generatePage(pageData, ssrEntry, builtPaths, pipeline) {
|
|
|
244
244
|
const icon = pageData.route.type === "page" || pageData.route.type === "redirect" || pageData.route.type === "fallback" ? green("\u25B6") : magenta("\u03BB");
|
|
245
245
|
if (isRelativePath(pageData.route.component)) {
|
|
246
246
|
logger.info(null, `${icon} ${pageData.route.route}`);
|
|
247
|
+
for (const fallbackRoute of pageData.route.fallbackRoutes) {
|
|
248
|
+
logger.info(null, `${icon} ${fallbackRoute.route}`);
|
|
249
|
+
}
|
|
247
250
|
} else {
|
|
248
251
|
logger.info(null, `${icon} ${pageData.route.component}`);
|
|
249
252
|
}
|
|
@@ -261,6 +264,12 @@ async function generatePage(pageData, ssrEntry, builtPaths, pipeline) {
|
|
|
261
264
|
prevTimeEnd = timeEnd;
|
|
262
265
|
}
|
|
263
266
|
}
|
|
267
|
+
function* eachRouteInRouteData(data) {
|
|
268
|
+
yield data.route;
|
|
269
|
+
for (const fallbackRoute of data.route.fallbackRoutes) {
|
|
270
|
+
yield fallbackRoute;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
264
273
|
async function getPathsForRoute(pageData, mod, pipeline, builtPaths) {
|
|
265
274
|
const opts = pipeline.getStaticBuildOptions();
|
|
266
275
|
const logger = pipeline.getLogger();
|
|
@@ -268,43 +277,52 @@ async function getPathsForRoute(pageData, mod, pipeline, builtPaths) {
|
|
|
268
277
|
if (pageData.route.pathname) {
|
|
269
278
|
paths.push(pageData.route.pathname);
|
|
270
279
|
builtPaths.add(pageData.route.pathname);
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
route,
|
|
276
|
-
routeCache: opts.routeCache,
|
|
277
|
-
logger,
|
|
278
|
-
ssr: isServerLikeOutput(opts.settings.config)
|
|
279
|
-
}).catch((err) => {
|
|
280
|
-
logger.debug("build", `\u251C\u2500\u2500 ${colors.bold(colors.red("\u2717"))} ${route.component}`);
|
|
281
|
-
throw err;
|
|
282
|
-
});
|
|
283
|
-
const label = staticPaths.length === 1 ? "page" : "pages";
|
|
284
|
-
logger.debug(
|
|
285
|
-
"build",
|
|
286
|
-
`\u251C\u2500\u2500 ${colors.bold(colors.green("\u2714"))} ${route.component} \u2192 ${colors.magenta(
|
|
287
|
-
`[${staticPaths.length} ${label}]`
|
|
288
|
-
)}`
|
|
289
|
-
);
|
|
290
|
-
paths = staticPaths.map((staticPath) => {
|
|
291
|
-
try {
|
|
292
|
-
return route.generate(staticPath.params);
|
|
293
|
-
} catch (e) {
|
|
294
|
-
if (e instanceof TypeError) {
|
|
295
|
-
throw getInvalidRouteSegmentError(e, route, staticPath);
|
|
296
|
-
}
|
|
297
|
-
throw e;
|
|
280
|
+
for (const virtualRoute of pageData.route.fallbackRoutes) {
|
|
281
|
+
if (virtualRoute.pathname) {
|
|
282
|
+
paths.push(virtualRoute.pathname);
|
|
283
|
+
builtPaths.add(virtualRoute.pathname);
|
|
298
284
|
}
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
|
|
285
|
+
}
|
|
286
|
+
} else {
|
|
287
|
+
for (const route of eachRouteInRouteData(pageData)) {
|
|
288
|
+
const staticPaths = await callGetStaticPaths({
|
|
289
|
+
mod,
|
|
290
|
+
route,
|
|
291
|
+
routeCache: opts.routeCache,
|
|
292
|
+
logger,
|
|
293
|
+
ssr: isServerLikeOutput(opts.settings.config)
|
|
294
|
+
}).catch((err) => {
|
|
295
|
+
logger.debug("build", `\u251C\u2500\u2500 ${colors.bold(colors.red("\u2717"))} ${route.component}`);
|
|
296
|
+
throw err;
|
|
297
|
+
});
|
|
298
|
+
const label = staticPaths.length === 1 ? "page" : "pages";
|
|
299
|
+
logger.debug(
|
|
300
|
+
"build",
|
|
301
|
+
`\u251C\u2500\u2500 ${colors.bold(colors.green("\u2714"))} ${route.component} \u2192 ${colors.magenta(
|
|
302
|
+
`[${staticPaths.length} ${label}]`
|
|
303
|
+
)}`
|
|
304
|
+
);
|
|
305
|
+
paths.push(
|
|
306
|
+
...staticPaths.map((staticPath) => {
|
|
307
|
+
try {
|
|
308
|
+
return route.generate(staticPath.params);
|
|
309
|
+
} catch (e) {
|
|
310
|
+
if (e instanceof TypeError) {
|
|
311
|
+
throw getInvalidRouteSegmentError(e, route, staticPath);
|
|
312
|
+
}
|
|
313
|
+
throw e;
|
|
314
|
+
}
|
|
315
|
+
}).filter((staticPath) => {
|
|
316
|
+
if (!builtPaths.has(removeTrailingForwardSlash(staticPath))) {
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
const matchedRoute = matchRoute(staticPath, opts.manifest);
|
|
320
|
+
return matchedRoute === route;
|
|
321
|
+
})
|
|
322
|
+
);
|
|
323
|
+
for (const staticPath of paths) {
|
|
324
|
+
builtPaths.add(removeTrailingForwardSlash(staticPath));
|
|
302
325
|
}
|
|
303
|
-
const matchedRoute = matchRoute(staticPath, opts.manifest);
|
|
304
|
-
return matchedRoute === route;
|
|
305
|
-
});
|
|
306
|
-
for (const staticPath of paths) {
|
|
307
|
-
builtPaths.add(removeTrailingForwardSlash(staticPath));
|
|
308
326
|
}
|
|
309
327
|
}
|
|
310
328
|
return paths;
|
|
@@ -356,84 +374,87 @@ function getUrlForPath(pathname, base, origin, format, routeType) {
|
|
|
356
374
|
async function generatePath(pathname, gopts, pipeline) {
|
|
357
375
|
const manifest = pipeline.getManifest();
|
|
358
376
|
const { mod, scripts: hoistedScripts, styles: _styles, pageData } = gopts;
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
pipeline.getEnvironment().logger.debug("build", `Generating: ${pathname}`);
|
|
363
|
-
const links = /* @__PURE__ */ new Set();
|
|
364
|
-
const scripts = createModuleScriptsSet(
|
|
365
|
-
hoistedScripts ? [hoistedScripts] : [],
|
|
366
|
-
manifest.base,
|
|
367
|
-
manifest.assetsPrefix
|
|
368
|
-
);
|
|
369
|
-
const styles = createStylesheetElementSet(_styles, manifest.base, manifest.assetsPrefix);
|
|
370
|
-
if (pipeline.getSettings().scripts.some((script) => script.stage === "page")) {
|
|
371
|
-
const hashedFilePath = pipeline.getInternals().entrySpecifierToBundleMap.get(PAGE_SCRIPT_ID);
|
|
372
|
-
if (typeof hashedFilePath !== "string") {
|
|
373
|
-
throw new Error(`Cannot find the built path for ${PAGE_SCRIPT_ID}`);
|
|
377
|
+
for (const route of eachRouteInRouteData(pageData)) {
|
|
378
|
+
if (route.type === "page") {
|
|
379
|
+
addPageName(pathname, pipeline.getStaticBuildOptions());
|
|
374
380
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
381
|
+
pipeline.getEnvironment().logger.debug("build", `Generating: ${pathname}`);
|
|
382
|
+
const links = /* @__PURE__ */ new Set();
|
|
383
|
+
const scripts = createModuleScriptsSet(
|
|
384
|
+
hoistedScripts ? [hoistedScripts] : [],
|
|
385
|
+
manifest.base,
|
|
386
|
+
manifest.assetsPrefix
|
|
387
|
+
);
|
|
388
|
+
const styles = createStylesheetElementSet(_styles, manifest.base, manifest.assetsPrefix);
|
|
389
|
+
if (pipeline.getSettings().scripts.some((script) => script.stage === "page")) {
|
|
390
|
+
const hashedFilePath = pipeline.getInternals().entrySpecifierToBundleMap.get(PAGE_SCRIPT_ID);
|
|
391
|
+
if (typeof hashedFilePath !== "string") {
|
|
392
|
+
throw new Error(`Cannot find the built path for ${PAGE_SCRIPT_ID}`);
|
|
393
|
+
}
|
|
394
|
+
const src = createAssetLink(hashedFilePath, manifest.base, manifest.assetsPrefix);
|
|
383
395
|
scripts.add({
|
|
384
|
-
props: {},
|
|
385
|
-
children:
|
|
396
|
+
props: { type: "module", src },
|
|
397
|
+
children: ""
|
|
386
398
|
});
|
|
387
399
|
}
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
pageData.route.type
|
|
396
|
-
);
|
|
397
|
-
const request = createRequest({
|
|
398
|
-
url,
|
|
399
|
-
headers: new Headers(),
|
|
400
|
-
logger: pipeline.getLogger(),
|
|
401
|
-
ssr
|
|
402
|
-
});
|
|
403
|
-
const i18n = pipeline.getConfig().experimental.i18n;
|
|
404
|
-
const renderContext = await createRenderContext({
|
|
405
|
-
pathname,
|
|
406
|
-
request,
|
|
407
|
-
componentMetadata: manifest.componentMetadata,
|
|
408
|
-
scripts,
|
|
409
|
-
styles,
|
|
410
|
-
links,
|
|
411
|
-
route: pageData.route,
|
|
412
|
-
env: pipeline.getEnvironment(),
|
|
413
|
-
mod,
|
|
414
|
-
locales: i18n ? i18n.locales : void 0
|
|
415
|
-
});
|
|
416
|
-
let body;
|
|
417
|
-
let encoding;
|
|
418
|
-
let response;
|
|
419
|
-
try {
|
|
420
|
-
response = await pipeline.renderRoute(renderContext, mod);
|
|
421
|
-
} catch (err) {
|
|
422
|
-
if (!AstroError.is(err) && !err.id && typeof err === "object") {
|
|
423
|
-
err.id = pageData.component;
|
|
400
|
+
for (const script of pipeline.getSettings().scripts) {
|
|
401
|
+
if (script.stage === "head-inline") {
|
|
402
|
+
scripts.add({
|
|
403
|
+
props: {},
|
|
404
|
+
children: script.content
|
|
405
|
+
});
|
|
406
|
+
}
|
|
424
407
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
408
|
+
const ssr = isServerLikeOutput(pipeline.getConfig());
|
|
409
|
+
const url = getUrlForPath(
|
|
410
|
+
pathname,
|
|
411
|
+
pipeline.getConfig().base,
|
|
412
|
+
pipeline.getStaticBuildOptions().origin,
|
|
413
|
+
pipeline.getConfig().build.format,
|
|
414
|
+
route.type
|
|
415
|
+
);
|
|
416
|
+
const request = createRequest({
|
|
417
|
+
url,
|
|
418
|
+
headers: new Headers(),
|
|
419
|
+
logger: pipeline.getLogger(),
|
|
420
|
+
ssr
|
|
421
|
+
});
|
|
422
|
+
const i18n = pipeline.getConfig().experimental.i18n;
|
|
423
|
+
const renderContext = await createRenderContext({
|
|
424
|
+
pathname,
|
|
425
|
+
request,
|
|
426
|
+
componentMetadata: manifest.componentMetadata,
|
|
427
|
+
scripts,
|
|
428
|
+
styles,
|
|
429
|
+
links,
|
|
430
|
+
route,
|
|
431
|
+
env: pipeline.getEnvironment(),
|
|
432
|
+
mod,
|
|
433
|
+
locales: i18n?.locales,
|
|
434
|
+
routingStrategy: i18n?.routingStrategy,
|
|
435
|
+
defaultLocale: i18n?.defaultLocale
|
|
436
|
+
});
|
|
437
|
+
let body;
|
|
438
|
+
let encoding;
|
|
439
|
+
let response;
|
|
440
|
+
try {
|
|
441
|
+
response = await pipeline.renderRoute(renderContext, mod);
|
|
442
|
+
} catch (err) {
|
|
443
|
+
if (!AstroError.is(err) && !err.id && typeof err === "object") {
|
|
444
|
+
err.id = pageData.component;
|
|
445
|
+
}
|
|
446
|
+
throw err;
|
|
430
447
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
448
|
+
if (response.status >= 300 && response.status < 400) {
|
|
449
|
+
if (!pipeline.getConfig().build.redirects) {
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
const locationSite = getRedirectLocationOrThrow(response.headers);
|
|
453
|
+
const siteURL = pipeline.getConfig().site;
|
|
454
|
+
const location = siteURL ? new URL(locationSite, siteURL) : locationSite;
|
|
455
|
+
const fromPath = new URL(renderContext.request.url).pathname;
|
|
456
|
+
const delay = response.status === 302 ? 2 : 0;
|
|
457
|
+
body = `<!doctype html>
|
|
437
458
|
<title>Redirecting to: ${location}</title>
|
|
438
459
|
<meta http-equiv="refresh" content="${delay};url=${location}">
|
|
439
460
|
<meta name="robots" content="noindex">
|
|
@@ -441,23 +462,24 @@ async function generatePath(pathname, gopts, pipeline) {
|
|
|
441
462
|
<body>
|
|
442
463
|
<a href="${location}">Redirecting from <code>${fromPath}</code> to <code>${location}</code></a>
|
|
443
464
|
</body>`;
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
465
|
+
if (pipeline.getConfig().compressHTML === true) {
|
|
466
|
+
body = body.replaceAll("\n", "");
|
|
467
|
+
}
|
|
468
|
+
if (route.type !== "redirect") {
|
|
469
|
+
route.redirect = location.toString();
|
|
470
|
+
}
|
|
471
|
+
} else {
|
|
472
|
+
if (!response.body)
|
|
473
|
+
return;
|
|
474
|
+
body = Buffer.from(await response.arrayBuffer());
|
|
475
|
+
encoding = response.headers.get("X-Astro-Encoding") ?? "utf-8";
|
|
449
476
|
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
477
|
+
const outFolder = getOutFolder(pipeline.getConfig(), pathname, route.type);
|
|
478
|
+
const outFile = getOutFile(pipeline.getConfig(), outFolder, pathname, route.type);
|
|
479
|
+
route.distURL = outFile;
|
|
480
|
+
await fs.promises.mkdir(outFolder, { recursive: true });
|
|
481
|
+
await fs.promises.writeFile(outFile, body, encoding);
|
|
455
482
|
}
|
|
456
|
-
const outFolder = getOutFolder(pipeline.getConfig(), pathname, pageData.route.type);
|
|
457
|
-
const outFile = getOutFile(pipeline.getConfig(), outFolder, pathname, pageData.route.type);
|
|
458
|
-
pageData.route.distURL = outFile;
|
|
459
|
-
await fs.promises.mkdir(outFolder, { recursive: true });
|
|
460
|
-
await fs.promises.writeFile(outFile, body, encoding);
|
|
461
483
|
}
|
|
462
484
|
function createBuildManifest(settings, internals, renderers) {
|
|
463
485
|
let i18nManifest = void 0;
|
|
@@ -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
|
-
|
|
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,
|
|
109
|
-
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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).
|
|
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;
|
package/dist/core/constants.js
CHANGED
package/dist/core/dev/dev.js
CHANGED
|
@@ -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.
|
|
23
|
+
const currentVersion = "3.5.7";
|
|
24
24
|
if (currentVersion.includes("-")) {
|
|
25
25
|
logger.warn(null, msg.prerelease({ currentVersion }));
|
|
26
26
|
}
|
|
@@ -8,16 +8,18 @@ type CreateAPIContext = {
|
|
|
8
8
|
props: Record<string, any>;
|
|
9
9
|
adapterName?: string;
|
|
10
10
|
locales: string[] | undefined;
|
|
11
|
+
routingStrategy: 'prefix-always' | 'prefix-other-locales' | undefined;
|
|
12
|
+
defaultLocale: string | undefined;
|
|
11
13
|
};
|
|
12
14
|
/**
|
|
13
15
|
* Creates a context that holds all the information needed to handle an Astro endpoint.
|
|
14
16
|
*
|
|
15
17
|
* @param {CreateAPIContext} payload
|
|
16
18
|
*/
|
|
17
|
-
export declare function createAPIContext({ request, params, site, props, adapterName, locales, }: CreateAPIContext): APIContext;
|
|
19
|
+
export declare function createAPIContext({ request, params, site, props, adapterName, locales, routingStrategy, defaultLocale, }: CreateAPIContext): APIContext;
|
|
18
20
|
type ResponseParameters = ConstructorParameters<typeof Response>;
|
|
19
21
|
export declare class ResponseWithEncoding extends Response {
|
|
20
22
|
constructor(body: ResponseParameters[0], init: ResponseParameters[1], encoding?: BufferEncoding);
|
|
21
23
|
}
|
|
22
|
-
export declare function callEndpoint<MiddlewareResult = Response | EndpointOutput>(mod: EndpointHandler, env: Environment, ctx: RenderContext, onRequest: MiddlewareHandler<MiddlewareResult> | undefined
|
|
24
|
+
export declare function callEndpoint<MiddlewareResult = Response | EndpointOutput>(mod: EndpointHandler, env: Environment, ctx: RenderContext, onRequest: MiddlewareHandler<MiddlewareResult> | undefined): Promise<Response>;
|
|
23
25
|
export {};
|
|
@@ -4,7 +4,11 @@ import { ASTRO_VERSION } from "../constants.js";
|
|
|
4
4
|
import { AstroCookies, attachCookiesToResponse } from "../cookies/index.js";
|
|
5
5
|
import { AstroError, AstroErrorData } from "../errors/index.js";
|
|
6
6
|
import { callMiddleware } from "../middleware/callMiddleware.js";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
computeCurrentLocale,
|
|
9
|
+
computePreferredLocale,
|
|
10
|
+
computePreferredLocaleList
|
|
11
|
+
} from "../render/context.js";
|
|
8
12
|
import {} from "../render/index.js";
|
|
9
13
|
const encoder = new TextEncoder();
|
|
10
14
|
const clientAddressSymbol = Symbol.for("astro.clientAddress");
|
|
@@ -15,10 +19,13 @@ function createAPIContext({
|
|
|
15
19
|
site,
|
|
16
20
|
props,
|
|
17
21
|
adapterName,
|
|
18
|
-
locales
|
|
22
|
+
locales,
|
|
23
|
+
routingStrategy,
|
|
24
|
+
defaultLocale
|
|
19
25
|
}) {
|
|
20
26
|
let preferredLocale = void 0;
|
|
21
27
|
let preferredLocaleList = void 0;
|
|
28
|
+
let currentLocale = void 0;
|
|
22
29
|
const context = {
|
|
23
30
|
cookies: new AstroCookies(request),
|
|
24
31
|
request,
|
|
@@ -55,6 +62,15 @@ function createAPIContext({
|
|
|
55
62
|
}
|
|
56
63
|
return void 0;
|
|
57
64
|
},
|
|
65
|
+
get currentLocale() {
|
|
66
|
+
if (currentLocale) {
|
|
67
|
+
return currentLocale;
|
|
68
|
+
}
|
|
69
|
+
if (locales) {
|
|
70
|
+
currentLocale = computeCurrentLocale(request, locales, routingStrategy, defaultLocale);
|
|
71
|
+
}
|
|
72
|
+
return currentLocale;
|
|
73
|
+
},
|
|
58
74
|
url: new URL(request.url),
|
|
59
75
|
get clientAddress() {
|
|
60
76
|
if (clientAddressSymbol in request) {
|
|
@@ -106,14 +122,16 @@ class ResponseWithEncoding extends Response {
|
|
|
106
122
|
}
|
|
107
123
|
}
|
|
108
124
|
}
|
|
109
|
-
async function callEndpoint(mod, env, ctx, onRequest
|
|
125
|
+
async function callEndpoint(mod, env, ctx, onRequest) {
|
|
110
126
|
const context = createAPIContext({
|
|
111
127
|
request: ctx.request,
|
|
112
128
|
params: ctx.params,
|
|
113
129
|
props: ctx.props,
|
|
114
130
|
site: env.site,
|
|
115
131
|
adapterName: env.adapterName,
|
|
116
|
-
|
|
132
|
+
routingStrategy: ctx.routingStrategy,
|
|
133
|
+
defaultLocale: ctx.defaultLocale,
|
|
134
|
+
locales: ctx.locales
|
|
117
135
|
});
|
|
118
136
|
let response;
|
|
119
137
|
if (onRequest) {
|
package/dist/core/messages.js
CHANGED
|
@@ -50,7 +50,7 @@ function serverStart({
|
|
|
50
50
|
base,
|
|
51
51
|
isRestart = false
|
|
52
52
|
}) {
|
|
53
|
-
const version = "3.5.
|
|
53
|
+
const version = "3.5.7";
|
|
54
54
|
const localPrefix = `${dim("\u2503")} Local `;
|
|
55
55
|
const networkPrefix = `${dim("\u2503")} Network `;
|
|
56
56
|
const emptyPrefix = " ".repeat(11);
|
|
@@ -235,7 +235,7 @@ function printHelp({
|
|
|
235
235
|
message.push(
|
|
236
236
|
linebreak(),
|
|
237
237
|
` ${bgGreen(black(` ${commandName} `))} ${green(
|
|
238
|
-
`v${"3.5.
|
|
238
|
+
`v${"3.5.7"}`
|
|
239
239
|
)} ${headline}`
|
|
240
240
|
);
|
|
241
241
|
}
|
|
@@ -9,7 +9,9 @@ function createContext({ request, params, userDefinedLocales = [] }) {
|
|
|
9
9
|
params: params ?? {},
|
|
10
10
|
props: {},
|
|
11
11
|
site: void 0,
|
|
12
|
-
locales: userDefinedLocales
|
|
12
|
+
locales: userDefinedLocales,
|
|
13
|
+
defaultLocale: void 0,
|
|
14
|
+
routingStrategy: void 0
|
|
13
15
|
});
|
|
14
16
|
}
|
|
15
17
|
function isLocalsSerializable(value) {
|
package/dist/core/pipeline.js
CHANGED
|
@@ -89,7 +89,9 @@ class Pipeline {
|
|
|
89
89
|
props: renderContext.props,
|
|
90
90
|
site: env.site,
|
|
91
91
|
adapterName: env.adapterName,
|
|
92
|
-
locales: renderContext.locales
|
|
92
|
+
locales: renderContext.locales,
|
|
93
|
+
routingStrategy: renderContext.routingStrategy,
|
|
94
|
+
defaultLocale: renderContext.defaultLocale
|
|
93
95
|
});
|
|
94
96
|
switch (renderContext.route.type) {
|
|
95
97
|
case "page":
|
|
@@ -119,13 +121,7 @@ class Pipeline {
|
|
|
119
121
|
}
|
|
120
122
|
}
|
|
121
123
|
case "endpoint": {
|
|
122
|
-
return await callEndpoint(
|
|
123
|
-
mod,
|
|
124
|
-
env,
|
|
125
|
-
renderContext,
|
|
126
|
-
onRequest,
|
|
127
|
-
renderContext.locales
|
|
128
|
-
);
|
|
124
|
+
return await callEndpoint(mod, env, renderContext, onRequest);
|
|
129
125
|
}
|
|
130
126
|
default:
|
|
131
127
|
throw new Error(`Couldn't find route of type [${renderContext.route.type}]`);
|
|
@@ -16,6 +16,8 @@ export interface RenderContext {
|
|
|
16
16
|
props: Props;
|
|
17
17
|
locals?: object;
|
|
18
18
|
locales: string[] | undefined;
|
|
19
|
+
defaultLocale: string | undefined;
|
|
20
|
+
routingStrategy: 'prefix-always' | 'prefix-other-locales' | undefined;
|
|
19
21
|
}
|
|
20
22
|
export type CreateRenderContextArgs = Partial<Omit<RenderContext, 'params' | 'props' | 'locals'>> & {
|
|
21
23
|
route: RouteData;
|
|
@@ -45,4 +47,5 @@ export declare function parseLocale(header: string): BrowserLocale[];
|
|
|
45
47
|
*/
|
|
46
48
|
export declare function computePreferredLocale(request: Request, locales: string[]): string | undefined;
|
|
47
49
|
export declare function computePreferredLocaleList(request: Request, locales: string[]): string[];
|
|
50
|
+
export declare function computeCurrentLocale(request: Request, locales: string[], routingStrategy: 'prefix-always' | 'prefix-other-locales' | undefined, defaultLocale: string | undefined): undefined | string;
|
|
48
51
|
export {};
|
|
@@ -18,7 +18,9 @@ async function createRenderContext(options) {
|
|
|
18
18
|
pathname,
|
|
19
19
|
params,
|
|
20
20
|
props,
|
|
21
|
-
locales: options.locales
|
|
21
|
+
locales: options.locales,
|
|
22
|
+
routingStrategy: options.routingStrategy,
|
|
23
|
+
defaultLocale: options.defaultLocale
|
|
22
24
|
};
|
|
23
25
|
Object.defineProperty(context, "locals", {
|
|
24
26
|
enumerable: true,
|
|
@@ -124,7 +126,22 @@ function computePreferredLocaleList(request, locales) {
|
|
|
124
126
|
}
|
|
125
127
|
return result;
|
|
126
128
|
}
|
|
129
|
+
function computeCurrentLocale(request, locales, routingStrategy, defaultLocale) {
|
|
130
|
+
const requestUrl = new URL(request.url);
|
|
131
|
+
for (const segment of requestUrl.pathname.split("/")) {
|
|
132
|
+
for (const locale of locales) {
|
|
133
|
+
if (normalizeTheLocale(locale) === normalizeTheLocale(segment)) {
|
|
134
|
+
return locale;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (routingStrategy === "prefix-other-locales") {
|
|
139
|
+
return defaultLocale;
|
|
140
|
+
}
|
|
141
|
+
return void 0;
|
|
142
|
+
}
|
|
127
143
|
export {
|
|
144
|
+
computeCurrentLocale,
|
|
128
145
|
computePreferredLocale,
|
|
129
146
|
computePreferredLocaleList,
|
|
130
147
|
createRenderContext,
|
package/dist/core/render/core.js
CHANGED
|
@@ -43,7 +43,9 @@ async function renderPage({ mod, renderContext, env, cookies }) {
|
|
|
43
43
|
status: renderContext.status ?? 200,
|
|
44
44
|
cookies,
|
|
45
45
|
locals: renderContext.locals ?? {},
|
|
46
|
-
locales: renderContext.locales
|
|
46
|
+
locales: renderContext.locales,
|
|
47
|
+
defaultLocale: renderContext.defaultLocale,
|
|
48
|
+
routingStrategy: renderContext.routingStrategy
|
|
47
49
|
});
|
|
48
50
|
if (mod.frontmatter && typeof mod.frontmatter === "object" && "draft" in mod.frontmatter) {
|
|
49
51
|
env.logger.warn(
|
|
@@ -31,5 +31,7 @@ export interface CreateResultArgs {
|
|
|
31
31
|
locals: App.Locals;
|
|
32
32
|
cookies?: AstroCookies;
|
|
33
33
|
locales: string[] | undefined;
|
|
34
|
+
defaultLocale: string | undefined;
|
|
35
|
+
routingStrategy: 'prefix-always' | 'prefix-other-locales' | undefined;
|
|
34
36
|
}
|
|
35
37
|
export declare function createResult(args: CreateResultArgs): SSRResult;
|
|
@@ -3,7 +3,11 @@ import { renderJSX } from "../../runtime/server/jsx.js";
|
|
|
3
3
|
import { chunkToString } from "../../runtime/server/render/index.js";
|
|
4
4
|
import { AstroCookies } from "../cookies/index.js";
|
|
5
5
|
import { AstroError, AstroErrorData } from "../errors/index.js";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
computeCurrentLocale,
|
|
8
|
+
computePreferredLocale,
|
|
9
|
+
computePreferredLocaleList
|
|
10
|
+
} from "./context.js";
|
|
7
11
|
const clientAddressSymbol = Symbol.for("astro.clientAddress");
|
|
8
12
|
const responseSentSymbol = Symbol.for("astro.responseSent");
|
|
9
13
|
function getFunctionExpression(slot) {
|
|
@@ -91,6 +95,7 @@ function createResult(args) {
|
|
|
91
95
|
let cookies = args.cookies;
|
|
92
96
|
let preferredLocale = void 0;
|
|
93
97
|
let preferredLocaleList = void 0;
|
|
98
|
+
let currentLocale = void 0;
|
|
94
99
|
const result = {
|
|
95
100
|
styles: args.styles ?? /* @__PURE__ */ new Set(),
|
|
96
101
|
scripts: args.scripts ?? /* @__PURE__ */ new Set(),
|
|
@@ -149,6 +154,23 @@ function createResult(args) {
|
|
|
149
154
|
}
|
|
150
155
|
return void 0;
|
|
151
156
|
},
|
|
157
|
+
get currentLocale() {
|
|
158
|
+
if (currentLocale) {
|
|
159
|
+
return currentLocale;
|
|
160
|
+
}
|
|
161
|
+
if (args.locales) {
|
|
162
|
+
currentLocale = computeCurrentLocale(
|
|
163
|
+
request,
|
|
164
|
+
args.locales,
|
|
165
|
+
args.routingStrategy,
|
|
166
|
+
args.defaultLocale
|
|
167
|
+
);
|
|
168
|
+
if (currentLocale) {
|
|
169
|
+
return currentLocale;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return void 0;
|
|
173
|
+
},
|
|
152
174
|
params,
|
|
153
175
|
props,
|
|
154
176
|
locals,
|
|
@@ -236,7 +236,8 @@ function createRouteManifest({ settings, cwd, fsMod }, logger) {
|
|
|
236
236
|
component,
|
|
237
237
|
generate,
|
|
238
238
|
pathname: pathname || void 0,
|
|
239
|
-
prerender
|
|
239
|
+
prerender,
|
|
240
|
+
fallbackRoutes: []
|
|
240
241
|
});
|
|
241
242
|
}
|
|
242
243
|
});
|
|
@@ -290,7 +291,8 @@ This route collides with: "${collision.component}".`
|
|
|
290
291
|
component,
|
|
291
292
|
generate,
|
|
292
293
|
pathname: pathname || void 0,
|
|
293
|
-
prerender: prerenderInjected ?? prerender
|
|
294
|
+
prerender: prerenderInjected ?? prerender,
|
|
295
|
+
fallbackRoutes: []
|
|
294
296
|
});
|
|
295
297
|
});
|
|
296
298
|
Object.entries(settings.config.redirects).forEach(([from, to]) => {
|
|
@@ -315,7 +317,8 @@ This route collides with: "${collision.component}".`
|
|
|
315
317
|
pathname: pathname || void 0,
|
|
316
318
|
prerender: false,
|
|
317
319
|
redirect: to,
|
|
318
|
-
redirectRoute: routes.find((r) => r.route === to)
|
|
320
|
+
redirectRoute: routes.find((r) => r.route === to),
|
|
321
|
+
fallbackRoutes: []
|
|
319
322
|
};
|
|
320
323
|
const lastSegmentIsDynamic = (r) => !!r.segments.at(-1)?.at(-1)?.dynamic;
|
|
321
324
|
const redirBase = path.posix.dirname(route);
|
|
@@ -433,14 +436,20 @@ This route collides with: "${collision.component}".`
|
|
|
433
436
|
validateSegment(s);
|
|
434
437
|
return getParts(s, route);
|
|
435
438
|
});
|
|
436
|
-
routes.
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
439
|
+
const index = routes.findIndex((r) => r === fallbackToRoute);
|
|
440
|
+
if (index) {
|
|
441
|
+
const fallbackRoute = {
|
|
442
|
+
...fallbackToRoute,
|
|
443
|
+
pathname,
|
|
444
|
+
route,
|
|
445
|
+
segments,
|
|
446
|
+
pattern: getPattern(segments, config, config.trailingSlash),
|
|
447
|
+
type: "fallback",
|
|
448
|
+
fallbackRoutes: []
|
|
449
|
+
};
|
|
450
|
+
const routeData = routes[index];
|
|
451
|
+
routeData.fallbackRoutes.push(fallbackRoute);
|
|
452
|
+
}
|
|
444
453
|
}
|
|
445
454
|
}
|
|
446
455
|
}
|
|
@@ -5,6 +5,9 @@ function serializeRouteData(routeData, trailingSlash) {
|
|
|
5
5
|
generate: void 0,
|
|
6
6
|
pattern: routeData.pattern.source,
|
|
7
7
|
redirectRoute: routeData.redirectRoute ? serializeRouteData(routeData.redirectRoute, trailingSlash) : void 0,
|
|
8
|
+
fallbackRoutes: routeData.fallbackRoutes.map((fallbackRoute) => {
|
|
9
|
+
return serializeRouteData(fallbackRoute, trailingSlash);
|
|
10
|
+
}),
|
|
8
11
|
_meta: { trailingSlash }
|
|
9
12
|
};
|
|
10
13
|
}
|
|
@@ -20,7 +23,10 @@ function deserializeRouteData(rawRouteData) {
|
|
|
20
23
|
segments: rawRouteData.segments,
|
|
21
24
|
prerender: rawRouteData.prerender,
|
|
22
25
|
redirect: rawRouteData.redirect,
|
|
23
|
-
redirectRoute: rawRouteData.redirectRoute ? deserializeRouteData(rawRouteData.redirectRoute) : void 0
|
|
26
|
+
redirectRoute: rawRouteData.redirectRoute ? deserializeRouteData(rawRouteData.redirectRoute) : void 0,
|
|
27
|
+
fallbackRoutes: rawRouteData.fallbackRoutes.map((fallback) => {
|
|
28
|
+
return deserializeRouteData(fallback);
|
|
29
|
+
})
|
|
24
30
|
};
|
|
25
31
|
}
|
|
26
32
|
export {
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
function matchRoute(pathname, manifest) {
|
|
2
|
-
|
|
2
|
+
const decodedPathname = decodeURI(pathname);
|
|
3
|
+
return manifest.routes.find((route) => {
|
|
4
|
+
return route.pattern.test(decodedPathname) || route.fallbackRoutes.some((fallbackRoute) => fallbackRoute.pattern.test(decodedPathname));
|
|
5
|
+
});
|
|
3
6
|
}
|
|
4
7
|
function matchAllRoutes(pathname, manifest) {
|
|
5
8
|
return manifest.routes.filter((route) => route.pattern.test(pathname));
|
|
@@ -139,14 +139,18 @@ async function handleRoute({
|
|
|
139
139
|
prerender: false,
|
|
140
140
|
segments: [],
|
|
141
141
|
type: "fallback",
|
|
142
|
-
route: ""
|
|
142
|
+
route: "",
|
|
143
|
+
fallbackRoutes: []
|
|
143
144
|
};
|
|
144
145
|
renderContext = await createRenderContext({
|
|
145
146
|
request,
|
|
146
147
|
pathname,
|
|
147
148
|
env,
|
|
148
149
|
mod,
|
|
149
|
-
route
|
|
150
|
+
route,
|
|
151
|
+
locales: manifest.i18n?.locales,
|
|
152
|
+
routingStrategy: manifest.i18n?.routingStrategy,
|
|
153
|
+
defaultLocale: manifest.i18n?.defaultLocale
|
|
150
154
|
});
|
|
151
155
|
} else {
|
|
152
156
|
return handle404Response(origin, incomingRequest, incomingResponse);
|
|
@@ -197,7 +201,9 @@ async function handleRoute({
|
|
|
197
201
|
route: options.route,
|
|
198
202
|
mod,
|
|
199
203
|
env,
|
|
200
|
-
locales: i18n
|
|
204
|
+
locales: i18n?.locales,
|
|
205
|
+
routingStrategy: i18n?.routingStrategy,
|
|
206
|
+
defaultLocale: i18n?.defaultLocale
|
|
201
207
|
});
|
|
202
208
|
}
|
|
203
209
|
const onRequest = middleware?.onRequest;
|