Skip to content

Commit c390fb7

Browse files
refactor(fonts): use runtime as entrypoint (#15181)
1 parent 1a3f302 commit c390fb7

7 files changed

Lines changed: 247 additions & 234 deletions

File tree

packages/astro/components/Font.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
import * as mod from 'virtual:astro:assets/fonts/internal';
3-
import { filterPreloads } from 'astro/assets/fonts/runtime';
3+
import { filterPreloads } from '../dist/assets/fonts/core/filter-preloads.js';
44
import { AstroError, AstroErrorData } from '../dist/core/errors/index.js';
55
66
// TODO: remove check when fonts are stabilized
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { AstroError, AstroErrorData } from '../../../core/errors/index.js';
2+
import type { ConsumableMap } from '../types.js';
3+
4+
export function createGetFontData({ consumableMap }: { consumableMap?: ConsumableMap }) {
5+
return function getFontData(cssVariable: string) {
6+
// TODO: remove once fonts are stabilized
7+
if (!consumableMap) {
8+
throw new AstroError(AstroErrorData.ExperimentalFontsNotEnabled);
9+
}
10+
const data = consumableMap.get(cssVariable);
11+
if (!data) {
12+
throw new AstroError({
13+
...AstroErrorData.FontFamilyNotFound,
14+
message: AstroErrorData.FontFamilyNotFound.message(cssVariable),
15+
});
16+
}
17+
return data;
18+
};
19+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import type { PreloadData, PreloadFilter } from '../types.js';
2+
3+
export function filterPreloads(
4+
data: Array<PreloadData>,
5+
preload: PreloadFilter,
6+
): Array<PreloadData> | null {
7+
if (!preload) {
8+
return null;
9+
}
10+
if (preload === true) {
11+
// Preload everything
12+
return data;
13+
}
14+
// Only preload urls based on weight, style and subset
15+
return data.filter(({ weight, style, subset }) =>
16+
preload.some((p) => {
17+
// Always check the weight
18+
if (
19+
p.weight !== undefined &&
20+
weight !== undefined &&
21+
!checkWeight(p.weight.toString(), weight)
22+
) {
23+
return false;
24+
}
25+
// Only check the style if specified
26+
if (p.style !== undefined && p.style !== style) {
27+
return false;
28+
}
29+
// Only check the subset if specified
30+
if (p.subset !== undefined && p.subset !== subset) {
31+
return false;
32+
}
33+
return true;
34+
}),
35+
);
36+
}
37+
38+
function checkWeight(input: string, target: string): boolean {
39+
// If the input looks like "100 900", we check it as is
40+
const trimmedInput = input.trim();
41+
if (trimmedInput.includes(' ')) {
42+
return trimmedInput === target;
43+
}
44+
// If the target looks like "100 900", we check if the input is between the values
45+
if (target.includes(' ')) {
46+
const [a, b] = target.split(' ');
47+
const parsedInput = Number.parseInt(input);
48+
return parsedInput >= Number.parseInt(a) && parsedInput <= Number.parseInt(b);
49+
}
50+
return input === target;
51+
}
Lines changed: 3 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,4 @@
1-
import { AstroError, AstroErrorData } from '../../core/errors/index.js';
2-
import type { ConsumableMap, PreloadData, PreloadFilter } from './types.js';
1+
import * as fontsMod from 'virtual:astro:assets/fonts/internal';
2+
import { createGetFontData } from './core/create-get-font-data.js';
33

4-
export function createGetFontData({ consumableMap }: { consumableMap?: ConsumableMap }) {
5-
return function getFontData(cssVariable: string) {
6-
// TODO: remove once fonts are stabilized
7-
if (!consumableMap) {
8-
throw new AstroError(AstroErrorData.ExperimentalFontsNotEnabled);
9-
}
10-
const data = consumableMap.get(cssVariable);
11-
if (!data) {
12-
throw new AstroError({
13-
...AstroErrorData.FontFamilyNotFound,
14-
message: AstroErrorData.FontFamilyNotFound.message(cssVariable),
15-
});
16-
}
17-
return data;
18-
};
19-
}
20-
21-
export function filterPreloads(
22-
data: Array<PreloadData>,
23-
preload: PreloadFilter,
24-
): Array<PreloadData> | null {
25-
if (!preload) {
26-
return null;
27-
}
28-
if (preload === true) {
29-
// Preload everything
30-
return data;
31-
}
32-
// Only preload urls based on weight, style and subset
33-
return data.filter(({ weight, style, subset }) =>
34-
preload.some((p) => {
35-
// Always check the weight
36-
if (
37-
p.weight !== undefined &&
38-
weight !== undefined &&
39-
!checkWeight(p.weight.toString(), weight)
40-
) {
41-
return false;
42-
}
43-
// Only check the style if specified
44-
if (p.style !== undefined && p.style !== style) {
45-
return false;
46-
}
47-
// Only check the subset if specified
48-
if (p.subset !== undefined && p.subset !== subset) {
49-
return false;
50-
}
51-
return true;
52-
}),
53-
);
54-
}
55-
56-
function checkWeight(input: string, target: string): boolean {
57-
// If the input looks like "100 900", we check it as is
58-
const trimmedInput = input.trim();
59-
if (trimmedInput.includes(' ')) {
60-
return trimmedInput === target;
61-
}
62-
// If the target looks like "100 900", we check if the input is between the values
63-
if (target.includes(' ')) {
64-
const [a, b] = target.split(' ');
65-
const parsedInput = Number.parseInt(input);
66-
return parsedInput >= Number.parseInt(a) && parsedInput <= Number.parseInt(b);
67-
}
68-
return input === target;
69-
}
4+
export const getFontData = createGetFontData(fontsMod);

packages/astro/src/assets/vite-plugin-assets.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,7 @@ export default function assets({ fs, settings, sync, logger }: Options): vite.Pl
149149
export { inferRemoteSize } from "astro/assets/utils/inferRemoteSize.js";
150150
151151
export { default as Font } from "astro/components/Font.astro";
152-
import * as fontsMod from 'virtual:astro:assets/fonts/internal';
153-
import { createGetFontData } from "astro/assets/fonts/runtime";
152+
export * from "astro/assets/fonts/runtime";
154153
155154
export const viteFSConfig = ${JSON.stringify(resolvedConfig.server.fs ?? {})};
156155
@@ -189,8 +188,6 @@ export default function assets({ fs, settings, sync, logger }: Options): vite.Pl
189188
new URL(settings.config.build.server),
190189
)});
191190
export const getImage = async (options) => await getImageInternal(options, imageConfig);
192-
193-
export const getFontData = createGetFontData(fontsMod);
194191
`,
195192
};
196193
}

packages/astro/test/units/assets/fonts/core.test.js

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// @ts-check
22
import assert from 'node:assert/strict';
33
import { describe, it } from 'node:test';
4+
import { createGetFontData } from '../../../../dist/assets/fonts/core/create-get-font-data.js';
5+
import { filterPreloads } from '../../../../dist/assets/fonts/core/filter-preloads.js';
46
import { normalizeRemoteFontFaces } from '../../../../dist/assets/fonts/core/normalize-remote-font-faces.js';
57
import { optimizeFallbacks } from '../../../../dist/assets/fonts/core/optimize-fallbacks.js';
68
import { resolveFamily } from '../../../../dist/assets/fonts/core/resolve-families.js';
@@ -593,4 +595,174 @@ describe('fonts core', () => {
593595
]);
594596
});
595597
});
598+
599+
describe('filterPreloads()', () => {
600+
it('returns null if it should not preload', () => {
601+
assert.equal(filterPreloads([], false), null);
602+
});
603+
604+
it('returns everything if it should preload all', () => {
605+
assert.deepStrictEqual(
606+
filterPreloads(
607+
[
608+
{
609+
style: 'normal',
610+
subset: undefined,
611+
type: 'woff2',
612+
url: 'foo',
613+
weight: undefined,
614+
},
615+
{
616+
style: 'italic',
617+
subset: 'latin',
618+
type: 'otf',
619+
url: 'bar',
620+
weight: undefined,
621+
},
622+
],
623+
true,
624+
),
625+
[
626+
{
627+
style: 'normal',
628+
subset: undefined,
629+
type: 'woff2',
630+
url: 'foo',
631+
weight: undefined,
632+
},
633+
{
634+
style: 'italic',
635+
subset: 'latin',
636+
type: 'otf',
637+
url: 'bar',
638+
weight: undefined,
639+
},
640+
],
641+
);
642+
});
643+
644+
it('returns filtered data', () => {
645+
assert.deepStrictEqual(
646+
filterPreloads(
647+
[
648+
{
649+
style: 'normal',
650+
subset: undefined,
651+
type: 'woff2',
652+
url: 'foo',
653+
weight: undefined,
654+
},
655+
{
656+
style: 'italic',
657+
subset: 'latin',
658+
type: 'otf',
659+
url: 'bar',
660+
weight: undefined,
661+
},
662+
],
663+
[
664+
{
665+
style: 'normal',
666+
},
667+
],
668+
),
669+
[
670+
{
671+
style: 'normal',
672+
subset: undefined,
673+
type: 'woff2',
674+
url: 'foo',
675+
weight: undefined,
676+
},
677+
],
678+
);
679+
});
680+
681+
it('returns variable weight', () => {
682+
assert.deepStrictEqual(
683+
filterPreloads(
684+
[
685+
{
686+
style: 'normal',
687+
subset: undefined,
688+
type: 'woff2',
689+
url: 'foo',
690+
weight: '500 900',
691+
},
692+
{
693+
style: 'italic',
694+
subset: 'latin',
695+
type: 'otf',
696+
url: 'bar',
697+
weight: '100 900',
698+
},
699+
],
700+
[
701+
{
702+
weight: '400',
703+
},
704+
],
705+
),
706+
[
707+
{
708+
style: 'italic',
709+
subset: 'latin',
710+
type: 'otf',
711+
url: 'bar',
712+
weight: '100 900',
713+
},
714+
],
715+
);
716+
717+
assert.deepStrictEqual(
718+
filterPreloads(
719+
[
720+
{
721+
style: 'normal',
722+
subset: undefined,
723+
type: 'woff2',
724+
url: 'foo',
725+
weight: '500 900',
726+
},
727+
{
728+
style: 'italic',
729+
subset: 'latin',
730+
type: 'otf',
731+
url: 'bar',
732+
weight: '100 900',
733+
},
734+
],
735+
[
736+
{
737+
weight: ' 100 900',
738+
},
739+
],
740+
),
741+
[
742+
{
743+
style: 'italic',
744+
subset: 'latin',
745+
type: 'otf',
746+
url: 'bar',
747+
weight: '100 900',
748+
},
749+
],
750+
);
751+
});
752+
});
753+
754+
describe('createGetFontData()', () => {
755+
it('throws if there is no consumable map', () => {
756+
assert.throws(() => createGetFontData({ consumableMap: undefined })('foo'));
757+
});
758+
759+
it('throws if no data can be found', () => {
760+
assert.throws(() => createGetFontData({ consumableMap: new Map([['bar', []]]) })('foo'));
761+
});
762+
763+
it('works when there is data', () => {
764+
const data = createGetFontData({ consumableMap: new Map([['bar', []]]) })('bar');
765+
assert.deepStrictEqual(data, []);
766+
});
767+
});
596768
});

0 commit comments

Comments
 (0)