diff options
author | 2025-04-28 15:33:52 +0200 | |
---|---|---|
committer | 2025-04-28 15:33:52 +0200 | |
commit | 28f8716ceef8b30ebb4da8c6ef32acc72405c1e6 (patch) | |
tree | 029ea0ca7e1fd3b70addb2438d4aca8f5313a9ec | |
parent | 7d8c1dc99d742f9c2992a89b04bf19f43cdf3a43 (diff) | |
download | astro-28f8716ceef8b30ebb4da8c6ef32acc72405c1e6.tar.gz astro-28f8716ceef8b30ebb4da8c6ef32acc72405c1e6.tar.zst astro-28f8716ceef8b30ebb4da8c6ef32acc72405c1e6.zip |
feat(fonts): update unifont (#13705)
18 files changed, 186 insertions, 110 deletions
diff --git a/.changeset/cyan-games-jog.md b/.changeset/cyan-games-jog.md new file mode 100644 index 000000000..cd4d8c0a8 --- /dev/null +++ b/.changeset/cyan-games-jog.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Updates unifont to latest and adds support for `fetch` options from remote providers when using the experimental fonts API diff --git a/packages/astro/package.json b/packages/astro/package.json index 0d99e4f8a..934197a83 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -160,7 +160,7 @@ "tinyglobby": "^0.2.12", "tsconfck": "^3.1.5", "ultrahtml": "^1.6.0", - "unifont": "~0.2.0", + "unifont": "~0.4.0", "unist-util-visit": "^5.0.0", "unstorage": "^1.15.0", "vfile": "^6.0.3", diff --git a/packages/astro/src/assets/fonts/definitions.ts b/packages/astro/src/assets/fonts/definitions.ts index 2c25f2968..caae27f95 100644 --- a/packages/astro/src/assets/fonts/definitions.ts +++ b/packages/astro/src/assets/fonts/definitions.ts @@ -1,7 +1,13 @@ import type * as unifont from 'unifont'; import type { CollectedFontForMetrics } from './logic/optimize-fallbacks.js'; /* eslint-disable @typescript-eslint/no-empty-object-type */ -import type { AstroFontProvider, FontType, PreloadData, ResolvedFontProvider } from './types.js'; +import type { + AstroFontProvider, + FontFileData, + FontType, + PreloadData, + ResolvedFontProvider, +} from './types.js'; import type { FontFaceMetrics, GenericFallbackName } from './types.js'; export interface Hasher { @@ -43,11 +49,12 @@ export interface ErrorHandler { } export interface UrlProxy { - proxy: (input: { - url: string; - collectPreload: boolean; - data: Partial<unifont.FontFaceData>; - }) => string; + proxy: ( + input: Pick<FontFileData, 'url' | 'init'> & { + collectPreload: boolean; + data: Partial<unifont.FontFaceData>; + }, + ) => string; } export interface UrlProxyContentResolver { @@ -55,12 +62,12 @@ export interface UrlProxyContentResolver { } export interface DataCollector { - collect: (input: { - originalUrl: string; - hash: string; - data: Partial<unifont.FontFaceData>; - preload: PreloadData | null; - }) => void; + collect: ( + input: FontFileData & { + data: Partial<unifont.FontFaceData>; + preload: PreloadData | null; + }, + ) => void; } export type CssProperties = Record<string, string | undefined>; @@ -87,7 +94,7 @@ export interface SystemFallbacksProvider { } export interface FontFetcher { - fetch: (hash: string, url: string) => Promise<Buffer>; + fetch: (input: FontFileData) => Promise<Buffer>; } export interface FontTypeExtractor { diff --git a/packages/astro/src/assets/fonts/implementations/data-collector.ts b/packages/astro/src/assets/fonts/implementations/data-collector.ts index 6c0f3ad04..43f29b14f 100644 --- a/packages/astro/src/assets/fonts/implementations/data-collector.ts +++ b/packages/astro/src/assets/fonts/implementations/data-collector.ts @@ -8,18 +8,14 @@ export function createDataCollector({ saveFontData, }: Omit<CreateUrlProxyParams, 'local'>): DataCollector { return { - collect({ originalUrl, hash, preload, data }) { + collect({ hash, url, init, preload, data }) { if (!hasUrl(hash)) { - saveUrl(hash, originalUrl); + saveUrl({ hash, url, init }); if (preload) { savePreload(preload); } } - saveFontData({ - hash, - url: originalUrl, - data, - }); + saveFontData({ hash, url, data, init }); }, }; } diff --git a/packages/astro/src/assets/fonts/implementations/font-fetcher.ts b/packages/astro/src/assets/fonts/implementations/font-fetcher.ts index af70bd130..9bc2ae8ff 100644 --- a/packages/astro/src/assets/fonts/implementations/font-fetcher.ts +++ b/packages/astro/src/assets/fonts/implementations/font-fetcher.ts @@ -11,19 +11,17 @@ export function createCachedFontFetcher({ }: { storage: Storage; errorHandler: ErrorHandler; - fetch: (url: string) => Promise<Response>; + fetch: (url: string, init?: RequestInit) => Promise<Response>; readFile: (url: string) => Promise<Buffer>; }): FontFetcher { return { - async fetch(hash, url) { + async fetch({ hash, url, init }) { return await cache(storage, hash, async () => { try { if (isAbsolute(url)) { return await readFile(url); } - // TODO: find a way to pass headers - // https://github.com/unjs/unifont/issues/143 - const response = await fetch(url); + const response = await fetch(url, init ?? undefined); if (!response.ok) { throw new Error(`Response was not successful, received status code ${response.status}`); } diff --git a/packages/astro/src/assets/fonts/implementations/font-metrics-resolver.ts b/packages/astro/src/assets/fonts/implementations/font-metrics-resolver.ts index 093a9d2fc..5dff86d09 100644 --- a/packages/astro/src/assets/fonts/implementations/font-metrics-resolver.ts +++ b/packages/astro/src/assets/fonts/implementations/font-metrics-resolver.ts @@ -36,8 +36,8 @@ export function createCapsizeFontMetricsResolver({ const cache: Record<string, FontFaceMetrics | null> = {}; return { - async getMetrics(name, { hash, url }) { - cache[name] ??= filterRequiredMetrics(await fromBuffer(await fontFetcher.fetch(hash, url))); + async getMetrics(name, input) { + cache[name] ??= filterRequiredMetrics(await fromBuffer(await fontFetcher.fetch(input))); return cache[name]; }, // Source: https://github.com/unjs/fontaine/blob/f00f84032c5d5da72c8798eae4cd68d3ddfbf340/src/css.ts#L170 diff --git a/packages/astro/src/assets/fonts/implementations/url-proxy.ts b/packages/astro/src/assets/fonts/implementations/url-proxy.ts index 01cfdc40b..424375949 100644 --- a/packages/astro/src/assets/fonts/implementations/url-proxy.ts +++ b/packages/astro/src/assets/fonts/implementations/url-proxy.ts @@ -20,16 +20,17 @@ export function createUrlProxy({ fontTypeExtractor: FontTypeExtractor; }): UrlProxy { return { - proxy({ url: originalUrl, data, collectPreload }) { + proxy({ url: originalUrl, data, collectPreload, init }) { const type = fontTypeExtractor.extract(originalUrl); const hash = `${hasher.hashString(contentResolver.resolve(originalUrl))}.${type}`; const url = base + hash; dataCollector.collect({ - originalUrl, + url: originalUrl, hash, preload: collectPreload ? { url, type } : null, data, + init, }); return url; diff --git a/packages/astro/src/assets/fonts/logic/normalize-remote-font-faces.ts b/packages/astro/src/assets/fonts/logic/normalize-remote-font-faces.ts index 4c4c6513d..c4689f0f7 100644 --- a/packages/astro/src/assets/fonts/logic/normalize-remote-font-faces.ts +++ b/packages/astro/src/assets/fonts/logic/normalize-remote-font-faces.ts @@ -35,6 +35,7 @@ export function normalizeRemoteFontFaces({ weight: font.weight, style: font.style, }, + init: font.meta?.init ?? null, }), }; index++; diff --git a/packages/astro/src/assets/fonts/logic/optimize-fallbacks.ts b/packages/astro/src/assets/fonts/logic/optimize-fallbacks.ts index ed49e4e68..ef988f9fa 100644 --- a/packages/astro/src/assets/fonts/logic/optimize-fallbacks.ts +++ b/packages/astro/src/assets/fonts/logic/optimize-fallbacks.ts @@ -1,11 +1,9 @@ -import type * as unifont from 'unifont'; import type { FontMetricsResolver, SystemFallbacksProvider } from '../definitions.js'; -import type { ResolvedFontFamily } from '../types.js'; +import type * as unifont from 'unifont'; +import type { FontFileData, ResolvedFontFamily } from '../types.js'; import { isGenericFontFamily, unifontFontFaceDataToProperties } from '../utils.js'; -export interface CollectedFontForMetrics { - hash: string; - url: string; +export interface CollectedFontForMetrics extends FontFileData { data: Partial<unifont.FontFaceData>; } @@ -64,14 +62,14 @@ export async function optimizeFallbacks({ let css = ''; for (const { font, name } of localFontsMappings) { - for (const { hash, url, data } of collectedFonts) { + for (const collected of collectedFonts) { // We generate a fallback for each font collected, which is per weight and style css += fontMetricsResolver.generateFontFace({ - metrics: await fontMetricsResolver.getMetrics(family.name, { hash, url, data }), + metrics: await fontMetricsResolver.getMetrics(family.name, collected), fallbackMetrics: systemFallbacksProvider.getMetricsForLocalFont(font), font, name, - properties: unifontFontFaceDataToProperties(data), + properties: unifontFontFaceDataToProperties(collected.data), }); } } diff --git a/packages/astro/src/assets/fonts/orchestrate.ts b/packages/astro/src/assets/fonts/orchestrate.ts index 1876cbc5d..5e476712b 100644 --- a/packages/astro/src/assets/fonts/orchestrate.ts +++ b/packages/astro/src/assets/fonts/orchestrate.ts @@ -16,7 +16,14 @@ import { normalizeRemoteFontFaces } from './logic/normalize-remote-font-faces.js import { type CollectedFontForMetrics, optimizeFallbacks } from './logic/optimize-fallbacks.js'; import { resolveFamilies } from './logic/resolve-families.js'; import { resolveLocalFont } from './providers/local.js'; -import type { CreateUrlProxyParams, Defaults, FontFamily, PreloadData } from './types.js'; +import type { + ConsumableMap, + CreateUrlProxyParams, + Defaults, + FontFamily, + FontFileDataMap, + PreloadData, +} from './types.js'; import { pickFontFaceProperty, unifontFontFaceDataToProperties } from './utils.js'; /** @@ -61,7 +68,10 @@ export async function orchestrate({ fontTypeExtractor: FontTypeExtractor; createUrlProxy: (params: CreateUrlProxyParams) => UrlProxy; defaults: Defaults; -}) { +}): Promise<{ + fontFileDataMap: FontFileDataMap; + consumableMap: ConsumableMap; +}> { let resolvedFamilies = await resolveFamilies({ families, hasher, @@ -84,11 +94,11 @@ export async function orchestrate({ * Holds associations of hash and original font file URLs, so they can be * downloaded whenever the hash is requested. */ - const hashToUrlMap = new Map<string, string>(); + const fontFileDataMap: FontFileDataMap = new Map(); /** * Holds associations of CSS variables and preloadData/css to be passed to the virtual module. */ - const resolvedMap = new Map<string, { preloadData: Array<PreloadData>; css: string }>(); + const consumableMap: ConsumableMap = new Map(); for (const family of resolvedFamilies) { const preloadData: Array<PreloadData> = []; @@ -106,9 +116,9 @@ export async function orchestrate({ */ const urlProxy = createUrlProxy({ local: family.provider === LOCAL_PROVIDER_NAME, - hasUrl: (hash) => hashToUrlMap.has(hash), - saveUrl: (hash, url) => { - hashToUrlMap.set(hash, url); + hasUrl: (hash) => fontFileDataMap.has(hash), + saveUrl: ({ hash, url, init }) => { + fontFileDataMap.set(hash, { url, init }); }, savePreload: (preload) => { preloadData.push(preload); @@ -195,8 +205,8 @@ export async function orchestrate({ css += cssRenderer.generateCssVariable(family.cssVariable, cssVarValues); - resolvedMap.set(family.cssVariable, { preloadData, css }); + consumableMap.set(family.cssVariable, { preloadData, css }); } - return { hashToUrlMap, resolvedMap }; + return { fontFileDataMap, consumableMap }; } diff --git a/packages/astro/src/assets/fonts/providers/local.ts b/packages/astro/src/assets/fonts/providers/local.ts index d4b95d500..1764b277c 100644 --- a/packages/astro/src/assets/fonts/providers/local.ts +++ b/packages/astro/src/assets/fonts/providers/local.ts @@ -28,6 +28,7 @@ export function resolveLocalFont({ family, urlProxy, fontTypeExtractor }: Option weight: variant.weight, style: variant.style, }, + init: null }), format: FONT_FORMAT_MAP[fontTypeExtractor.extract(source.url)], tech: source.tech, diff --git a/packages/astro/src/assets/fonts/types.ts b/packages/astro/src/assets/fonts/types.ts index 04678ad83..e55a9d663 100644 --- a/packages/astro/src/assets/fonts/types.ts +++ b/packages/astro/src/assets/fonts/types.ts @@ -77,10 +77,27 @@ export type Defaults = Partial< > >; +export interface FontFileData { + hash: string; + url: string; + init: RequestInit | null; +} + export interface CreateUrlProxyParams { local: boolean; hasUrl: (hash: string) => boolean; - saveUrl: (hash: string, url: string) => void; + saveUrl: (input: FontFileData) => void; savePreload: (preload: PreloadData) => void; saveFontData: (collected: CollectedFontForMetrics) => void; } + +/** + * Holds associations of hash and original font file URLs, so they can be + * downloaded whenever the hash is requested. + */ +export type FontFileDataMap = Map<FontFileData['hash'], Pick<FontFileData, 'url' | 'init'>>; + +/** + * Holds associations of CSS variables and preloadData/css to be passed to the virtual module. + */ +export type ConsumableMap = Map<string, { preloadData: Array<PreloadData>; css: string }>; diff --git a/packages/astro/src/assets/fonts/vite-plugin-fonts.ts b/packages/astro/src/assets/fonts/vite-plugin-fonts.ts index d0a4c3496..a7a404815 100644 --- a/packages/astro/src/assets/fonts/vite-plugin-fonts.ts +++ b/packages/astro/src/assets/fonts/vite-plugin-fonts.ts @@ -44,7 +44,7 @@ import { } from './implementations/url-proxy-content-resolver.js'; import { createUrlProxy } from './implementations/url-proxy.js'; import { orchestrate } from './orchestrate.js'; -import type { PreloadData } from './types.js'; +import type { ConsumableMap, FontFileDataMap } from './types.js'; interface Options { settings: AstroSettings; @@ -79,18 +79,15 @@ export function fontsPlugin({ settings, sync, logger }: Options): Plugin { // to trailingSlash: never) const baseUrl = removeTrailingForwardSlash(settings.config.base) + URL_PREFIX; - let resolvedMap: Map<string, { preloadData: Array<PreloadData>; css: string }> | null = null; - // Key is `${hash}.${ext}`, value is a URL. - // When a font file is requested (eg. /_astro/fonts/abc.woff), we use the hash - // to download the original file, or retrieve it from cache - let hashToUrlMap: Map<string, string> | null = null; + let fontFileDataMap: FontFileDataMap | null = null; + let consumableMap: ConsumableMap | null = null; let isBuild: boolean; let fontFetcher: FontFetcher | null = null; let fontTypeExtractor: FontTypeExtractor | null = null; const cleanup = () => { - resolvedMap = null; - hashToUrlMap = null; + consumableMap = null; + fontFileDataMap = null; fontFetcher = null; }; @@ -163,8 +160,8 @@ export function fontsPlugin({ settings, sync, logger }: Options): Plugin { }); // We initialize shared variables here and reset them in buildEnd // to avoid locking memory - hashToUrlMap = res.hashToUrlMap; - resolvedMap = res.resolvedMap; + fontFileDataMap = res.fontFileDataMap; + consumableMap = res.consumableMap; } return { @@ -190,7 +187,9 @@ export function fontsPlugin({ settings, sync, logger }: Options): Plugin { }); // The map is always defined at this point. Its values contains urls from remote providers // as well as local paths for the local provider. We filter them to only keep the filepaths - const localPaths = [...hashToUrlMap!.values()].filter((url) => isAbsolute(url)); + const localPaths = [...fontFileDataMap!.values()] + .filter(({ url }) => isAbsolute(url)) + .map((v) => v.url); server.watcher.on('change', (path) => { if (localPaths.includes(path)) { logger.info('assets', 'Font file updated'); @@ -214,8 +213,8 @@ export function fontsPlugin({ settings, sync, logger }: Options): Plugin { return next(); } const hash = req.url.slice(1); - const url = hashToUrlMap?.get(hash); - if (!url) { + const associatedData = fontFileDataMap?.get(hash); + if (!associatedData) { return next(); } // We don't want the request to be cached in dev because we cache it already internally, @@ -228,7 +227,7 @@ export function fontsPlugin({ settings, sync, logger }: Options): Plugin { // Storage should be defined at this point since initialize it called before registering // the middleware. hashToUrlMap is defined at the same time so if it's not set by now, // no url will be matched and this line will not be reached. - const data = await fontFetcher!.fetch(hash, url); + const data = await fontFetcher!.fetch({ hash, ...associatedData }); res.setHeader('Content-Length', data.length); res.setHeader('Content-Type', `font/${fontTypeExtractor!.extract(hash)}`); @@ -255,7 +254,7 @@ export function fontsPlugin({ settings, sync, logger }: Options): Plugin { load(id) { if (id === RESOLVED_VIRTUAL_MODULE_ID) { return { - code: `export const fontsData = new Map(${JSON.stringify(Array.from(resolvedMap?.entries() ?? []))})`, + code: `export const fontsData = new Map(${JSON.stringify(Array.from(consumableMap?.entries() ?? []))})`, }; } }, @@ -273,11 +272,11 @@ export function fontsPlugin({ settings, sync, logger }: Options): Plugin { } catch (cause) { throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause }); } - if (hashToUrlMap) { + if (fontFileDataMap) { logger.info('assets', 'Copying fonts...'); await Promise.all( - Array.from(hashToUrlMap.entries()).map(async ([hash, url]) => { - const data = await fontFetcher!.fetch(hash, url); + Array.from(fontFileDataMap.entries()).map(async ([hash, associatedData]) => { + const data = await fontFetcher!.fetch({ hash, ...associatedData }); try { writeFileSync(new URL(hash, fontsDir), data); } catch (cause) { diff --git a/packages/astro/test/units/assets/fonts/implementations.test.js b/packages/astro/test/units/assets/fonts/implementations.test.js index b5f2d5a7c..1370f730e 100644 --- a/packages/astro/test/units/assets/fonts/implementations.test.js +++ b/packages/astro/test/units/assets/fonts/implementations.test.js @@ -53,7 +53,7 @@ describe('fonts implementations', () => { }); it('createDataCollector()', () => { - /** @type {Map<string, string>} */ + /** @type {import('../../../../dist/assets/fonts/types.js').FontFileDataMap} */ const map = new Map(); /** @type {Array<import('../../../../dist/assets/fonts/types.js').PreloadData>} */ const preloadData = []; @@ -62,8 +62,8 @@ describe('fonts implementations', () => { const dataCollector = createDataCollector({ hasUrl: (hash) => map.has(hash), - saveUrl: (hash, url) => { - map.set(hash, url); + saveUrl: ({ hash, url, init }) => { + map.set(hash, { url, init }); }, savePreload: (preload) => { preloadData.push(preload); @@ -73,27 +73,40 @@ describe('fonts implementations', () => { }, }); - dataCollector.collect({ hash: 'xxx', originalUrl: 'abc', preload: null, data: {} }); + dataCollector.collect({ + hash: 'xxx', + url: 'abc', + preload: null, + data: {}, + init: null, + }); dataCollector.collect({ hash: 'yyy', - originalUrl: 'def', + url: 'def', preload: { type: 'woff2', url: 'def' }, data: {}, + init: null, + }); + dataCollector.collect({ + hash: 'xxx', + url: 'abc', + preload: null, + data: {}, + init: null, }); - dataCollector.collect({ hash: 'xxx', originalUrl: 'abc', preload: null, data: {} }); assert.deepStrictEqual( [...map.entries()], [ - ['xxx', 'abc'], - ['yyy', 'def'], + ['xxx', { url: 'abc', init: null }], + ['yyy', { url: 'def', init: null }], ], ); assert.deepStrictEqual(preloadData, [{ type: 'woff2', url: 'def' }]); assert.deepStrictEqual(collectedFonts, [ - { hash: 'xxx', url: 'abc', data: {} }, - { hash: 'yyy', url: 'def', data: {} }, - { hash: 'xxx', url: 'abc', data: {} }, + { hash: 'xxx', url: 'abc', data: {}, init: null }, + { hash: 'yyy', url: 'def', data: {}, init: null }, + { hash: 'xxx', url: 'abc', data: {}, init: null }, ]); }); @@ -185,9 +198,9 @@ describe('fonts implementations', () => { fetch, }); - await fontFetcher.fetch('abc', 'def'); - await fontFetcher.fetch('foo', 'bar'); - await fontFetcher.fetch('abc', 'def'); + await fontFetcher.fetch({ hash: 'abc', url: 'def', init: null }); + await fontFetcher.fetch({ hash: 'foo', url: 'bar', init: null }); + await fontFetcher.fetch({ hash: 'abc', url: 'def', init: null }); assert.deepStrictEqual([...store.keys()], ['abc', 'foo']); assert.deepStrictEqual(filesUrls, []); @@ -205,7 +218,7 @@ describe('fonts implementations', () => { fetch, }); - await fontFetcher.fetch('abc', '/foo/bar'); + await fontFetcher.fetch({ hash: 'abc', url: '/foo/bar', init: null }); assert.deepStrictEqual(filesUrls, ['/foo/bar']); assert.deepStrictEqual(fetchUrls, []); @@ -222,7 +235,7 @@ describe('fonts implementations', () => { fetch, }); - await fontFetcher.fetch('abc', 'https://example.com'); + await fontFetcher.fetch({ hash: 'abc', url: 'https://example.com', init: null }); assert.deepStrictEqual(filesUrls, []); assert.deepStrictEqual(fetchUrls, ['https://example.com']); @@ -239,12 +252,16 @@ describe('fonts implementations', () => { fetch, }); - let error = await fontFetcher.fetch('abc', '/foo/bar').catch((err) => err); + let error = await fontFetcher + .fetch({ hash: 'abc', url: '/foo/bar', init: null }) + .catch((err) => err); assert.equal(error instanceof Error, true); assert.equal(error.message, 'cannot-fetch-font-file'); assert.equal(error.cause, 'fs error'); - error = await fontFetcher.fetch('abc', 'https://example.com').catch((err) => err); + error = await fontFetcher + .fetch({ hash: 'abc', url: 'https://example.com', init: null }) + .catch((err) => err); assert.equal(error instanceof Error, true); assert.equal(error.message, 'cannot-fetch-font-file'); assert.equal(error.cause instanceof Error, true); diff --git a/packages/astro/test/units/assets/fonts/logic.test.js b/packages/astro/test/units/assets/fonts/logic.test.js index 00d43df98..0fe637868 100644 --- a/packages/astro/test/units/assets/fonts/logic.test.js +++ b/packages/astro/test/units/assets/fonts/logic.test.js @@ -389,21 +389,24 @@ describe('fonts logic', () => { url: '/', collectPreload: true, data: { weight: '400', style: 'normal' }, + init: null, }, { url: '/ignored', collectPreload: false, data: { weight: '400', style: 'normal' }, + init: null, }, { url: '/2', collectPreload: true, data: { weight: '500', style: 'normal' }, + init: null, }, ]); }); - it('collect preloads correctly', () => { + it('collects preloads correctly', () => { const { collected, urlProxy } = createSpyUrlProxy(); normalizeRemoteFontFaces({ urlProxy, @@ -425,21 +428,25 @@ describe('fonts logic', () => { url: '/', collectPreload: true, data: { weight: '400', style: 'normal' }, + init: null, }, { url: '/ignored', collectPreload: false, data: { weight: '400', style: 'normal' }, + init: null, }, { url: '/2', collectPreload: true, data: { weight: '500', style: 'normal' }, + init: null, }, { url: '/also-ignored', collectPreload: false, data: { weight: '500', style: 'normal' }, + init: null, }, ]); }); @@ -458,7 +465,7 @@ describe('fonts logic', () => { await optimizeFallbacks({ family, fallbacks: [], - collectedFonts: [{ url: '', hash: '', data: {} }], + collectedFonts: [{ url: '', hash: '', data: {}, init: null }], enabled: true, systemFallbacksProvider, fontMetricsResolver, @@ -472,7 +479,7 @@ describe('fonts logic', () => { await optimizeFallbacks({ family, fallbacks: ['foo'], - collectedFonts: [{ url: '', hash: '', data: {} }], + collectedFonts: [{ url: '', hash: '', data: {}, init: null }], enabled: false, systemFallbacksProvider, fontMetricsResolver, @@ -500,7 +507,7 @@ describe('fonts logic', () => { await optimizeFallbacks({ family, fallbacks: ['foo'], - collectedFonts: [{ url: '', hash: '', data: {} }], + collectedFonts: [{ url: '', hash: '', data: {}, init: null }], enabled: true, systemFallbacksProvider, fontMetricsResolver, @@ -514,7 +521,7 @@ describe('fonts logic', () => { await optimizeFallbacks({ family, fallbacks: ['cursive'], - collectedFonts: [{ url: '', hash: '', data: {} }], + collectedFonts: [{ url: '', hash: '', data: {}, init: null }], enabled: true, systemFallbacksProvider, fontMetricsResolver, @@ -531,7 +538,7 @@ describe('fonts logic', () => { nameWithHash: 'Arial-xxx', }, fallbacks: ['sans-serif'], - collectedFonts: [{ url: '', hash: '', data: {} }], + collectedFonts: [{ url: '', hash: '', data: {}, init: null }], enabled: true, systemFallbacksProvider, fontMetricsResolver, @@ -544,7 +551,7 @@ describe('fonts logic', () => { const result = await optimizeFallbacks({ family, fallbacks: ['foo', 'sans-serif'], - collectedFonts: [{ url: '', hash: '', data: {} }], + collectedFonts: [{ url: '', hash: '', data: {}, init: null }], enabled: true, systemFallbacksProvider, fontMetricsResolver, @@ -557,8 +564,8 @@ describe('fonts logic', () => { family, fallbacks: ['foo', 'sans-serif'], collectedFonts: [ - { url: '', hash: '', data: { weight: '400' } }, - { url: '', hash: '', data: { weight: '500' } }, + { url: '', hash: '', data: { weight: '400' }, init: null }, + { url: '', hash: '', data: { weight: '500' }, init: null }, ], enabled: true, systemFallbacksProvider, diff --git a/packages/astro/test/units/assets/fonts/orchestrate.test.js b/packages/astro/test/units/assets/fonts/orchestrate.test.js index d745f903c..022d89b87 100644 --- a/packages/astro/test/units/assets/fonts/orchestrate.test.js +++ b/packages/astro/test/units/assets/fonts/orchestrate.test.js @@ -29,7 +29,7 @@ describe('fonts orchestrate()', () => { const errorHandler = simpleErrorHandler; const fontTypeExtractor = createFontTypeExtractor({ errorHandler }); const hasher = fakeHasher; - const { hashToUrlMap, resolvedMap } = await orchestrate({ + const { fontFileDataMap, consumableMap } = await orchestrate({ families: [ { name: 'Test', @@ -70,20 +70,20 @@ describe('fonts orchestrate()', () => { defaults: DEFAULTS, }); assert.deepStrictEqual( - [...hashToUrlMap.entries()], + [...fontFileDataMap.entries()], [ [ fileURLToPath(new URL('my-font.woff2.woff2', root)), - fileURLToPath(new URL('my-font.woff2', root)), + { url: fileURLToPath(new URL('my-font.woff2', root)), init: null }, ], [ fileURLToPath(new URL('my-font.woff.woff', root)), - fileURLToPath(new URL('my-font.woff', root)), + { url: fileURLToPath(new URL('my-font.woff', root)), init: null }, ], ], ); - assert.deepStrictEqual([...resolvedMap.keys()], ['--test']); - const entry = resolvedMap.get('--test'); + assert.deepStrictEqual([...consumableMap.keys()], ['--test']); + const entry = consumableMap.get('--test'); assert.deepStrictEqual(entry?.preloadData, [ { url: '/test' + fileURLToPath(new URL('my-font.woff2.woff2', root)), @@ -111,6 +111,11 @@ describe('fonts orchestrate()', () => { ], weight: '400', style: 'normal', + meta: { + init: { + method: 'POST', + }, + }, }, ], }; @@ -126,7 +131,7 @@ describe('fonts orchestrate()', () => { const errorHandler = simpleErrorHandler; const fontTypeExtractor = createFontTypeExtractor({ errorHandler }); const hasher = fakeHasher; - const { hashToUrlMap, resolvedMap } = await orchestrate({ + const { fontFileDataMap, consumableMap } = await orchestrate({ families: [ { name: 'Test', @@ -166,14 +171,20 @@ describe('fonts orchestrate()', () => { }); assert.deepStrictEqual( - [...hashToUrlMap.entries()], + [...fontFileDataMap.entries()], [ - ['https://example.com/foo.woff2.woff2', 'https://example.com/foo.woff2'], - ['https://example.com/foo.woff.woff', 'https://example.com/foo.woff'], + [ + 'https://example.com/foo.woff2.woff2', + { url: 'https://example.com/foo.woff2', init: { method: 'POST' } }, + ], + [ + 'https://example.com/foo.woff.woff', + { url: 'https://example.com/foo.woff', init: { method: 'POST' } }, + ], ], ); - assert.deepStrictEqual([...resolvedMap.keys()], ['--test']); - const entry = resolvedMap.get('--test'); + assert.deepStrictEqual([...consumableMap.keys()], ['--test']); + const entry = consumableMap.get('--test'); assert.deepStrictEqual(entry?.preloadData, [ { url: 'https://example.com/foo.woff2.woff2', type: 'woff2' }, ]); diff --git a/packages/astro/test/units/assets/fonts/providers.test.js b/packages/astro/test/units/assets/fonts/providers.test.js index dec49fbb1..9d88a7b4a 100644 --- a/packages/astro/test/units/assets/fonts/providers.test.js +++ b/packages/astro/test/units/assets/fonts/providers.test.js @@ -89,16 +89,19 @@ describe('fonts providers', () => { url: '/test.woff2', collectPreload: true, data: { weight: '400', style: 'normal' }, + init: null, }, { url: '/ignored.woff', collectPreload: false, data: { weight: '400', style: 'normal' }, + init: null, }, { url: '/2.woff2', collectPreload: true, data: { weight: '500', style: 'normal' }, + init: null, }, ]); }); @@ -132,21 +135,25 @@ describe('fonts providers', () => { url: '/test.woff2', collectPreload: true, data: { weight: '400', style: 'normal' }, + init: null, }, { url: '/ignored.woff', collectPreload: false, data: { weight: '400', style: 'normal' }, + init: null, }, { url: '/2.woff2', collectPreload: true, data: { weight: '500', style: 'normal' }, + init: null, }, { url: '/also-ignored.woff', collectPreload: false, data: { weight: '500', style: 'normal' }, + init: null, }, ]); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2ae548a3c..c642cd5ce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -605,8 +605,8 @@ importers: specifier: ^1.6.0 version: 1.6.0 unifont: - specifier: ~0.2.0 - version: 0.2.0 + specifier: ~0.4.0 + version: 0.4.0 unist-util-visit: specifier: ^5.0.0 version: 5.0.0 @@ -9969,6 +9969,7 @@ packages: libsql@0.5.4: resolution: {integrity: sha512-GEFeWca4SDAQFxjHWJBE6GK52LEtSskiujbG3rqmmeTO9t4sfSBKIURNLLpKDDF7fb7jmTuuRkDAn9BZGITQNw==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] lightningcss-darwin-arm64@1.29.2: @@ -11806,8 +11807,8 @@ packages: unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} - unifont@0.2.0: - resolution: {integrity: sha512-RoF14/tOhLvDa7R5K6A3PjsfJVFKvadvRpWjfV1ttabUe9704P1ie9z1ABLWEts/8SxrBVePav/XhgeFNltpsw==} + unifont@0.4.0: + resolution: {integrity: sha512-wbc8b02b+K7WRHSxD+YQRYS31iVwOd0dRF7Nv73nolzyQ5n4qMtuJ4OdJSe1hEB7XT+lPb2Qk7FHxOrMReh9lw==} unist-util-find-after@5.0.0: resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} @@ -18607,7 +18608,7 @@ snapshots: trough: 2.2.0 vfile: 6.0.3 - unifont@0.2.0: + unifont@0.4.0: dependencies: css-tree: 3.1.0 ohash: 2.0.11 |