astro 5.6.2 → 5.7.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.
- package/client.d.ts +3 -0
- package/components/Font.astro +32 -0
- package/dist/actions/plugins.js +2 -2
- package/dist/assets/fonts/config.d.ts +378 -0
- package/dist/assets/fonts/config.js +157 -0
- package/dist/assets/fonts/constants.d.ts +15 -0
- package/dist/assets/fonts/constants.js +41 -0
- package/dist/assets/fonts/load.d.ts +20 -0
- package/dist/assets/fonts/load.js +135 -0
- package/dist/assets/fonts/metrics.d.ts +9 -0
- package/dist/assets/fonts/metrics.js +61 -0
- package/dist/assets/fonts/providers/entrypoints/adobe.d.ts +2 -0
- package/dist/assets/fonts/providers/entrypoints/adobe.js +5 -0
- package/dist/assets/fonts/providers/entrypoints/bunny.d.ts +1 -0
- package/dist/assets/fonts/providers/entrypoints/bunny.js +5 -0
- package/dist/assets/fonts/providers/entrypoints/fontshare.d.ts +1 -0
- package/dist/assets/fonts/providers/entrypoints/fontshare.js +5 -0
- package/dist/assets/fonts/providers/entrypoints/fontsource.d.ts +1 -0
- package/dist/assets/fonts/providers/entrypoints/fontsource.js +5 -0
- package/dist/assets/fonts/providers/entrypoints/google.d.ts +2 -0
- package/dist/assets/fonts/providers/entrypoints/google.js +5 -0
- package/dist/assets/fonts/providers/index.d.ts +48 -0
- package/dist/assets/fonts/providers/index.js +40 -0
- package/dist/assets/fonts/providers/local.d.ts +10 -0
- package/dist/assets/fonts/providers/local.js +30 -0
- package/dist/assets/fonts/providers/utils.d.ts +9 -0
- package/dist/assets/fonts/providers/utils.js +37 -0
- package/dist/assets/fonts/sync.d.ts +2 -0
- package/dist/assets/fonts/sync.js +17 -0
- package/dist/assets/fonts/types.d.ts +45 -0
- package/dist/assets/fonts/types.js +0 -0
- package/dist/assets/fonts/utils.d.ts +92 -0
- package/dist/assets/fonts/utils.js +215 -0
- package/dist/assets/fonts/vite-plugin-fonts.d.ts +10 -0
- package/dist/assets/fonts/vite-plugin-fonts.js +212 -0
- package/dist/assets/utils/node/emitAsset.d.ts +4 -2
- package/dist/assets/utils/node/emitAsset.js +1 -1
- package/dist/assets/utils/vendor/image-size/types/index.d.ts +2 -2
- package/dist/assets/vite-plugin-assets.d.ts +8 -3
- package/dist/assets/vite-plugin-assets.js +7 -7
- package/dist/config/entrypoint.d.ts +2 -0
- package/dist/config/entrypoint.js +3 -0
- package/dist/config/index.d.ts +2 -1
- package/dist/content/content-layer.js +5 -4
- package/dist/content/runtime-assets.js +1 -0
- package/dist/content/vite-plugin-content-imports.js +4 -2
- package/dist/core/build/generate.js +2 -2
- package/dist/core/build/pipeline.js +2 -2
- package/dist/core/build/static-build.js +2 -2
- package/dist/core/config/schemas/base.d.ts +436 -39
- package/dist/core/config/schemas/base.js +3 -7
- package/dist/core/config/schemas/refined.js +12 -0
- package/dist/core/config/schemas/relative.d.ts +567 -63
- package/dist/core/config/schemas/relative.js +1 -2
- package/dist/core/constants.js +1 -1
- package/dist/core/create-vite.js +2 -2
- package/dist/core/dev/dev.js +1 -1
- package/dist/core/errors/errors-data.d.ts +82 -26
- package/dist/core/errors/errors-data.js +45 -16
- package/dist/core/logger/core.d.ts +1 -1
- package/dist/core/messages.js +2 -2
- package/dist/core/middleware/vite-plugin.js +2 -2
- package/dist/core/render-context.js +38 -5
- package/dist/core/routing/rewrite.js +14 -5
- package/dist/core/session.d.ts +4 -6
- package/dist/core/session.js +4 -29
- package/dist/core/sync/index.js +2 -0
- package/dist/integrations/hooks.js +2 -3
- package/dist/manifest/virtual-module.d.ts +1 -5
- package/dist/manifest/virtual-module.js +1 -18
- package/dist/prerender/utils.d.ts +5 -1
- package/dist/prerender/utils.js +8 -8
- package/dist/runtime/client/dev-toolbar/apps/audit/annotations.d.ts +6 -0
- package/dist/runtime/client/dev-toolbar/apps/audit/annotations.js +27 -0
- package/dist/runtime/client/dev-toolbar/apps/audit/index.js +10 -4
- package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-ui.js +2 -2
- package/dist/types/public/config.d.ts +155 -98
- package/dist/vite-plugin-astro-server/plugin.js +1 -1
- package/package.json +7 -4
- package/types/fonts.d.ts +4 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { extname } from "node:path";
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
4
|
+
import { AstroError, AstroErrorData } from "../../core/errors/index.js";
|
|
5
|
+
import { DEFAULT_FALLBACKS, FONT_TYPES, LOCAL_PROVIDER_NAME } from "./constants.js";
|
|
6
|
+
import { resolveProvider } from "./providers/utils.js";
|
|
7
|
+
function generateFontFace(family, font) {
|
|
8
|
+
return [
|
|
9
|
+
"@font-face {",
|
|
10
|
+
` font-family: ${family};`,
|
|
11
|
+
` src: ${renderFontSrc(font.src)};`,
|
|
12
|
+
` font-display: ${font.display ?? "swap"};`,
|
|
13
|
+
font.unicodeRange && ` unicode-range: ${font.unicodeRange};`,
|
|
14
|
+
font.weight && ` font-weight: ${Array.isArray(font.weight) ? font.weight.join(" ") : font.weight};`,
|
|
15
|
+
font.style && ` font-style: ${font.style};`,
|
|
16
|
+
font.stretch && ` font-stretch: ${font.stretch};`,
|
|
17
|
+
font.featureSettings && ` font-feature-settings: ${font.featureSettings};`,
|
|
18
|
+
font.variationSettings && ` font-variation-settings: ${font.variationSettings};`,
|
|
19
|
+
`}`
|
|
20
|
+
].filter(Boolean).join("\n");
|
|
21
|
+
}
|
|
22
|
+
function renderFontSrc(sources) {
|
|
23
|
+
return sources.map((src) => {
|
|
24
|
+
if ("url" in src) {
|
|
25
|
+
let rendered = `url("${src.url}")`;
|
|
26
|
+
for (const key of ["format", "tech"]) {
|
|
27
|
+
if (key in src) {
|
|
28
|
+
rendered += ` ${key}(${src[key]})`;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return rendered;
|
|
32
|
+
}
|
|
33
|
+
return `local("${src.name}")`;
|
|
34
|
+
}).join(", ");
|
|
35
|
+
}
|
|
36
|
+
function extractFontType(str) {
|
|
37
|
+
const extension = extname(str).slice(1);
|
|
38
|
+
if (!isFontType(extension)) {
|
|
39
|
+
throw new AstroError(
|
|
40
|
+
{
|
|
41
|
+
...AstroErrorData.CannotExtractFontType,
|
|
42
|
+
message: AstroErrorData.CannotExtractFontType.message(str)
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
cause: `Unexpected extension, got "${extension}"`
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
return extension;
|
|
50
|
+
}
|
|
51
|
+
function isFontType(str) {
|
|
52
|
+
return FONT_TYPES.includes(str);
|
|
53
|
+
}
|
|
54
|
+
async function cache(storage, key, cb) {
|
|
55
|
+
const existing = await storage.getItemRaw(key);
|
|
56
|
+
if (existing) {
|
|
57
|
+
return existing;
|
|
58
|
+
}
|
|
59
|
+
const data = await cb();
|
|
60
|
+
await storage.setItemRaw(key, data);
|
|
61
|
+
return data;
|
|
62
|
+
}
|
|
63
|
+
function proxyURL({ value, hashString, collect }) {
|
|
64
|
+
const type = extractFontType(value);
|
|
65
|
+
const hash = `${hashString(value)}.${type}`;
|
|
66
|
+
const url = collect({ hash, type, value });
|
|
67
|
+
return url;
|
|
68
|
+
}
|
|
69
|
+
function isGenericFontFamily(str) {
|
|
70
|
+
return Object.keys(DEFAULT_FALLBACKS).includes(str);
|
|
71
|
+
}
|
|
72
|
+
async function generateFallbacksCSS({
|
|
73
|
+
family,
|
|
74
|
+
fallbacks: _fallbacks,
|
|
75
|
+
font: fontData,
|
|
76
|
+
metrics
|
|
77
|
+
}) {
|
|
78
|
+
let fallbacks = [..._fallbacks];
|
|
79
|
+
if (fallbacks.length === 0) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
let css = "";
|
|
83
|
+
if (!fontData || !metrics) {
|
|
84
|
+
return { css, fallbacks };
|
|
85
|
+
}
|
|
86
|
+
const lastFallback = fallbacks[fallbacks.length - 1];
|
|
87
|
+
if (!isGenericFontFamily(lastFallback)) {
|
|
88
|
+
return { css, fallbacks };
|
|
89
|
+
}
|
|
90
|
+
const localFonts = DEFAULT_FALLBACKS[lastFallback];
|
|
91
|
+
if (localFonts.length === 0) {
|
|
92
|
+
return { css, fallbacks };
|
|
93
|
+
}
|
|
94
|
+
const foundMetrics = await metrics.getMetricsForFamily(family.name, fontData);
|
|
95
|
+
if (!foundMetrics) {
|
|
96
|
+
return { css, fallbacks };
|
|
97
|
+
}
|
|
98
|
+
const localFontsMappings = localFonts.map((font) => ({
|
|
99
|
+
font,
|
|
100
|
+
name: `"${family.nameWithHash} fallback: ${font}"`
|
|
101
|
+
}));
|
|
102
|
+
fallbacks = [.../* @__PURE__ */ new Set([...localFontsMappings.map((m) => m.name), ...fallbacks])];
|
|
103
|
+
for (const { font, name } of localFontsMappings) {
|
|
104
|
+
css += metrics.generateFontFace(foundMetrics, { font, name });
|
|
105
|
+
}
|
|
106
|
+
return { css, fallbacks };
|
|
107
|
+
}
|
|
108
|
+
function dedupe(arr) {
|
|
109
|
+
return [...new Set(arr)];
|
|
110
|
+
}
|
|
111
|
+
function resolveVariants({
|
|
112
|
+
variants,
|
|
113
|
+
root
|
|
114
|
+
}) {
|
|
115
|
+
return variants.map((variant) => ({
|
|
116
|
+
...variant,
|
|
117
|
+
weight: variant.weight.toString(),
|
|
118
|
+
src: variant.src.map((value) => {
|
|
119
|
+
const isValue = typeof value === "string" || value instanceof URL;
|
|
120
|
+
const url = (isValue ? value : value.url).toString();
|
|
121
|
+
const tech = isValue ? void 0 : value.tech;
|
|
122
|
+
return {
|
|
123
|
+
url: fileURLToPath(resolveEntrypoint(root, url)),
|
|
124
|
+
tech
|
|
125
|
+
};
|
|
126
|
+
})
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
async function resolveFontFamily({
|
|
130
|
+
family,
|
|
131
|
+
generateNameWithHash,
|
|
132
|
+
root,
|
|
133
|
+
resolveMod
|
|
134
|
+
}) {
|
|
135
|
+
const nameWithHash = generateNameWithHash(family);
|
|
136
|
+
if (family.provider === LOCAL_PROVIDER_NAME) {
|
|
137
|
+
return {
|
|
138
|
+
...family,
|
|
139
|
+
nameWithHash,
|
|
140
|
+
variants: resolveVariants({ variants: family.variants, root }),
|
|
141
|
+
fallbacks: family.fallbacks ? dedupe(family.fallbacks) : void 0
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
...family,
|
|
146
|
+
nameWithHash,
|
|
147
|
+
provider: await resolveProvider({
|
|
148
|
+
root,
|
|
149
|
+
resolveMod,
|
|
150
|
+
provider: family.provider
|
|
151
|
+
}),
|
|
152
|
+
weights: family.weights ? dedupe(family.weights.map((weight) => weight.toString())) : void 0,
|
|
153
|
+
styles: family.styles ? dedupe(family.styles) : void 0,
|
|
154
|
+
subsets: family.subsets ? dedupe(family.subsets) : void 0,
|
|
155
|
+
fallbacks: family.fallbacks ? dedupe(family.fallbacks) : void 0,
|
|
156
|
+
unicodeRange: family.unicodeRange ? dedupe(family.unicodeRange) : void 0
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
function sortObjectByKey(unordered) {
|
|
160
|
+
const ordered = Object.keys(unordered).sort().reduce((obj, key) => {
|
|
161
|
+
obj[key] = unordered[key];
|
|
162
|
+
return obj;
|
|
163
|
+
}, {});
|
|
164
|
+
return ordered;
|
|
165
|
+
}
|
|
166
|
+
function familiesToUnifontProviders({
|
|
167
|
+
families,
|
|
168
|
+
hashString
|
|
169
|
+
}) {
|
|
170
|
+
const hashes = /* @__PURE__ */ new Set();
|
|
171
|
+
const providers = [];
|
|
172
|
+
for (const { provider } of families) {
|
|
173
|
+
if (provider === LOCAL_PROVIDER_NAME) {
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
const unifontProvider = provider.provider(provider.config);
|
|
177
|
+
const hash = hashString(
|
|
178
|
+
JSON.stringify(
|
|
179
|
+
sortObjectByKey({
|
|
180
|
+
name: unifontProvider._name,
|
|
181
|
+
...provider.config
|
|
182
|
+
})
|
|
183
|
+
)
|
|
184
|
+
);
|
|
185
|
+
if (hashes.has(hash)) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
unifontProvider._name += `-${hash}`;
|
|
189
|
+
provider.name = unifontProvider._name;
|
|
190
|
+
hashes.add(hash);
|
|
191
|
+
providers.push(unifontProvider);
|
|
192
|
+
}
|
|
193
|
+
return { families, providers };
|
|
194
|
+
}
|
|
195
|
+
function resolveEntrypoint(root, entrypoint) {
|
|
196
|
+
const require2 = createRequire(root);
|
|
197
|
+
try {
|
|
198
|
+
return pathToFileURL(require2.resolve(entrypoint));
|
|
199
|
+
} catch {
|
|
200
|
+
return new URL(entrypoint, root);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
export {
|
|
204
|
+
cache,
|
|
205
|
+
extractFontType,
|
|
206
|
+
familiesToUnifontProviders,
|
|
207
|
+
generateFallbacksCSS,
|
|
208
|
+
generateFontFace,
|
|
209
|
+
isFontType,
|
|
210
|
+
isGenericFontFamily,
|
|
211
|
+
proxyURL,
|
|
212
|
+
resolveEntrypoint,
|
|
213
|
+
resolveFontFamily,
|
|
214
|
+
sortObjectByKey
|
|
215
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Plugin } from 'vite';
|
|
2
|
+
import type { Logger } from '../../core/logger/core.js';
|
|
3
|
+
import type { AstroSettings } from '../../types/astro.js';
|
|
4
|
+
interface Options {
|
|
5
|
+
settings: AstroSettings;
|
|
6
|
+
sync: boolean;
|
|
7
|
+
logger: Logger;
|
|
8
|
+
}
|
|
9
|
+
export declare function fontsPlugin({ settings, sync, logger }: Options): Plugin;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { isAbsolute } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { removeTrailingForwardSlash } from "@astrojs/internal-helpers/path";
|
|
6
|
+
import { createStorage } from "unstorage";
|
|
7
|
+
import fsLiteDriver from "unstorage/drivers/fs-lite";
|
|
8
|
+
import xxhash from "xxhash-wasm";
|
|
9
|
+
import { collectErrorMetadata } from "../../core/errors/dev/utils.js";
|
|
10
|
+
import { AstroError, AstroErrorData, isAstroError } from "../../core/errors/index.js";
|
|
11
|
+
import { formatErrorMessage } from "../../core/messages.js";
|
|
12
|
+
import { getClientOutputDirectory } from "../../prerender/utils.js";
|
|
13
|
+
import {
|
|
14
|
+
CACHE_DIR,
|
|
15
|
+
RESOLVED_VIRTUAL_MODULE_ID,
|
|
16
|
+
URL_PREFIX,
|
|
17
|
+
VIRTUAL_MODULE_ID
|
|
18
|
+
} from "./constants.js";
|
|
19
|
+
import { loadFonts } from "./load.js";
|
|
20
|
+
import { generateFallbackFontFace, readMetrics } from "./metrics.js";
|
|
21
|
+
import { cache, extractFontType, resolveFontFamily, sortObjectByKey } from "./utils.js";
|
|
22
|
+
async function fetchFont(url) {
|
|
23
|
+
try {
|
|
24
|
+
if (isAbsolute(url)) {
|
|
25
|
+
return await readFile(url);
|
|
26
|
+
}
|
|
27
|
+
const response = await fetch(url);
|
|
28
|
+
if (!response.ok) {
|
|
29
|
+
throw new Error(`Response was not successful, received status code ${response.status}`);
|
|
30
|
+
}
|
|
31
|
+
return Buffer.from(await response.arrayBuffer());
|
|
32
|
+
} catch (cause) {
|
|
33
|
+
throw new AstroError(
|
|
34
|
+
{
|
|
35
|
+
...AstroErrorData.CannotFetchFontFile,
|
|
36
|
+
message: AstroErrorData.CannotFetchFontFile.message(url)
|
|
37
|
+
},
|
|
38
|
+
{ cause }
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function fontsPlugin({ settings, sync, logger }) {
|
|
43
|
+
if (!settings.config.experimental.fonts) {
|
|
44
|
+
return {
|
|
45
|
+
name: "astro:fonts:fallback",
|
|
46
|
+
config() {
|
|
47
|
+
return {
|
|
48
|
+
build: {
|
|
49
|
+
rollupOptions: {
|
|
50
|
+
external: [VIRTUAL_MODULE_ID]
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const baseUrl = removeTrailingForwardSlash(settings.config.base) + URL_PREFIX;
|
|
58
|
+
let resolvedMap = null;
|
|
59
|
+
let hashToUrlMap = null;
|
|
60
|
+
let isBuild;
|
|
61
|
+
let storage = null;
|
|
62
|
+
const cleanup = () => {
|
|
63
|
+
resolvedMap = null;
|
|
64
|
+
hashToUrlMap = null;
|
|
65
|
+
storage = null;
|
|
66
|
+
};
|
|
67
|
+
async function initialize({ resolveMod, base }) {
|
|
68
|
+
const { h64ToString } = await xxhash();
|
|
69
|
+
storage = createStorage({
|
|
70
|
+
// Types are weirly exported
|
|
71
|
+
driver: fsLiteDriver({
|
|
72
|
+
base: fileURLToPath(base)
|
|
73
|
+
})
|
|
74
|
+
});
|
|
75
|
+
hashToUrlMap = /* @__PURE__ */ new Map();
|
|
76
|
+
resolvedMap = /* @__PURE__ */ new Map();
|
|
77
|
+
const families = [];
|
|
78
|
+
for (const family of settings.config.experimental.fonts) {
|
|
79
|
+
families.push(
|
|
80
|
+
await resolveFontFamily({
|
|
81
|
+
family,
|
|
82
|
+
root: settings.config.root,
|
|
83
|
+
resolveMod,
|
|
84
|
+
generateNameWithHash: (_family) => `${_family.name}-${h64ToString(JSON.stringify(sortObjectByKey(_family)))}`
|
|
85
|
+
})
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
await loadFonts({
|
|
89
|
+
base: baseUrl,
|
|
90
|
+
families,
|
|
91
|
+
storage,
|
|
92
|
+
hashToUrlMap,
|
|
93
|
+
resolvedMap,
|
|
94
|
+
hashString: h64ToString,
|
|
95
|
+
generateFallbackFontFace,
|
|
96
|
+
getMetricsForFamily: async (name, font) => {
|
|
97
|
+
return await readMetrics(name, await cache(storage, font.hash, () => fetchFont(font.url)));
|
|
98
|
+
},
|
|
99
|
+
log: (message) => logger.info("assets", message)
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
name: "astro:fonts",
|
|
104
|
+
config(_, { command }) {
|
|
105
|
+
isBuild = command === "build";
|
|
106
|
+
},
|
|
107
|
+
async buildStart() {
|
|
108
|
+
if (isBuild) {
|
|
109
|
+
await initialize({
|
|
110
|
+
resolveMod: (id) => import(id),
|
|
111
|
+
base: new URL(CACHE_DIR, settings.config.cacheDir)
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
async configureServer(server) {
|
|
116
|
+
await initialize({
|
|
117
|
+
resolveMod: (id) => server.ssrLoadModule(id),
|
|
118
|
+
// In dev, we cache fonts data in .astro so it can be easily inspected and cleared
|
|
119
|
+
base: new URL(CACHE_DIR, settings.dotAstroDir)
|
|
120
|
+
});
|
|
121
|
+
const localPaths = [...hashToUrlMap.values()].filter((url) => isAbsolute(url));
|
|
122
|
+
server.watcher.on("change", (path) => {
|
|
123
|
+
if (localPaths.includes(path)) {
|
|
124
|
+
logger.info("assets", "Font file updated");
|
|
125
|
+
server.restart();
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
server.watcher.on("unlink", (path) => {
|
|
129
|
+
if (localPaths.includes(path)) {
|
|
130
|
+
logger.warn(
|
|
131
|
+
"assets",
|
|
132
|
+
`The font file ${JSON.stringify(path)} referenced in your config has been deleted. Restore the file or remove this font from your configuration if it is no longer needed.`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
server.middlewares.use(URL_PREFIX, async (req, res, next) => {
|
|
137
|
+
if (!req.url) {
|
|
138
|
+
return next();
|
|
139
|
+
}
|
|
140
|
+
const hash = req.url.slice(1);
|
|
141
|
+
const url = hashToUrlMap?.get(hash);
|
|
142
|
+
if (!url) {
|
|
143
|
+
return next();
|
|
144
|
+
}
|
|
145
|
+
res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
|
|
146
|
+
res.setHeader("Pragma", "no-cache");
|
|
147
|
+
res.setHeader("Expires", 0);
|
|
148
|
+
try {
|
|
149
|
+
const data = await cache(storage, hash, () => fetchFont(url));
|
|
150
|
+
res.setHeader("Content-Length", data.length);
|
|
151
|
+
res.setHeader("Content-Type", `font/${extractFontType(hash)}`);
|
|
152
|
+
res.end(data);
|
|
153
|
+
} catch (err) {
|
|
154
|
+
logger.error("assets", "Cannot download font file");
|
|
155
|
+
if (isAstroError(err)) {
|
|
156
|
+
logger.error(
|
|
157
|
+
"SKIP_FORMAT",
|
|
158
|
+
formatErrorMessage(collectErrorMetadata(err), logger.level() === "debug")
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
res.statusCode = 500;
|
|
162
|
+
res.end();
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
},
|
|
166
|
+
resolveId(id) {
|
|
167
|
+
if (id === VIRTUAL_MODULE_ID) {
|
|
168
|
+
return RESOLVED_VIRTUAL_MODULE_ID;
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
load(id) {
|
|
172
|
+
if (id === RESOLVED_VIRTUAL_MODULE_ID) {
|
|
173
|
+
return {
|
|
174
|
+
code: `export const fontsData = new Map(${JSON.stringify(Array.from(resolvedMap?.entries() ?? []))})`
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
async buildEnd() {
|
|
179
|
+
if (sync || settings.config.experimental.fonts.length === 0) {
|
|
180
|
+
cleanup();
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
const dir = getClientOutputDirectory(settings);
|
|
185
|
+
const fontsDir = new URL("." + baseUrl, dir);
|
|
186
|
+
try {
|
|
187
|
+
mkdirSync(fontsDir, { recursive: true });
|
|
188
|
+
} catch (cause) {
|
|
189
|
+
throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause });
|
|
190
|
+
}
|
|
191
|
+
if (hashToUrlMap) {
|
|
192
|
+
logger.info("assets", "Copying fonts...");
|
|
193
|
+
await Promise.all(
|
|
194
|
+
Array.from(hashToUrlMap.entries()).map(async ([hash, url]) => {
|
|
195
|
+
const data = await cache(storage, hash, () => fetchFont(url));
|
|
196
|
+
try {
|
|
197
|
+
writeFileSync(new URL(hash, fontsDir), data);
|
|
198
|
+
} catch (cause) {
|
|
199
|
+
throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause });
|
|
200
|
+
}
|
|
201
|
+
})
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
} finally {
|
|
205
|
+
cleanup();
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
export {
|
|
211
|
+
fontsPlugin
|
|
212
|
+
};
|
|
@@ -9,13 +9,15 @@ type ImageMetadataWithContents = ImageMetadata & {
|
|
|
9
9
|
*
|
|
10
10
|
* @param {string | undefined} id - The identifier or path of the image file to process. If undefined, the function returns immediately.
|
|
11
11
|
* @param {boolean} _watchMode - **Deprecated**: Indicates if the method is operating in watch mode. This parameter will be removed or updated in the future.
|
|
12
|
-
* @param {boolean}
|
|
12
|
+
* @param {boolean} _experimentalSvgEnabled - **Deprecated**: A flag to enable experimental handling of SVG files. Embeds SVG file data if set to true.
|
|
13
13
|
* @param {FileEmitter | undefined} [fileEmitter] - Function for emitting files during the build process. May throw in certain scenarios.
|
|
14
14
|
* @return {Promise<ImageMetadataWithContents | undefined>} Resolves to metadata with optional image contents or `undefined` if processing fails.
|
|
15
15
|
*/
|
|
16
16
|
export declare function emitESMImage(id: string | undefined,
|
|
17
17
|
/** @deprecated */
|
|
18
|
-
_watchMode: boolean,
|
|
18
|
+
_watchMode: boolean,
|
|
19
|
+
/** @deprecated */
|
|
20
|
+
_experimentalSvgEnabled: boolean, fileEmitter?: FileEmitter): Promise<ImageMetadataWithContents | undefined>;
|
|
19
21
|
/**
|
|
20
22
|
* Processes an image file and emits its metadata and optionally its contents. This function supports both build and development modes.
|
|
21
23
|
*
|
|
@@ -3,7 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
4
4
|
import { prependForwardSlash, slash } from "../../../core/path.js";
|
|
5
5
|
import { imageMetadata } from "../metadata.js";
|
|
6
|
-
async function emitESMImage(id, _watchMode,
|
|
6
|
+
async function emitESMImage(id, _watchMode, _experimentalSvgEnabled, fileEmitter) {
|
|
7
7
|
if (!id) {
|
|
8
8
|
return void 0;
|
|
9
9
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export declare const typeHandlers: Map<"
|
|
2
|
-
export declare const types: ("
|
|
1
|
+
export declare const typeHandlers: Map<"jpg" | "png" | "tiff" | "webp" | "gif" | "svg" | "heif" | "icns" | "ktx" | "bmp" | "cur" | "dds" | "ico" | "j2c" | "jp2" | "pnm" | "psd" | "tga", import("./interface.js").IImage>;
|
|
2
|
+
export declare const types: ("jpg" | "png" | "tiff" | "webp" | "gif" | "svg" | "heif" | "icns" | "ktx" | "bmp" | "cur" | "dds" | "ico" | "j2c" | "jp2" | "pnm" | "psd" | "tga")[];
|
|
3
3
|
export type imageType = typeof types[number];
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import type * as fsMod from 'node:fs';
|
|
2
2
|
import type * as vite from 'vite';
|
|
3
|
+
import type { Logger } from '../core/logger/core.js';
|
|
3
4
|
import type { AstroSettings } from '../types/astro.js';
|
|
4
|
-
|
|
5
|
-
fs: typeof fsMod;
|
|
5
|
+
interface Options {
|
|
6
6
|
settings: AstroSettings;
|
|
7
|
-
|
|
7
|
+
sync: boolean;
|
|
8
|
+
logger: Logger;
|
|
9
|
+
fs: typeof fsMod;
|
|
10
|
+
}
|
|
11
|
+
export default function assets({ fs, settings, sync, logger }: Options): vite.Plugin[];
|
|
12
|
+
export {};
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from "../core/path.js";
|
|
11
11
|
import { normalizePath } from "../core/viteUtils.js";
|
|
12
12
|
import { VALID_INPUT_FORMATS, VIRTUAL_MODULE_ID, VIRTUAL_SERVICE_ID } from "./consts.js";
|
|
13
|
+
import { fontsPlugin } from "./fonts/vite-plugin-fonts.js";
|
|
13
14
|
import { getAssetsPrefix } from "./utils/getAssetsPrefix.js";
|
|
14
15
|
import { isESMImportedImage } from "./utils/imageKind.js";
|
|
15
16
|
import { emitESMImage } from "./utils/node/emitAsset.js";
|
|
@@ -63,10 +64,7 @@ const addStaticImageFactory = (settings) => {
|
|
|
63
64
|
}
|
|
64
65
|
};
|
|
65
66
|
};
|
|
66
|
-
function assets({
|
|
67
|
-
fs,
|
|
68
|
-
settings
|
|
69
|
-
}) {
|
|
67
|
+
function assets({ fs, settings, sync, logger }) {
|
|
70
68
|
let resolvedConfig;
|
|
71
69
|
let shouldEmitFile = false;
|
|
72
70
|
let isBuild = false;
|
|
@@ -97,6 +95,7 @@ function assets({
|
|
|
97
95
|
import { getImage as getImageInternal } from "astro/assets";
|
|
98
96
|
export { default as Image } from "astro/components/${imageComponentPrefix}Image.astro";
|
|
99
97
|
export { default as Picture } from "astro/components/${imageComponentPrefix}Picture.astro";
|
|
98
|
+
export { default as Font } from "astro/components/Font.astro";
|
|
100
99
|
export { inferRemoteSize } from "astro/assets/utils/inferRemoteSize.js";
|
|
101
100
|
|
|
102
101
|
export const imageConfig = ${JSON.stringify({ ...settings.config.image, experimentalResponsiveImages: settings.config.experimental.responsiveImages })};
|
|
@@ -173,7 +172,7 @@ function assets({
|
|
|
173
172
|
const imageMetadata = await emitESMImage(
|
|
174
173
|
id,
|
|
175
174
|
this.meta.watchMode,
|
|
176
|
-
|
|
175
|
+
id.endsWith(".svg"),
|
|
177
176
|
emitFile
|
|
178
177
|
);
|
|
179
178
|
if (!imageMetadata) {
|
|
@@ -182,7 +181,7 @@ function assets({
|
|
|
182
181
|
message: AstroErrorData.ImageNotFound.message(id)
|
|
183
182
|
});
|
|
184
183
|
}
|
|
185
|
-
if (
|
|
184
|
+
if (id.endsWith(".svg")) {
|
|
186
185
|
const contents = await fs.promises.readFile(imageMetadata.fsPath, { encoding: "utf8" });
|
|
187
186
|
return { code: makeSvgComponent(imageMetadata, contents) };
|
|
188
187
|
}
|
|
@@ -201,7 +200,8 @@ function assets({
|
|
|
201
200
|
}
|
|
202
201
|
}
|
|
203
202
|
}
|
|
204
|
-
}
|
|
203
|
+
},
|
|
204
|
+
fontsPlugin({ settings, sync, logger })
|
|
205
205
|
];
|
|
206
206
|
}
|
|
207
207
|
export {
|
|
@@ -4,6 +4,8 @@ export { defineConfig, getViteConfig } from './index.js';
|
|
|
4
4
|
export { envField } from '../env/config.js';
|
|
5
5
|
export { mergeConfig } from '../core/config/merge.js';
|
|
6
6
|
export { validateConfig } from '../core/config/validate.js';
|
|
7
|
+
export { fontProviders, defineAstroFontProvider } from '../assets/fonts/providers/index.js';
|
|
8
|
+
export type { AstroFontProvider } from '../assets/fonts/types.js';
|
|
7
9
|
/**
|
|
8
10
|
* Return the configuration needed to use the Sharp-based image service
|
|
9
11
|
*/
|
|
@@ -2,6 +2,7 @@ import { defineConfig, getViteConfig } from "./index.js";
|
|
|
2
2
|
import { envField } from "../env/config.js";
|
|
3
3
|
import { mergeConfig } from "../core/config/merge.js";
|
|
4
4
|
import { validateConfig } from "../core/config/validate.js";
|
|
5
|
+
import { fontProviders, defineAstroFontProvider } from "../assets/fonts/providers/index.js";
|
|
5
6
|
function sharpImageService(config = {}) {
|
|
6
7
|
return {
|
|
7
8
|
entrypoint: "astro/assets/services/sharp",
|
|
@@ -15,8 +16,10 @@ function passthroughImageService() {
|
|
|
15
16
|
};
|
|
16
17
|
}
|
|
17
18
|
export {
|
|
19
|
+
defineAstroFontProvider,
|
|
18
20
|
defineConfig,
|
|
19
21
|
envField,
|
|
22
|
+
fontProviders,
|
|
20
23
|
getViteConfig,
|
|
21
24
|
mergeConfig,
|
|
22
25
|
passthroughImageService,
|
package/dist/config/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { UserConfig as ViteUserConfig, UserConfigFn as ViteUserConfigFn } from 'vite';
|
|
2
|
+
import type { FontFamily } from '../assets/fonts/types.js';
|
|
2
3
|
import type { AstroInlineConfig, AstroUserConfig, Locales, SessionDriverName } from '../types/public/config.js';
|
|
3
4
|
/**
|
|
4
5
|
* See the full Astro Configuration API Documentation
|
|
5
6
|
* https://astro.build/config
|
|
6
7
|
*/
|
|
7
|
-
export declare function defineConfig<const TLocales extends Locales = never, const TDriver extends SessionDriverName = never>(config: AstroUserConfig<TLocales, TDriver>): AstroUserConfig<TLocales, TDriver>;
|
|
8
|
+
export declare function defineConfig<const TLocales extends Locales = never, const TDriver extends SessionDriverName = never, const TFontFamilies extends FontFamily[] = never>(config: AstroUserConfig<TLocales, TDriver, TFontFamilies>): AstroUserConfig<TLocales, TDriver, TFontFamilies>;
|
|
8
9
|
/**
|
|
9
10
|
* Use Astro to generate a fully resolved Vite config
|
|
10
11
|
*/
|
|
@@ -153,7 +153,7 @@ ${contentConfig.error.message}`);
|
|
|
153
153
|
logger.info("Content config changed");
|
|
154
154
|
shouldClear = true;
|
|
155
155
|
}
|
|
156
|
-
if (previousAstroVersion && previousAstroVersion !== "5.
|
|
156
|
+
if (previousAstroVersion && previousAstroVersion !== "5.7.1") {
|
|
157
157
|
logger.info("Astro version changed");
|
|
158
158
|
shouldClear = true;
|
|
159
159
|
}
|
|
@@ -161,8 +161,8 @@ ${contentConfig.error.message}`);
|
|
|
161
161
|
logger.info("Clearing content store");
|
|
162
162
|
this.#store.clearAll();
|
|
163
163
|
}
|
|
164
|
-
if ("5.
|
|
165
|
-
await this.#store.metaStore().set("astro-version", "5.
|
|
164
|
+
if ("5.7.1") {
|
|
165
|
+
await this.#store.metaStore().set("astro-version", "5.7.1");
|
|
166
166
|
}
|
|
167
167
|
if (currentConfigDigest) {
|
|
168
168
|
await this.#store.metaStore().set("content-config-digest", currentConfigDigest);
|
|
@@ -202,7 +202,8 @@ ${contentConfig.error.message}`);
|
|
|
202
202
|
},
|
|
203
203
|
collectionWithResolvedSchema,
|
|
204
204
|
false,
|
|
205
|
-
|
|
205
|
+
// FUTURE: Remove in this in v6
|
|
206
|
+
id.endsWith(".svg")
|
|
206
207
|
);
|
|
207
208
|
return parsedData;
|
|
208
209
|
};
|
|
@@ -7,6 +7,7 @@ function createImage(pluginContext, shouldEmitFile, entryFilePath, experimentalS
|
|
|
7
7
|
const metadata = await emitESMImage(
|
|
8
8
|
resolvedFilePath,
|
|
9
9
|
pluginContext.meta.watchMode,
|
|
10
|
+
// FUTURE: Remove in this in v6
|
|
10
11
|
experimentalSvgEnabled,
|
|
11
12
|
shouldEmitFile ? pluginContext.emitFile : void 0
|
|
12
13
|
);
|
|
@@ -171,7 +171,8 @@ async function getContentEntryModule(params) {
|
|
|
171
171
|
{ id, collection, _internal, unvalidatedData },
|
|
172
172
|
collectionConfig,
|
|
173
173
|
params.shouldEmitFile,
|
|
174
|
-
|
|
174
|
+
// FUTURE: Remove in this in v6
|
|
175
|
+
id.endsWith(".svg"),
|
|
175
176
|
pluginContext
|
|
176
177
|
) : unvalidatedData;
|
|
177
178
|
const contentEntryModule = {
|
|
@@ -197,7 +198,8 @@ async function getDataEntryModule(params) {
|
|
|
197
198
|
{ id, collection, _internal, unvalidatedData },
|
|
198
199
|
collectionConfig,
|
|
199
200
|
params.shouldEmitFile,
|
|
200
|
-
|
|
201
|
+
// FUTURE: Remove in this in v6
|
|
202
|
+
id.endsWith(".svg"),
|
|
201
203
|
pluginContext
|
|
202
204
|
) : unvalidatedData;
|
|
203
205
|
const dataEntryModule = {
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
} from "../../core/path.js";
|
|
19
19
|
import { toFallbackType, toRoutingStrategy } from "../../i18n/utils.js";
|
|
20
20
|
import { runHookBuildGenerated } from "../../integrations/hooks.js";
|
|
21
|
-
import {
|
|
21
|
+
import { getServerOutputDirectory } from "../../prerender/utils.js";
|
|
22
22
|
import { NoPrerenderedRoutesWithDomains } from "../errors/errors-data.js";
|
|
23
23
|
import { AstroError, AstroErrorData } from "../errors/index.js";
|
|
24
24
|
import { NOOP_MIDDLEWARE_FN } from "../middleware/noop-middleware.js";
|
|
@@ -41,7 +41,7 @@ async function generatePages(options, internals) {
|
|
|
41
41
|
if (ssr) {
|
|
42
42
|
manifest = await BuildPipeline.retrieveManifest(options.settings, internals);
|
|
43
43
|
} else {
|
|
44
|
-
const baseDirectory =
|
|
44
|
+
const baseDirectory = getServerOutputDirectory(options.settings);
|
|
45
45
|
const renderersEntryUrl = new URL("renderers.mjs", baseDirectory);
|
|
46
46
|
const renderers = await import(renderersEntryUrl.toString());
|
|
47
47
|
const middleware = internals.middlewareEntryPoint ? await import(internals.middlewareEntryPoint.toString()).then((mod) => mod.onRequest) : NOOP_MIDDLEWARE_FN;
|