astro 4.2.7 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/@types/astro.d.ts +88 -7
- package/dist/content/types-generator.js +2 -1
- package/dist/content/utils.d.ts +1 -1
- package/dist/content/utils.js +23 -11
- package/dist/core/app/index.js +55 -2
- package/dist/core/app/node.js +2 -2
- package/dist/core/app/types.d.ts +2 -1
- package/dist/core/build/common.d.ts +3 -3
- package/dist/core/build/common.js +20 -2
- package/dist/core/build/generate.js +15 -5
- package/dist/core/build/plugins/plugin-manifest.js +12 -3
- package/dist/core/build/plugins/plugin-ssr.js +8 -1
- package/dist/core/build/util.js +1 -0
- package/dist/core/config/schema.d.ts +305 -36
- package/dist/core/config/schema.js +95 -18
- package/dist/core/constants.js +1 -1
- package/dist/core/dev/dev.js +1 -1
- package/dist/core/dev/restart.js +11 -3
- package/dist/core/errors/errors-data.d.ts +10 -0
- package/dist/core/errors/errors-data.js +6 -0
- package/dist/core/logger/vite.js +7 -1
- package/dist/core/messages.d.ts +5 -0
- package/dist/core/messages.js +6 -2
- package/dist/core/render/context.js +1 -1
- package/dist/core/routing/manifest/serialization.js +2 -1
- package/dist/i18n/index.d.ts +9 -7
- package/dist/i18n/index.js +61 -12
- package/dist/i18n/middleware.js +82 -24
- package/dist/i18n/vite-plugin-i18n.d.ts +1 -0
- package/dist/i18n/vite-plugin-i18n.js +9 -2
- package/dist/integrations/astroFeaturesValidation.d.ts +2 -2
- package/dist/integrations/astroFeaturesValidation.js +20 -2
- package/dist/integrations/index.d.ts +0 -1
- package/dist/integrations/index.js +2 -8
- package/dist/runtime/server/endpoint.js +3 -1
- package/dist/virtual-modules/i18n.js +12 -3
- package/dist/vite-plugin-astro-server/plugin.js +2 -1
- package/dist/vite-plugin-astro-server/response.js +1 -5
- package/dist/vite-plugin-astro-server/route.js +3 -2
- package/dist/vite-plugin-markdown/content-entry-type.js +4 -3
- package/dist/vite-plugin-markdown/images.js +5 -2
- package/dist/vite-plugin-markdown/index.js +3 -26
- package/package.json +1 -1
- package/types.d.ts +4 -1
package/dist/@types/astro.d.ts
CHANGED
|
@@ -689,14 +689,15 @@ export interface AstroUserConfig {
|
|
|
689
689
|
* @default `'directory'`
|
|
690
690
|
* @description
|
|
691
691
|
* Control the output file format of each page. This value may be set by an adapter for you.
|
|
692
|
-
* -
|
|
693
|
-
* -
|
|
692
|
+
* - `'file'`: Astro will generate an HTML file named for each page route. (e.g. `src/pages/about.astro` and `src/pages/about/index.astro` both build the file `/about.html`)
|
|
693
|
+
* - `'directory'`: Astro will generate a directory with a nested `index.html` file for each page. (e.g. `src/pages/about.astro` and `src/pages/about/index.astro` both build the file `/about/index.html`)
|
|
694
|
+
* - `'preserve'`: Astro will generate HTML files exactly as they appear in your source folder. (e.g. `src/pages/about.astro` builds `/about.html` and `src/pages/about/index.astro` builds the file `/about/index.html`)
|
|
694
695
|
*
|
|
695
696
|
* ```js
|
|
696
697
|
* {
|
|
697
698
|
* build: {
|
|
698
699
|
* // Example: Generate `page.html` instead of `page/index.html` during build.
|
|
699
|
-
* format: '
|
|
700
|
+
* format: 'preserve'
|
|
700
701
|
* }
|
|
701
702
|
* }
|
|
702
703
|
* ```
|
|
@@ -714,7 +715,7 @@ export interface AstroUserConfig {
|
|
|
714
715
|
* - `directory` - Set `trailingSlash: 'always'`
|
|
715
716
|
* - `file` - Set `trailingSlash: 'never'`
|
|
716
717
|
*/
|
|
717
|
-
format?: 'file' | 'directory';
|
|
718
|
+
format?: 'file' | 'directory' | 'preserve';
|
|
718
719
|
/**
|
|
719
720
|
* @docs
|
|
720
721
|
* @name build.client
|
|
@@ -1412,6 +1413,44 @@ export interface AstroUserConfig {
|
|
|
1412
1413
|
* - `"pathanme": The strategy is applied to the pathname of the URLs
|
|
1413
1414
|
*/
|
|
1414
1415
|
strategy: 'pathname';
|
|
1416
|
+
/**
|
|
1417
|
+
* @name i18n.domains
|
|
1418
|
+
* @type {Record<string, string> }
|
|
1419
|
+
* @default '{}'
|
|
1420
|
+
* @version 4.3.0
|
|
1421
|
+
* @description
|
|
1422
|
+
*
|
|
1423
|
+
* Configures the URL pattern of one or more supported languages to use a custom domain (or sub-domain).
|
|
1424
|
+
*
|
|
1425
|
+
* When a locale is mapped to a domain, a `/[locale]/` path prefix will not be used.
|
|
1426
|
+
* However, localized folders within `src/pages/` are still required, including for your configured `defaultLocale`.
|
|
1427
|
+
*
|
|
1428
|
+
* Any other locale not configured will default to a localized path-based URL according to your `prefixDefaultLocale` strategy (e.g. `https://example.com/[locale]/blog`).
|
|
1429
|
+
*
|
|
1430
|
+
* ```js
|
|
1431
|
+
* //astro.config.mjs
|
|
1432
|
+
* export default defineConfig({
|
|
1433
|
+
* site: "https://example.com",
|
|
1434
|
+
* output: "server", // required, with no prerendered pages
|
|
1435
|
+
* adapter: node({
|
|
1436
|
+
* mode: 'standalone',
|
|
1437
|
+
* }),
|
|
1438
|
+
* i18n: {
|
|
1439
|
+
* defaultLocale: "en",
|
|
1440
|
+
* locales: ["en", "fr", "pt-br", "es"],
|
|
1441
|
+
* prefixDefaultLocale: false,
|
|
1442
|
+
* domains: {
|
|
1443
|
+
* fr: "https://fr.example.com",
|
|
1444
|
+
* es: "https://example.es"
|
|
1445
|
+
* },
|
|
1446
|
+
* })
|
|
1447
|
+
* ```
|
|
1448
|
+
*
|
|
1449
|
+
* Both page routes built and URLs returned by the `astro:i18n` helper functions [`getAbsoluteLocaleUrl()`](https://docs.astro.build/en/guides/internationalization/#getabsolutelocaleurl) and [`getAbsoluteLocaleUrlList()`](https://docs.astro.build/en/guides/internationalization/#getabsolutelocaleurllist) will use the options set in `i18n.domains`.
|
|
1450
|
+
*
|
|
1451
|
+
* See the [Internationalization Guide](https://docs.astro.build/en/guides/internationalization/#domains) for more details, including the limitations of this feature.
|
|
1452
|
+
*/
|
|
1453
|
+
domains?: Record<string, string>;
|
|
1415
1454
|
};
|
|
1416
1455
|
};
|
|
1417
1456
|
/** ⚠️ WARNING: SUBJECT TO CHANGE */
|
|
@@ -1538,6 +1577,47 @@ export interface AstroUserConfig {
|
|
|
1538
1577
|
* In the event of route collisions, where two routes of equal route priority attempt to build the same URL, Astro will log a warning identifying the conflicting routes.
|
|
1539
1578
|
*/
|
|
1540
1579
|
globalRoutePriority?: boolean;
|
|
1580
|
+
/**
|
|
1581
|
+
* @docs
|
|
1582
|
+
* @name experimental.i18nDomains
|
|
1583
|
+
* @type {boolean}
|
|
1584
|
+
* @default `false`
|
|
1585
|
+
* @version 4.3.0
|
|
1586
|
+
* @description
|
|
1587
|
+
*
|
|
1588
|
+
* Enables domain support for the [experimental `domains` routing strategy](https://docs.astro.build/en/guides/internationalization/#domains-experimental) which allows you to configure the URL pattern of one or more supported languages to use a custom domain (or sub-domain).
|
|
1589
|
+
*
|
|
1590
|
+
* When a locale is mapped to a domain, a `/[locale]/` path prefix will not be used. However, localized folders within `src/pages/` are still required, including for your configured `defaultLocale`.
|
|
1591
|
+
*
|
|
1592
|
+
* Any other locale not configured will default to a localized path-based URL according to your `prefixDefaultLocale` strategy (e.g. `https://example.com/[locale]/blog`).
|
|
1593
|
+
*
|
|
1594
|
+
* ```js
|
|
1595
|
+
* //astro.config.mjs
|
|
1596
|
+
* export default defineConfig({
|
|
1597
|
+
* site: "https://example.com",
|
|
1598
|
+
* output: "server", // required, with no prerendered pages
|
|
1599
|
+
* adapter: node({
|
|
1600
|
+
* mode: 'standalone',
|
|
1601
|
+
* }),
|
|
1602
|
+
* i18n: {
|
|
1603
|
+
* defaultLocale: "en",
|
|
1604
|
+
* locales: ["en", "fr", "pt-br", "es"],
|
|
1605
|
+
* prefixDefaultLocale: false,
|
|
1606
|
+
* domains: {
|
|
1607
|
+
* fr: "https://fr.example.com",
|
|
1608
|
+
* es: "https://example.es"
|
|
1609
|
+
* },
|
|
1610
|
+
* experimental: {
|
|
1611
|
+
* i18nDomains: true
|
|
1612
|
+
* }
|
|
1613
|
+
* })
|
|
1614
|
+
* ```
|
|
1615
|
+
*
|
|
1616
|
+
* Both page routes built and URLs returned by the `astro:i18n` helper functions [`getAbsoluteLocaleUrl()`](https://docs.astro.build/en/guides/internationalization/#getabsolutelocaleurl) and [`getAbsoluteLocaleUrlList()`](https://docs.astro.build/en/guides/internationalization/#getabsolutelocaleurllist) will use the options set in `i18n.domains`.
|
|
1617
|
+
*
|
|
1618
|
+
* See the [Internationalization Guide](https://docs.astro.build/en/guides/internationalization/#domains-experimental) for more details, including the limitations of this experimental feature.
|
|
1619
|
+
*/
|
|
1620
|
+
i18nDomains?: boolean;
|
|
1541
1621
|
};
|
|
1542
1622
|
}
|
|
1543
1623
|
/**
|
|
@@ -1918,7 +1998,7 @@ export type AstroFeatureMap = {
|
|
|
1918
1998
|
/**
|
|
1919
1999
|
* List of features that orbit around the i18n routing
|
|
1920
2000
|
*/
|
|
1921
|
-
|
|
2001
|
+
i18nDomains?: SupportsKind;
|
|
1922
2002
|
};
|
|
1923
2003
|
export interface AstroAssetsFeature {
|
|
1924
2004
|
supportKind?: SupportsKind;
|
|
@@ -1933,9 +2013,9 @@ export interface AstroAssetsFeature {
|
|
|
1933
2013
|
}
|
|
1934
2014
|
export interface AstroInternationalizationFeature {
|
|
1935
2015
|
/**
|
|
1936
|
-
*
|
|
2016
|
+
* The adapter should be able to create the proper redirects
|
|
1937
2017
|
*/
|
|
1938
|
-
|
|
2018
|
+
domains?: SupportsKind;
|
|
1939
2019
|
}
|
|
1940
2020
|
export type Locales = (string | {
|
|
1941
2021
|
codes: string[];
|
|
@@ -2288,6 +2368,7 @@ export interface RouteData {
|
|
|
2288
2368
|
redirect?: RedirectConfig;
|
|
2289
2369
|
redirectRoute?: RouteData;
|
|
2290
2370
|
fallbackRoutes: RouteData[];
|
|
2371
|
+
isIndex: boolean;
|
|
2291
2372
|
}
|
|
2292
2373
|
export type RedirectRouteData = RouteData & {
|
|
2293
2374
|
redirect: string;
|
|
@@ -266,7 +266,8 @@ function invalidateVirtualMod(viteServer) {
|
|
|
266
266
|
}
|
|
267
267
|
function normalizeConfigPath(from, to) {
|
|
268
268
|
const configPath = path.relative(from, to).replace(/\.ts$/, ".js");
|
|
269
|
-
|
|
269
|
+
const normalizedPath = configPath.replaceAll("\\", "/");
|
|
270
|
+
return `"${isRelativePath(configPath) ? "" : "./"}${normalizedPath}"`;
|
|
270
271
|
}
|
|
271
272
|
async function writeContentFiles({
|
|
272
273
|
fs,
|
package/dist/content/utils.d.ts
CHANGED
|
@@ -119,7 +119,7 @@ export declare function getContentEntryIdAndSlug({ entry, contentDir, collection
|
|
|
119
119
|
};
|
|
120
120
|
export declare function getEntryType(entryPath: string, paths: Pick<ContentPaths, 'config' | 'contentDir'>, contentFileExts: string[], dataFileExts: string[]): 'content' | 'data' | 'config' | 'ignored';
|
|
121
121
|
export declare function hasUnderscoreBelowContentDirectoryPath(fileUrl: URL, contentDir: ContentPaths['contentDir']): boolean;
|
|
122
|
-
export declare function
|
|
122
|
+
export declare function safeParseFrontmatter(source: string, id?: string): matter.GrayMatterFile<string>;
|
|
123
123
|
/**
|
|
124
124
|
* The content config is loaded separately from other `src/` files.
|
|
125
125
|
* This global observable lets dependent plugins (like the content flag plugin)
|
package/dist/content/utils.js
CHANGED
|
@@ -6,7 +6,8 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
|
|
6
6
|
import { normalizePath } from "vite";
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
import { AstroError, AstroErrorData } from "../core/errors/index.js";
|
|
9
|
-
import {
|
|
9
|
+
import { MarkdownError } from "../core/errors/index.js";
|
|
10
|
+
import { isYAMLException } from "../core/errors/utils.js";
|
|
10
11
|
import { CONTENT_FLAGS, CONTENT_TYPES_FILE } from "./consts.js";
|
|
11
12
|
import { errorMap } from "./error-map.js";
|
|
12
13
|
import { createImage } from "./runtime-assets.js";
|
|
@@ -199,16 +200,27 @@ function getYAMLErrorLine(rawData, objectKey) {
|
|
|
199
200
|
const numNewlinesBeforeKey = dataBeforeKey.split("\n").length;
|
|
200
201
|
return numNewlinesBeforeKey;
|
|
201
202
|
}
|
|
202
|
-
function
|
|
203
|
+
function safeParseFrontmatter(source, id) {
|
|
203
204
|
try {
|
|
204
|
-
matter
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
205
|
+
return matter(source);
|
|
206
|
+
} catch (err) {
|
|
207
|
+
const markdownError = new MarkdownError({
|
|
208
|
+
name: "MarkdownError",
|
|
209
|
+
message: err.message,
|
|
210
|
+
stack: err.stack,
|
|
211
|
+
location: id ? {
|
|
212
|
+
file: id
|
|
213
|
+
} : void 0
|
|
214
|
+
});
|
|
215
|
+
if (isYAMLException(err)) {
|
|
216
|
+
markdownError.setLocation({
|
|
217
|
+
file: id,
|
|
218
|
+
line: err.mark.line,
|
|
219
|
+
column: err.mark.column
|
|
220
|
+
});
|
|
221
|
+
markdownError.setMessage(err.reason);
|
|
211
222
|
}
|
|
223
|
+
throw markdownError;
|
|
212
224
|
}
|
|
213
225
|
}
|
|
214
226
|
const globalContentConfigObserver = contentObservable({ status: "init" });
|
|
@@ -356,6 +368,6 @@ export {
|
|
|
356
368
|
loadContentConfig,
|
|
357
369
|
msg,
|
|
358
370
|
parseEntrySlug,
|
|
359
|
-
|
|
360
|
-
|
|
371
|
+
reloadContentConfigObserver,
|
|
372
|
+
safeParseFrontmatter
|
|
361
373
|
};
|
package/dist/core/app/index.js
CHANGED
|
@@ -5,7 +5,9 @@ import { consoleLogDestination } from "../logger/console.js";
|
|
|
5
5
|
import { AstroIntegrationLogger, Logger } from "../logger/core.js";
|
|
6
6
|
import { sequence } from "../middleware/index.js";
|
|
7
7
|
import {
|
|
8
|
+
appendForwardSlash,
|
|
8
9
|
collapseDuplicateSlashes,
|
|
10
|
+
joinPaths,
|
|
9
11
|
prependForwardSlash,
|
|
10
12
|
removeTrailingForwardSlash
|
|
11
13
|
} from "../path.js";
|
|
@@ -19,6 +21,7 @@ import {
|
|
|
19
21
|
} from "../render/ssr-element.js";
|
|
20
22
|
import { matchRoute } from "../routing/match.js";
|
|
21
23
|
import { SSRRoutePipeline } from "./ssrPipeline.js";
|
|
24
|
+
import { normalizeTheLocale } from "../../i18n/index.js";
|
|
22
25
|
import { deserializeManifest } from "./common.js";
|
|
23
26
|
const localsSymbol = Symbol.for("astro.locals");
|
|
24
27
|
const clientAddressSymbol = Symbol.for("astro.clientAddress");
|
|
@@ -108,12 +111,62 @@ class App {
|
|
|
108
111
|
const url = new URL(request.url);
|
|
109
112
|
if (this.#manifest.assets.has(url.pathname))
|
|
110
113
|
return void 0;
|
|
111
|
-
|
|
112
|
-
|
|
114
|
+
let pathname = this.#computePathnameFromDomain(request);
|
|
115
|
+
if (!pathname) {
|
|
116
|
+
pathname = prependForwardSlash(this.removeBase(url.pathname));
|
|
117
|
+
}
|
|
118
|
+
let routeData = matchRoute(pathname, this.#manifestData);
|
|
113
119
|
if (!routeData || routeData.prerender)
|
|
114
120
|
return void 0;
|
|
115
121
|
return routeData;
|
|
116
122
|
}
|
|
123
|
+
#computePathnameFromDomain(request) {
|
|
124
|
+
let pathname = void 0;
|
|
125
|
+
const url = new URL(request.url);
|
|
126
|
+
if (this.#manifest.i18n && (this.#manifest.i18n.routing === "domains-prefix-always" || this.#manifest.i18n.routing === "domains-prefix-other-locales" || this.#manifest.i18n.routing === "domains-prefix-other-no-redirect")) {
|
|
127
|
+
let host = request.headers.get("X-Forwarded-Host");
|
|
128
|
+
let protocol = request.headers.get("X-Forwarded-Proto");
|
|
129
|
+
if (protocol) {
|
|
130
|
+
protocol = protocol + ":";
|
|
131
|
+
} else {
|
|
132
|
+
protocol = url.protocol;
|
|
133
|
+
}
|
|
134
|
+
if (!host) {
|
|
135
|
+
host = request.headers.get("Host");
|
|
136
|
+
}
|
|
137
|
+
if (host && protocol) {
|
|
138
|
+
host = host.split(":")[0];
|
|
139
|
+
try {
|
|
140
|
+
let locale;
|
|
141
|
+
const hostAsUrl = new URL(`${protocol}//${host}`);
|
|
142
|
+
for (const [domainKey, localeValue] of Object.entries(
|
|
143
|
+
this.#manifest.i18n.domainLookupTable
|
|
144
|
+
)) {
|
|
145
|
+
const domainKeyAsUrl = new URL(domainKey);
|
|
146
|
+
if (hostAsUrl.host === domainKeyAsUrl.host && hostAsUrl.protocol === domainKeyAsUrl.protocol) {
|
|
147
|
+
locale = localeValue;
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (locale) {
|
|
152
|
+
pathname = prependForwardSlash(
|
|
153
|
+
joinPaths(normalizeTheLocale(locale), this.removeBase(url.pathname))
|
|
154
|
+
);
|
|
155
|
+
if (url.pathname.endsWith("/")) {
|
|
156
|
+
pathname = appendForwardSlash(pathname);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
} catch (e) {
|
|
160
|
+
this.#logger.error(
|
|
161
|
+
"router",
|
|
162
|
+
`Astro tried to parse ${protocol}//${host} as an URL, but it threw a parsing error. Check the X-Forwarded-Host and X-Forwarded-Proto headers.`
|
|
163
|
+
);
|
|
164
|
+
this.#logger.error("router", `Error: ${e}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return pathname;
|
|
169
|
+
}
|
|
117
170
|
async render(request, routeDataOrOptions, maybeLocals) {
|
|
118
171
|
let routeData;
|
|
119
172
|
let locals;
|
package/dist/core/app/node.js
CHANGED
|
@@ -84,11 +84,11 @@ class NodeApp extends App {
|
|
|
84
84
|
destination.write(result.value);
|
|
85
85
|
result = await reader.read();
|
|
86
86
|
}
|
|
87
|
+
destination.end();
|
|
87
88
|
} catch {
|
|
88
|
-
destination.
|
|
89
|
+
destination.end("Internal server error");
|
|
89
90
|
}
|
|
90
91
|
}
|
|
91
|
-
destination.end();
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
function makeRequestHeaders(req) {
|
package/dist/core/app/types.d.ts
CHANGED
|
@@ -32,7 +32,7 @@ export type SSRManifest = {
|
|
|
32
32
|
site?: string;
|
|
33
33
|
base: string;
|
|
34
34
|
trailingSlash: 'always' | 'never' | 'ignore';
|
|
35
|
-
buildFormat: 'file' | 'directory';
|
|
35
|
+
buildFormat: 'file' | 'directory' | 'preserve';
|
|
36
36
|
compressHTML: boolean;
|
|
37
37
|
assetsPrefix?: string;
|
|
38
38
|
renderers: SSRLoadedRenderer[];
|
|
@@ -53,6 +53,7 @@ export type SSRManifestI18n = {
|
|
|
53
53
|
routing: RoutingStrategies;
|
|
54
54
|
locales: Locales;
|
|
55
55
|
defaultLocale: string;
|
|
56
|
+
domainLookupTable: Record<string, string>;
|
|
56
57
|
};
|
|
57
58
|
export type SerializedSSRManifest = Omit<SSRManifest, 'middleware' | 'routes' | 'assets' | 'componentMetadata' | 'clientDirectives'> & {
|
|
58
59
|
routes: SerializedRouteInfo[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { AstroConfig,
|
|
2
|
-
export declare function getOutFolder(astroConfig: AstroConfig, pathname: string,
|
|
3
|
-
export declare function getOutFile(astroConfig: AstroConfig, outFolder: URL, pathname: string,
|
|
1
|
+
import type { AstroConfig, RouteData } from '../../@types/astro.js';
|
|
2
|
+
export declare function getOutFolder(astroConfig: AstroConfig, pathname: string, routeData: RouteData): URL;
|
|
3
|
+
export declare function getOutFile(astroConfig: AstroConfig, outFolder: URL, pathname: string, routeData: RouteData): URL;
|
|
4
4
|
/**
|
|
5
5
|
* Ensures the `outDir` is within `process.cwd()`. If not it will fallback to `<cwd>/.astro`.
|
|
6
6
|
* This is used for static `ssrBuild` so the output can access node_modules when we import
|
|
@@ -10,8 +10,9 @@ function getOutRoot(astroConfig) {
|
|
|
10
10
|
return new URL("./", astroConfig.build.client);
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
-
function getOutFolder(astroConfig, pathname,
|
|
13
|
+
function getOutFolder(astroConfig, pathname, routeData) {
|
|
14
14
|
const outRoot = getOutRoot(astroConfig);
|
|
15
|
+
const routeType = routeData.type;
|
|
15
16
|
switch (routeType) {
|
|
16
17
|
case "endpoint":
|
|
17
18
|
return new URL("." + appendForwardSlash(npath.dirname(pathname)), outRoot);
|
|
@@ -29,10 +30,20 @@ function getOutFolder(astroConfig, pathname, routeType) {
|
|
|
29
30
|
const d = pathname === "" ? pathname : npath.dirname(pathname);
|
|
30
31
|
return new URL("." + appendForwardSlash(d), outRoot);
|
|
31
32
|
}
|
|
33
|
+
case "preserve": {
|
|
34
|
+
let dir;
|
|
35
|
+
if (pathname === "" || routeData.isIndex) {
|
|
36
|
+
dir = pathname;
|
|
37
|
+
} else {
|
|
38
|
+
dir = npath.dirname(pathname);
|
|
39
|
+
}
|
|
40
|
+
return new URL("." + appendForwardSlash(dir), outRoot);
|
|
41
|
+
}
|
|
32
42
|
}
|
|
33
43
|
}
|
|
34
44
|
}
|
|
35
|
-
function getOutFile(astroConfig, outFolder, pathname,
|
|
45
|
+
function getOutFile(astroConfig, outFolder, pathname, routeData) {
|
|
46
|
+
const routeType = routeData.type;
|
|
36
47
|
switch (routeType) {
|
|
37
48
|
case "endpoint":
|
|
38
49
|
return new URL(npath.basename(pathname), outFolder);
|
|
@@ -51,6 +62,13 @@ function getOutFile(astroConfig, outFolder, pathname, routeType) {
|
|
|
51
62
|
const baseName = npath.basename(pathname);
|
|
52
63
|
return new URL("./" + (baseName || "index") + ".html", outFolder);
|
|
53
64
|
}
|
|
65
|
+
case "preserve": {
|
|
66
|
+
let baseName = npath.basename(pathname);
|
|
67
|
+
if (!baseName || routeData.isIndex) {
|
|
68
|
+
baseName = "index";
|
|
69
|
+
}
|
|
70
|
+
return new URL(`./${baseName}.html`, outFolder);
|
|
71
|
+
}
|
|
54
72
|
}
|
|
55
73
|
}
|
|
56
74
|
}
|
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
mergeInlineCss
|
|
48
48
|
} from "./internal.js";
|
|
49
49
|
import { getTimeStat, shouldAppendForwardSlash } from "./util.js";
|
|
50
|
+
import { NoPrerenderedRoutesWithDomains } from "../errors/errors-data.js";
|
|
50
51
|
function createEntryURL(filePath, outFolder) {
|
|
51
52
|
return new URL("./" + filePath + `?time=${Date.now()}`, outFolder);
|
|
52
53
|
}
|
|
@@ -130,9 +131,16 @@ async function generatePages(opts, internals) {
|
|
|
130
131
|
${bgGreen(black(` ${verb} static routes `))}`);
|
|
131
132
|
const builtPaths = /* @__PURE__ */ new Set();
|
|
132
133
|
const pagesToGenerate = pipeline.retrieveRoutesToGenerate();
|
|
134
|
+
const config = pipeline.getConfig();
|
|
133
135
|
if (ssr) {
|
|
134
136
|
for (const [pageData, filePath] of pagesToGenerate) {
|
|
135
137
|
if (pageData.route.prerender) {
|
|
138
|
+
if (config.experimental.i18nDomains) {
|
|
139
|
+
throw new AstroError({
|
|
140
|
+
...NoPrerenderedRoutesWithDomains,
|
|
141
|
+
message: NoPrerenderedRoutesWithDomains.message(pageData.component)
|
|
142
|
+
});
|
|
143
|
+
}
|
|
136
144
|
const ssrEntryURLPage = createEntryURL(filePath, outFolder);
|
|
137
145
|
const ssrEntryPage = await import(ssrEntryURLPage.toString());
|
|
138
146
|
if (opts.settings.adapter?.adapterFeatures?.functionPerRoute) {
|
|
@@ -334,8 +342,8 @@ function addPageName(pathname, opts) {
|
|
|
334
342
|
const pageName = shouldAppendForwardSlash(trailingSlash, buildFormat) ? pathname.replace(/\/?$/, "/").replace(/^\//, "") : pathname.replace(/^\//, "");
|
|
335
343
|
opts.pageNames.push(pageName);
|
|
336
344
|
}
|
|
337
|
-
function getUrlForPath(pathname, base, origin, format, routeType) {
|
|
338
|
-
const ending = format === "directory" ? "/" : ".html";
|
|
345
|
+
function getUrlForPath(pathname, base, origin, format, trailingSlash, routeType) {
|
|
346
|
+
const ending = format === "directory" ? trailingSlash === "never" ? "" : "/" : ".html";
|
|
339
347
|
let buildPathname;
|
|
340
348
|
if (pathname === "/" || pathname === "") {
|
|
341
349
|
buildPathname = base;
|
|
@@ -389,6 +397,7 @@ async function generatePath(pathname, pipeline, gopts, route) {
|
|
|
389
397
|
pipeline.getConfig().base,
|
|
390
398
|
pipeline.getStaticBuildOptions().origin,
|
|
391
399
|
pipeline.getConfig().build.format,
|
|
400
|
+
pipeline.getConfig().trailingSlash,
|
|
392
401
|
route.type
|
|
393
402
|
);
|
|
394
403
|
const request = createRequest({
|
|
@@ -450,8 +459,8 @@ async function generatePath(pathname, pipeline, gopts, route) {
|
|
|
450
459
|
return;
|
|
451
460
|
body = Buffer.from(await response.arrayBuffer());
|
|
452
461
|
}
|
|
453
|
-
const outFolder = getOutFolder(pipeline.getConfig(), pathname, route
|
|
454
|
-
const outFile = getOutFile(pipeline.getConfig(), outFolder, pathname, route
|
|
462
|
+
const outFolder = getOutFolder(pipeline.getConfig(), pathname, route);
|
|
463
|
+
const outFile = getOutFile(pipeline.getConfig(), outFolder, pathname, route);
|
|
455
464
|
route.distURL = outFile;
|
|
456
465
|
await fs.promises.mkdir(outFolder, { recursive: true });
|
|
457
466
|
await fs.promises.writeFile(outFile, body);
|
|
@@ -472,7 +481,8 @@ function createBuildManifest(settings, internals, renderers, middleware) {
|
|
|
472
481
|
fallback: settings.config.i18n.fallback,
|
|
473
482
|
routing: settings.config.i18n.routing,
|
|
474
483
|
defaultLocale: settings.config.i18n.defaultLocale,
|
|
475
|
-
locales: settings.config.i18n.locales
|
|
484
|
+
locales: settings.config.i18n.locales,
|
|
485
|
+
domainLookupTable: {}
|
|
476
486
|
};
|
|
477
487
|
}
|
|
478
488
|
return {
|
|
@@ -8,6 +8,7 @@ import { serializeRouteData } from "../../routing/index.js";
|
|
|
8
8
|
import { addRollupInput } from "../add-rollup-input.js";
|
|
9
9
|
import { getOutFile, getOutFolder } from "../common.js";
|
|
10
10
|
import { cssOrder, mergeInlineCss } from "../internal.js";
|
|
11
|
+
import { normalizeTheLocale } from "../../../i18n/index.js";
|
|
11
12
|
const manifestReplace = "@@ASTRO_MANIFEST_REPLACE@@";
|
|
12
13
|
const replaceExp = new RegExp(`['"](${manifestReplace})['"]`, "g");
|
|
13
14
|
const SSR_MANIFEST_VIRTUAL_MODULE_ID = "@astrojs-manifest";
|
|
@@ -111,6 +112,7 @@ function injectManifest(manifest, chunk) {
|
|
|
111
112
|
function buildManifest(opts, internals, staticFiles) {
|
|
112
113
|
const { settings } = opts;
|
|
113
114
|
const routes = [];
|
|
115
|
+
const domainLookupTable = {};
|
|
114
116
|
const entryModules = Object.fromEntries(internals.entrySpecifierToBundleMap.entries());
|
|
115
117
|
if (settings.scripts.some((script) => script.stage === "page")) {
|
|
116
118
|
staticFiles.push(entryModules[PAGE_SCRIPT_ID]);
|
|
@@ -127,8 +129,8 @@ function buildManifest(opts, internals, staticFiles) {
|
|
|
127
129
|
continue;
|
|
128
130
|
if (!route.pathname)
|
|
129
131
|
continue;
|
|
130
|
-
const outFolder = getOutFolder(opts.settings.config, route.pathname, route
|
|
131
|
-
const outFile = getOutFile(opts.settings.config, outFolder, route.pathname, route
|
|
132
|
+
const outFolder = getOutFolder(opts.settings.config, route.pathname, route);
|
|
133
|
+
const outFile = getOutFile(opts.settings.config, outFolder, route.pathname, route);
|
|
132
134
|
const file = outFile.toString().replace(opts.settings.config.build.client.toString(), "");
|
|
133
135
|
routes.push({
|
|
134
136
|
file,
|
|
@@ -174,6 +176,12 @@ function buildManifest(opts, internals, staticFiles) {
|
|
|
174
176
|
routeData: serializeRouteData(route, settings.config.trailingSlash)
|
|
175
177
|
});
|
|
176
178
|
}
|
|
179
|
+
const i18n = settings.config.i18n;
|
|
180
|
+
if (settings.config.experimental.i18nDomains && i18n && i18n.domains && (i18n.routing === "domains-prefix-always" || i18n.routing === "domains-prefix-other-locales" || i18n.routing === "domains-prefix-other-no-redirect")) {
|
|
181
|
+
for (const [locale, domainValue] of Object.entries(i18n.domains)) {
|
|
182
|
+
domainLookupTable[domainValue] = normalizeTheLocale(locale);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
177
185
|
if (!(BEFORE_HYDRATION_SCRIPT_ID in entryModules)) {
|
|
178
186
|
entryModules[BEFORE_HYDRATION_SCRIPT_ID] = "";
|
|
179
187
|
}
|
|
@@ -183,7 +191,8 @@ function buildManifest(opts, internals, staticFiles) {
|
|
|
183
191
|
fallback: settings.config.i18n.fallback,
|
|
184
192
|
routing: settings.config.i18n.routing,
|
|
185
193
|
locales: settings.config.i18n.locales,
|
|
186
|
-
defaultLocale: settings.config.i18n.defaultLocale
|
|
194
|
+
defaultLocale: settings.config.i18n.defaultLocale,
|
|
195
|
+
domainLookupTable
|
|
187
196
|
};
|
|
188
197
|
}
|
|
189
198
|
return {
|
|
@@ -210,7 +210,14 @@ function generateSSRCode(adapter, middlewareId) {
|
|
|
210
210
|
return `export const ${name} = _exports['${name}'];`;
|
|
211
211
|
}
|
|
212
212
|
}) ?? [],
|
|
213
|
-
|
|
213
|
+
// NOTE: This is intentionally obfuscated!
|
|
214
|
+
// Do NOT simplify this to something like `serverEntrypointModule.start?.(_manifest, _args)`
|
|
215
|
+
// They are NOT equivalent! Some bundlers will throw if `start` is not exported, but we
|
|
216
|
+
// only want to silently ignore it... hence the dynamic, obfuscated weirdness.
|
|
217
|
+
`const _start = 'start';
|
|
218
|
+
if (_start in serverEntrypointModule) {
|
|
219
|
+
serverEntrypointModule[_start](_manifest, _args);
|
|
220
|
+
}`
|
|
214
221
|
];
|
|
215
222
|
return {
|
|
216
223
|
imports,
|