subfont 6.7.0 → 6.10.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/CHANGELOG.md +22 -0
- package/lib/getCssRulesByProperty.js +50 -24
- package/lib/parseFontVariationSettings.js +39 -0
- package/lib/subsetFonts.js +351 -170
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
### v6.10.0 (2022-08-29)
|
|
2
|
+
|
|
3
|
+
- [Update @hookun\/parse-animation-shorthand to ^0.1.4 to make sure we get the fix for hookhookun\/parse-animation-shorthand\#16](https://github.com/Munter/subfont/commit/4db17826245e289e987c6dc02d3f67ebf5891e6f) ([Andreas Lind](mailto:andreas.lind@workday.com))
|
|
4
|
+
- [Disable notice about unused variation axis ranges when there's an out-of-bounds cubic-bezier animation timing function in play](https://github.com/Munter/subfont/commit/1cf4ff46bb6099f8df8602968c7dc0fefb1c1f21) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
|
|
5
|
+
- [Update font-tracer to ^3.6.0](https://github.com/Munter/subfont/commit/2a47adc03122aad50ba2a01f116a2d1fe0f2b29e) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
|
|
6
|
+
- [Remove accidentally committed commented out code](https://github.com/Munter/subfont/commit/e0c677f9b2c7a9af123045cf29bc78a4f9a56550) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
|
|
7
|
+
- [Warn about unused variation axis ranges, not just fully unused axes](https://github.com/Munter/subfont/commit/32fc472327b1c8fc87090d4c1e5f1085533ad8fa) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
|
|
8
|
+
- [+13 more](https://github.com/Munter/subfont/compare/v6.9.0...v6.10.0)
|
|
9
|
+
|
|
10
|
+
### v6.9.0 (2022-08-07)
|
|
11
|
+
|
|
12
|
+
- [Update font-tracer to ^3.3.0 Adds support for tracing ::marker, fixes \#166](https://github.com/Munter/subfont/commit/e46c79bac9cb3e62c70deb357823b7963114863b) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
|
|
13
|
+
- [Move some code into a collectTextsByPage function](https://github.com/Munter/subfont/commit/1dff3819fb80793f23a3cc37f9ff58bafffa4efc) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
|
|
14
|
+
- [Move the missing glyph detection to a function](https://github.com/Munter/subfont/commit/38bf36eba4370ecdbc777cb2457696b9bc7c7d1c) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
|
|
15
|
+
- [Fix typo causing regexp to not be matched correctly](https://github.com/Munter/subfont/commit/05137708b5c48af305f3119deb836b1cd9fed683) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
|
|
16
|
+
- [Remove delayed minification of CSS, seems like it's no longer necessary](https://github.com/Munter/subfont/commit/b98976b24c3a859ffbdd2a43f9f05e5048175f5a) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
|
|
17
|
+
|
|
18
|
+
### v6.8.0 (2022-07-28)
|
|
19
|
+
|
|
20
|
+
- [Update assetgraph to ^7.8.1](https://github.com/Munter/subfont/commit/888a97912f98bd937a53b7bec0f39d50ddc96023) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
|
|
21
|
+
- [Don't leave stylesheets behind that only contain comments after removing @font-face rules from them https:\/\/github.com\/Munter\/subfont\/issues\/160\#issuecomment-1194672752](https://github.com/Munter/subfont/commit/3dfd9dfbbe5071b94eb52ac216796bc7c0554078) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
|
|
22
|
+
|
|
1
23
|
### v6.7.0 (2022-07-24)
|
|
2
24
|
|
|
3
25
|
- [Update subset-font to ^1.5.0](https://github.com/Munter/subfont/commit/ba79ef6db81cedfd0e52672b530ca3afddd68a94) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const specificity = require('specificity');
|
|
2
2
|
const postcss = require('postcss');
|
|
3
3
|
const unquote = require('./unquote');
|
|
4
|
+
const parseAnimationShorthand = require('@hookun/parse-animation-shorthand');
|
|
4
5
|
|
|
5
6
|
const counterRendererNames = new Set([
|
|
6
7
|
'none',
|
|
@@ -144,34 +145,59 @@ function getCssRulesByProperty(properties, cssSource, existingPredicates) {
|
|
|
144
145
|
});
|
|
145
146
|
});
|
|
146
147
|
}
|
|
147
|
-
} else if (
|
|
148
|
-
propName === 'animation' &&
|
|
149
|
-
properties.includes('animation-name')
|
|
150
|
-
) {
|
|
148
|
+
} else if (propName === 'animation') {
|
|
151
149
|
// Shorthand
|
|
152
|
-
const
|
|
150
|
+
const parsedAnimation = parseAnimationShorthand.parseSingle(node.value);
|
|
153
151
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
152
|
+
if (properties.includes('animation-name')) {
|
|
153
|
+
// Split up combined selectors as they might have different specificity
|
|
154
|
+
specificity
|
|
155
|
+
.calculate(node.parent.selector)
|
|
156
|
+
.forEach((specificityObject) => {
|
|
157
|
+
const isStyleAttribute =
|
|
158
|
+
specificityObject.selector === 'bogusselector';
|
|
160
159
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
160
|
+
rulesByProperty['animation-name'].push({
|
|
161
|
+
predicates: getCurrentPredicates(),
|
|
162
|
+
namespaceURI: defaultNamespaceURI,
|
|
163
|
+
selector: isStyleAttribute
|
|
164
|
+
? undefined
|
|
165
|
+
: specificityObject.selector.trim(),
|
|
166
|
+
specificityArray: isStyleAttribute
|
|
167
|
+
? [1, 0, 0, 0]
|
|
168
|
+
: specificityObject.specificityArray,
|
|
169
|
+
prop: 'animation-name',
|
|
170
|
+
value: parsedAnimation.name,
|
|
171
|
+
important: !!node.important,
|
|
172
|
+
});
|
|
173
173
|
});
|
|
174
|
-
|
|
174
|
+
}
|
|
175
|
+
if (properties.includes('animation-timing-function')) {
|
|
176
|
+
// Split up combined selectors as they might have different specificity
|
|
177
|
+
specificity
|
|
178
|
+
.calculate(node.parent.selector)
|
|
179
|
+
.forEach((specificityObject) => {
|
|
180
|
+
const isStyleAttribute =
|
|
181
|
+
specificityObject.selector === 'bogusselector';
|
|
182
|
+
|
|
183
|
+
rulesByProperty['animation-timing-function'].push({
|
|
184
|
+
predicates: getCurrentPredicates(),
|
|
185
|
+
namespaceURI: defaultNamespaceURI,
|
|
186
|
+
selector: isStyleAttribute
|
|
187
|
+
? undefined
|
|
188
|
+
: specificityObject.selector.trim(),
|
|
189
|
+
specificityArray: isStyleAttribute
|
|
190
|
+
? [1, 0, 0, 0]
|
|
191
|
+
: specificityObject.specificityArray,
|
|
192
|
+
prop: 'animation-timing-function',
|
|
193
|
+
value: parseAnimationShorthand.serialize({
|
|
194
|
+
name: '',
|
|
195
|
+
timingFunction: parsedAnimation.timingFunction,
|
|
196
|
+
}),
|
|
197
|
+
important: !!node.important,
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
}
|
|
175
201
|
} else if (propName === 'transition') {
|
|
176
202
|
// Shorthand
|
|
177
203
|
const transitionProperties = [];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const postcssValueParser = require('postcss-value-parser');
|
|
2
|
+
|
|
3
|
+
module.exports = function* parseFontVariationSettings(value) {
|
|
4
|
+
let state = 'BEFORE_AXIS_NAME';
|
|
5
|
+
let axisName;
|
|
6
|
+
for (const token of postcssValueParser(value).nodes) {
|
|
7
|
+
if (token.type === 'space') {
|
|
8
|
+
continue;
|
|
9
|
+
}
|
|
10
|
+
switch (state) {
|
|
11
|
+
case 'BEFORE_AXIS_NAME': {
|
|
12
|
+
if (token.type !== 'string') {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
axisName = token.value.toUpperCase();
|
|
16
|
+
state = 'AFTER_AXIS_NAME';
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
case 'AFTER_AXIS_NAME': {
|
|
20
|
+
if (token.type === 'word') {
|
|
21
|
+
const axisValue = parseFloat(token.value);
|
|
22
|
+
if (!isNaN(axisValue)) {
|
|
23
|
+
yield [axisName, axisValue];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
state = 'AFTER_AXIS_VALUE';
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
case 'AFTER_AXIS_VALUE': {
|
|
30
|
+
if (token.type !== 'div' || token.value !== ',') {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
axisName = undefined;
|
|
34
|
+
state = 'BEFORE_AXIS_NAME';
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
};
|
package/lib/subsetFonts.js
CHANGED
|
@@ -13,13 +13,14 @@ const HeadlessBrowser = require('./HeadlessBrowser');
|
|
|
13
13
|
const gatherStylesheetsWithPredicates = require('./gatherStylesheetsWithPredicates');
|
|
14
14
|
const findCustomPropertyDefinitions = require('./findCustomPropertyDefinitions');
|
|
15
15
|
const extractReferencedCustomPropertyNames = require('./extractReferencedCustomPropertyNames');
|
|
16
|
+
const parseFontVariationSettings = require('./parseFontVariationSettings');
|
|
17
|
+
const parseAnimationShorthand = require('@hookun/parse-animation-shorthand');
|
|
16
18
|
const stripLocalTokens = require('./stripLocalTokens');
|
|
17
19
|
const injectSubsetDefinitions = require('./injectSubsetDefinitions');
|
|
18
20
|
const cssFontParser = require('css-font-parser');
|
|
19
21
|
const cssListHelpers = require('css-list-helpers');
|
|
20
22
|
const LinesAndColumns = require('lines-and-columns').default;
|
|
21
23
|
const fontkit = require('fontkit');
|
|
22
|
-
const fontFamily = require('font-family-papandreou');
|
|
23
24
|
const crypto = require('crypto');
|
|
24
25
|
|
|
25
26
|
const unquote = require('./unquote');
|
|
@@ -41,6 +42,14 @@ const contentTypeByFontFormat = {
|
|
|
41
42
|
truetype: 'font/ttf',
|
|
42
43
|
};
|
|
43
44
|
|
|
45
|
+
function stringifyFontFamily(name) {
|
|
46
|
+
if (/[^a-z0-9_-]/i.test(name)) {
|
|
47
|
+
return name.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
48
|
+
} else {
|
|
49
|
+
return name;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
44
53
|
function uniqueChars(text) {
|
|
45
54
|
return [...new Set([...text])].sort().join('');
|
|
46
55
|
}
|
|
@@ -79,6 +88,21 @@ function getPreferredFontUrl(cssFontFaceSrcRelations = []) {
|
|
|
79
88
|
}
|
|
80
89
|
}
|
|
81
90
|
|
|
91
|
+
function isOutOfBoundsAnimationTimingFunction(animationTimingFunctionStr) {
|
|
92
|
+
if (typeof animationTimingFunctionStr !== 'string') {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
const { timingFunction } = parseAnimationShorthand.parseSingle(
|
|
96
|
+
`${animationTimingFunctionStr} ignored-name`
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
if (timingFunction.type === 'cubic-bezier') {
|
|
100
|
+
const [, y1, , y2] = timingFunction.value;
|
|
101
|
+
return y1 > 1 || y1 < 0 || y2 > 1 || y2 < 0;
|
|
102
|
+
}
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
|
|
82
106
|
// Hack to extract '@font-face { ... }' with all absolute urls
|
|
83
107
|
function getFontFaceDeclarationText(node, relations) {
|
|
84
108
|
const originalHrefTypeByRelation = new Map();
|
|
@@ -145,8 +169,8 @@ function groupTextsByFontFamilyProps(
|
|
|
145
169
|
return [];
|
|
146
170
|
}
|
|
147
171
|
// Find all the families in the traced font-family that we have @font-face declarations for:
|
|
148
|
-
const families =
|
|
149
|
-
.
|
|
172
|
+
const families = cssFontParser
|
|
173
|
+
.parseFontFamily(family)
|
|
150
174
|
.filter((family) =>
|
|
151
175
|
availableFontFaceDeclarations.some(
|
|
152
176
|
(fontFace) =>
|
|
@@ -159,7 +183,7 @@ function groupTextsByFontFamilyProps(
|
|
|
159
183
|
availableFontFaceDeclarations,
|
|
160
184
|
{
|
|
161
185
|
...textAndProps.props,
|
|
162
|
-
'font-family':
|
|
186
|
+
'font-family': stringifyFontFamily(family),
|
|
163
187
|
}
|
|
164
188
|
);
|
|
165
189
|
|
|
@@ -173,6 +197,9 @@ function groupTextsByFontFamilyProps(
|
|
|
173
197
|
return {
|
|
174
198
|
htmlOrSvgAsset: textAndProps.htmlOrSvgAsset,
|
|
175
199
|
text: textAndProps.text,
|
|
200
|
+
fontVariationSettings: textAndProps.props['font-variation-settings'],
|
|
201
|
+
animationTimingFunction:
|
|
202
|
+
textAndProps.props['animation-timing-function'],
|
|
176
203
|
props,
|
|
177
204
|
fontRelations: relations,
|
|
178
205
|
fontUrl,
|
|
@@ -190,6 +217,18 @@ function groupTextsByFontFamilyProps(
|
|
|
190
217
|
const fontFamilies = new Set(
|
|
191
218
|
textsPropsArray.map((obj) => obj.props['font-family'])
|
|
192
219
|
);
|
|
220
|
+
const fontVariationSettings = new Set(
|
|
221
|
+
textsPropsArray
|
|
222
|
+
.map((obj) => obj.fontVariationSettings)
|
|
223
|
+
.filter(
|
|
224
|
+
(fontVariationSettings) =>
|
|
225
|
+
fontVariationSettings &&
|
|
226
|
+
fontVariationSettings.toLowerCase() !== 'normal'
|
|
227
|
+
)
|
|
228
|
+
);
|
|
229
|
+
const hasOutOfBoundsAnimationTimingFunction = textsPropsArray.some((obj) =>
|
|
230
|
+
isOutOfBoundsAnimationTimingFunction(obj.animationTimingFunction)
|
|
231
|
+
);
|
|
193
232
|
|
|
194
233
|
let smallestOriginalSize;
|
|
195
234
|
let smallestOriginalFormat;
|
|
@@ -217,6 +256,8 @@ function groupTextsByFontFamilyProps(
|
|
|
217
256
|
props: { ...textsPropsArray[0].props },
|
|
218
257
|
fontUrl,
|
|
219
258
|
fontFamilies,
|
|
259
|
+
fontVariationSettings,
|
|
260
|
+
hasOutOfBoundsAnimationTimingFunction,
|
|
220
261
|
preload,
|
|
221
262
|
};
|
|
222
263
|
});
|
|
@@ -497,9 +538,9 @@ async function createSelfHostedGoogleFontsCssAsset(
|
|
|
497
538
|
assetGraph,
|
|
498
539
|
googleFontsCssAsset,
|
|
499
540
|
formats,
|
|
500
|
-
hrefType
|
|
541
|
+
hrefType,
|
|
542
|
+
subsetUrl
|
|
501
543
|
) {
|
|
502
|
-
const baseUrl = assetGraph.resolveUrl(assetGraph.root, '/subfont/');
|
|
503
544
|
const lines = [];
|
|
504
545
|
for (const cssFontFaceSrc of assetGraph.findRelations({
|
|
505
546
|
from: googleFontsCssAsset,
|
|
@@ -516,9 +557,12 @@ async function createSelfHostedGoogleFontsCssAsset(
|
|
|
516
557
|
const srcFragments = [];
|
|
517
558
|
for (const format of formats) {
|
|
518
559
|
const rawSrc = await fontverter.convert(cssFontFaceSrc.to.rawSrc, format);
|
|
519
|
-
const url =
|
|
520
|
-
|
|
521
|
-
|
|
560
|
+
const url = assetGraph.resolveUrl(
|
|
561
|
+
subsetUrl,
|
|
562
|
+
`${cssFontFaceSrc.to.baseName}-${md5HexPrefix(rawSrc)}${
|
|
563
|
+
extensionByFormat[format]
|
|
564
|
+
}`
|
|
565
|
+
);
|
|
522
566
|
const fontAsset =
|
|
523
567
|
assetGraph.findAssets({ url })[0] ||
|
|
524
568
|
(await assetGraph.addAsset({
|
|
@@ -526,7 +570,7 @@ async function createSelfHostedGoogleFontsCssAsset(
|
|
|
526
570
|
rawSrc,
|
|
527
571
|
}));
|
|
528
572
|
srcFragments.push(
|
|
529
|
-
`url(${assetGraph.buildHref(fontAsset.url,
|
|
573
|
+
`url(${assetGraph.buildHref(fontAsset.url, subsetUrl, {
|
|
530
574
|
hrefType,
|
|
531
575
|
})}) format('${format}')`
|
|
532
576
|
);
|
|
@@ -542,7 +586,7 @@ async function createSelfHostedGoogleFontsCssAsset(
|
|
|
542
586
|
const text = lines.join('\n');
|
|
543
587
|
const fallbackAsset = assetGraph.addAsset({
|
|
544
588
|
type: 'Css',
|
|
545
|
-
url:
|
|
589
|
+
url: assetGraph.resolveUrl(subsetUrl, `fallback-${md5HexPrefix(text)}.css`),
|
|
546
590
|
text,
|
|
547
591
|
});
|
|
548
592
|
return fallbackAsset;
|
|
@@ -568,62 +612,228 @@ function getCodepoints(text) {
|
|
|
568
612
|
return codepoints;
|
|
569
613
|
}
|
|
570
614
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
}
|
|
615
|
+
function cssAssetIsEmpty(cssAsset) {
|
|
616
|
+
return cssAsset.parseTree.nodes.every(
|
|
617
|
+
(node) => node.type === 'comment' && !node.text.startsWith('!')
|
|
618
|
+
);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
function warnAboutMissingGlyphs(htmlOrSvgAssetTextsWithProps, assetGraph) {
|
|
622
|
+
const missingGlyphsErrors = [];
|
|
623
|
+
|
|
624
|
+
for (const {
|
|
625
|
+
htmlOrSvgAsset,
|
|
626
|
+
fontUsages,
|
|
627
|
+
accumulatedFontFaceDeclarations,
|
|
628
|
+
} of htmlOrSvgAssetTextsWithProps) {
|
|
629
|
+
for (const fontUsage of fontUsages) {
|
|
630
|
+
if (fontUsage.subsets) {
|
|
631
|
+
const characterSet = fontkit.create(
|
|
632
|
+
Object.values(fontUsage.subsets)[0]
|
|
633
|
+
).characterSet;
|
|
634
|
+
|
|
635
|
+
let missedAny = false;
|
|
636
|
+
for (const char of [...fontUsage.pageText]) {
|
|
637
|
+
// Turns out that browsers don't mind that these are missing:
|
|
638
|
+
if (char === '\t' || char === '\n') {
|
|
639
|
+
continue;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
const codePoint = char.codePointAt(0);
|
|
643
|
+
|
|
644
|
+
const isMissing = !characterSet.includes(codePoint);
|
|
645
|
+
|
|
646
|
+
if (isMissing) {
|
|
647
|
+
let location;
|
|
648
|
+
const charIdx = htmlOrSvgAsset.text.indexOf(char);
|
|
649
|
+
|
|
650
|
+
if (charIdx === -1) {
|
|
651
|
+
location = `${htmlOrSvgAsset.urlOrDescription} (generated content)`;
|
|
652
|
+
} else {
|
|
653
|
+
const position = new LinesAndColumns(
|
|
654
|
+
htmlOrSvgAsset.text
|
|
655
|
+
).locationForIndex(charIdx);
|
|
656
|
+
location = `${htmlOrSvgAsset.urlOrDescription}:${
|
|
657
|
+
position.line + 1
|
|
658
|
+
}:${position.column + 1}`;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
missingGlyphsErrors.push({
|
|
662
|
+
codePoint,
|
|
663
|
+
char,
|
|
664
|
+
htmlOrSvgAsset,
|
|
665
|
+
fontUsage,
|
|
666
|
+
location,
|
|
667
|
+
});
|
|
668
|
+
missedAny = true;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
if (missedAny) {
|
|
672
|
+
const fontFaces = accumulatedFontFaceDeclarations.filter((fontFace) =>
|
|
673
|
+
fontUsage.fontFamilies.has(fontFace['font-family'])
|
|
674
|
+
);
|
|
675
|
+
for (const fontFace of fontFaces) {
|
|
676
|
+
const cssFontFaceSrc = fontFace.relations[0];
|
|
677
|
+
const fontFaceDeclaration = cssFontFaceSrc.node;
|
|
678
|
+
if (
|
|
679
|
+
!fontFaceDeclaration.some((node) => node.prop === 'unicode-range')
|
|
680
|
+
) {
|
|
681
|
+
fontFaceDeclaration.append({
|
|
682
|
+
prop: 'unicode-range',
|
|
683
|
+
value: unicodeRange(fontUsage.codepoints.original),
|
|
684
|
+
});
|
|
685
|
+
cssFontFaceSrc.from.markDirty();
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
if (missingGlyphsErrors.length) {
|
|
694
|
+
const errorLog = missingGlyphsErrors.map(
|
|
695
|
+
({ char, fontUsage, location }) =>
|
|
696
|
+
`- \\u{${char.codePointAt(0).toString(16)}} (${char}) in font-family '${
|
|
697
|
+
fontUsage.props['font-family']
|
|
698
|
+
}' (${fontUsage.props['font-weight']}/${
|
|
699
|
+
fontUsage.props['font-style']
|
|
700
|
+
}) at ${location}`
|
|
701
|
+
);
|
|
702
|
+
|
|
703
|
+
const message = `Missing glyph fallback detected.
|
|
704
|
+
When your primary webfont doesn't contain the glyphs you use, browsers that don't support unicode-range will load your fallback fonts, which will be a potential waste of bandwidth.
|
|
705
|
+
These glyphs are used on your site, but they don't exist in the font you applied to them:`;
|
|
706
|
+
|
|
707
|
+
assetGraph.info(new Error(`${message}\n${errorLog.join('\n')}`));
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
const standardVariationAxes = new Set(['WGHT', 'ITAL', 'SLNT', 'OPSZ']);
|
|
712
|
+
|
|
713
|
+
function warnAboutUnusedCustomVariationAxes(
|
|
714
|
+
htmlOrSvgAssetTextsWithProps,
|
|
715
|
+
assetGraph
|
|
585
716
|
) {
|
|
586
|
-
|
|
587
|
-
|
|
717
|
+
const seenAxisValuesByFontUrlAndAxisName = new Map();
|
|
718
|
+
const outOfBoundsAxesByFontUrl = new Map();
|
|
719
|
+
|
|
720
|
+
for (const { fontUsages } of htmlOrSvgAssetTextsWithProps) {
|
|
721
|
+
for (const {
|
|
722
|
+
fontUrl,
|
|
723
|
+
fontVariationSettings,
|
|
724
|
+
hasOutOfBoundsAnimationTimingFunction,
|
|
725
|
+
} of fontUsages) {
|
|
726
|
+
let seenAxes = seenAxisValuesByFontUrlAndAxisName.get(fontUrl);
|
|
727
|
+
if (!seenAxes) {
|
|
728
|
+
seenAxes = new Map();
|
|
729
|
+
seenAxisValuesByFontUrlAndAxisName.set(fontUrl, seenAxes);
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
for (const fontVariationSettingsValue of fontVariationSettings) {
|
|
733
|
+
for (const [axisName, axisValue] of parseFontVariationSettings(
|
|
734
|
+
fontVariationSettingsValue
|
|
735
|
+
)) {
|
|
736
|
+
const seenAxisValues = seenAxes.get(axisName);
|
|
737
|
+
if (seenAxisValues) {
|
|
738
|
+
seenAxisValues.push(axisValue);
|
|
739
|
+
} else {
|
|
740
|
+
seenAxes.set(axisName, [axisValue]);
|
|
741
|
+
}
|
|
742
|
+
if (hasOutOfBoundsAnimationTimingFunction) {
|
|
743
|
+
let outOfBoundsAxes = outOfBoundsAxesByFontUrl.get(fontUrl);
|
|
744
|
+
if (!outOfBoundsAxes) {
|
|
745
|
+
outOfBoundsAxes = new Set();
|
|
746
|
+
outOfBoundsAxesByFontUrl.set(fontUrl, outOfBoundsAxes);
|
|
747
|
+
}
|
|
748
|
+
outOfBoundsAxes.add(axisName);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
}
|
|
588
753
|
}
|
|
589
754
|
|
|
590
|
-
const
|
|
591
|
-
|
|
755
|
+
const warnings = [];
|
|
756
|
+
for (const [
|
|
757
|
+
fontUrl,
|
|
758
|
+
seenAxisValuesByAxisName,
|
|
759
|
+
] of seenAxisValuesByFontUrlAndAxisName.entries()) {
|
|
760
|
+
const outOfBoundsAxes = outOfBoundsAxesByFontUrl.get(fontUrl) || new Set();
|
|
761
|
+
let font;
|
|
762
|
+
try {
|
|
763
|
+
font = fontkit.create(assetGraph.findAssets({ url: fontUrl })[0].rawSrc);
|
|
764
|
+
} catch (err) {
|
|
765
|
+
// Don't break if we encounter an invalid font or one that's unsupported by fontkit
|
|
766
|
+
continue;
|
|
767
|
+
}
|
|
768
|
+
const unusedAxes = [];
|
|
769
|
+
const underutilizedAxes = [];
|
|
770
|
+
for (const { name, min, max, default: defaultValue } of Object.values(
|
|
771
|
+
font.variationAxes
|
|
772
|
+
)) {
|
|
773
|
+
const axisName = name.toUpperCase();
|
|
774
|
+
if (standardVariationAxes.has(axisName)) {
|
|
775
|
+
continue;
|
|
776
|
+
}
|
|
777
|
+
if (
|
|
778
|
+
seenAxisValuesByAxisName.has(axisName) &&
|
|
779
|
+
!outOfBoundsAxes.has(axisName)
|
|
780
|
+
) {
|
|
781
|
+
const usedValues = [
|
|
782
|
+
defaultValue,
|
|
783
|
+
...seenAxisValuesByAxisName.get(axisName),
|
|
784
|
+
];
|
|
785
|
+
const minUsed = Math.min(...usedValues);
|
|
786
|
+
const maxUsed = Math.max(...usedValues);
|
|
787
|
+
if (minUsed > min || maxUsed < max) {
|
|
788
|
+
underutilizedAxes.push({
|
|
789
|
+
name: axisName,
|
|
790
|
+
minUsed,
|
|
791
|
+
maxUsed,
|
|
792
|
+
min,
|
|
793
|
+
max,
|
|
794
|
+
});
|
|
795
|
+
}
|
|
796
|
+
} else {
|
|
797
|
+
unusedAxes.push(axisName);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
592
800
|
|
|
593
|
-
|
|
801
|
+
if (unusedAxes.length > 0 || underutilizedAxes.length > 0) {
|
|
802
|
+
let message = `${fontUrl}:\n`;
|
|
803
|
+
if (unusedAxes.length > 0) {
|
|
804
|
+
message += ` Unused axes: ${unusedAxes.join(', ')}\n`;
|
|
805
|
+
}
|
|
806
|
+
if (underutilizedAxes.length > 0) {
|
|
807
|
+
message += ` Underutilized axes:\n${underutilizedAxes
|
|
808
|
+
.map(
|
|
809
|
+
({ name, min, max, minUsed, maxUsed }) =>
|
|
810
|
+
` ${name}: ${minUsed}-${maxUsed} used (${min}-${max} available)`
|
|
811
|
+
)
|
|
812
|
+
.join('\n')}\n`;
|
|
813
|
+
}
|
|
814
|
+
warnings.push(message);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
594
817
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
from: {
|
|
606
|
-
url: googleFontsCssUrlRegex,
|
|
607
|
-
},
|
|
608
|
-
},
|
|
609
|
-
],
|
|
610
|
-
},
|
|
611
|
-
});
|
|
818
|
+
if (warnings.length > 0) {
|
|
819
|
+
assetGraph.info(
|
|
820
|
+
new Error(`🪓 Unused custom variation axes detected in your variable fonts.
|
|
821
|
+
The below variable fonts contain custom axes that do not appear to be fully used on any of your pages.
|
|
822
|
+
This bloats your fonts and also the subset fonts that subfont creates.
|
|
823
|
+
Consider removing the unused axis ranges using a tool like Slice <https://slice-gui.netlify.app/>
|
|
824
|
+
${warnings.join('\n')}`)
|
|
825
|
+
);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
612
828
|
|
|
613
|
-
|
|
829
|
+
async function collectTextsByPage(
|
|
830
|
+
assetGraph,
|
|
831
|
+
htmlOrSvgAssets,
|
|
832
|
+
{ text, console, dynamic = false } = {}
|
|
833
|
+
) {
|
|
834
|
+
const htmlOrSvgAssetTextsWithProps = [];
|
|
614
835
|
|
|
615
836
|
const memoizedGetCssRulesByProperty = memoizeSync(getCssRulesByProperty);
|
|
616
|
-
const htmlOrSvgAssets = assetGraph.findAssets({
|
|
617
|
-
$or: [
|
|
618
|
-
{
|
|
619
|
-
type: 'Html',
|
|
620
|
-
isInline: false,
|
|
621
|
-
},
|
|
622
|
-
{
|
|
623
|
-
type: 'Svg',
|
|
624
|
-
},
|
|
625
|
-
],
|
|
626
|
-
});
|
|
627
837
|
const traversalRelationQuery = {
|
|
628
838
|
$or: [
|
|
629
839
|
{
|
|
@@ -638,12 +848,7 @@ async function subsetFonts(
|
|
|
638
848
|
],
|
|
639
849
|
};
|
|
640
850
|
|
|
641
|
-
// Keep track of the injected CSS assets that should eventually be minified
|
|
642
|
-
// Minifying them along the way currently doesn't work because some of the
|
|
643
|
-
// manipulation is sensitive to the exact text contents. We should fix that.
|
|
644
|
-
const subsetFontsToBeMinified = new Set();
|
|
645
851
|
const fontFaceDeclarationsByHtmlOrSvgAsset = new Map();
|
|
646
|
-
const potentiallyOrphanedAssets = new Set();
|
|
647
852
|
|
|
648
853
|
const headlessBrowser = dynamic && new HeadlessBrowser({ console });
|
|
649
854
|
const globalTextByProps = [];
|
|
@@ -679,9 +884,8 @@ async function subsetFonts(
|
|
|
679
884
|
node.walkDecls((declaration) => {
|
|
680
885
|
const propName = declaration.prop.toLowerCase();
|
|
681
886
|
if (propName === 'font-family') {
|
|
682
|
-
fontFaceDeclaration[propName] =
|
|
683
|
-
declaration.value
|
|
684
|
-
)[0];
|
|
887
|
+
fontFaceDeclaration[propName] =
|
|
888
|
+
cssFontParser.parseFontFamily(declaration.value)[0];
|
|
685
889
|
} else {
|
|
686
890
|
fontFaceDeclaration[propName] = declaration.value;
|
|
687
891
|
}
|
|
@@ -768,7 +972,72 @@ async function subsetFonts(
|
|
|
768
972
|
}
|
|
769
973
|
}
|
|
770
974
|
}
|
|
975
|
+
return { htmlOrSvgAssetTextsWithProps, fontFaceDeclarationsByHtmlOrSvgAsset };
|
|
976
|
+
}
|
|
771
977
|
|
|
978
|
+
async function subsetFonts(
|
|
979
|
+
assetGraph,
|
|
980
|
+
{
|
|
981
|
+
formats = ['woff2', 'woff'],
|
|
982
|
+
subsetPath = 'subfont/',
|
|
983
|
+
omitFallbacks = false,
|
|
984
|
+
inlineCss,
|
|
985
|
+
fontDisplay,
|
|
986
|
+
hrefType = 'rootRelative',
|
|
987
|
+
onlyInfo,
|
|
988
|
+
dynamic,
|
|
989
|
+
console = global.console,
|
|
990
|
+
text,
|
|
991
|
+
} = {}
|
|
992
|
+
) {
|
|
993
|
+
if (!validFontDisplayValues.includes(fontDisplay)) {
|
|
994
|
+
fontDisplay = undefined;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
const subsetUrl = urltools.ensureTrailingSlash(assetGraph.root + subsetPath);
|
|
998
|
+
|
|
999
|
+
await assetGraph.applySourceMaps({ type: 'Css' });
|
|
1000
|
+
|
|
1001
|
+
await assetGraph.populate({
|
|
1002
|
+
followRelations: {
|
|
1003
|
+
$or: [
|
|
1004
|
+
{
|
|
1005
|
+
to: {
|
|
1006
|
+
url: { $regex: googleFontsCssUrlRegex },
|
|
1007
|
+
},
|
|
1008
|
+
},
|
|
1009
|
+
{
|
|
1010
|
+
type: 'CssFontFaceSrc',
|
|
1011
|
+
from: {
|
|
1012
|
+
url: { $regex: googleFontsCssUrlRegex },
|
|
1013
|
+
},
|
|
1014
|
+
},
|
|
1015
|
+
],
|
|
1016
|
+
},
|
|
1017
|
+
});
|
|
1018
|
+
|
|
1019
|
+
const htmlOrSvgAssets = assetGraph.findAssets({
|
|
1020
|
+
$or: [
|
|
1021
|
+
{
|
|
1022
|
+
type: 'Html',
|
|
1023
|
+
isInline: false,
|
|
1024
|
+
},
|
|
1025
|
+
{
|
|
1026
|
+
type: 'Svg',
|
|
1027
|
+
},
|
|
1028
|
+
],
|
|
1029
|
+
});
|
|
1030
|
+
|
|
1031
|
+
// Collect texts by page
|
|
1032
|
+
|
|
1033
|
+
const { htmlOrSvgAssetTextsWithProps, fontFaceDeclarationsByHtmlOrSvgAsset } =
|
|
1034
|
+
await collectTextsByPage(assetGraph, htmlOrSvgAssets, {
|
|
1035
|
+
text,
|
|
1036
|
+
console,
|
|
1037
|
+
dynamic,
|
|
1038
|
+
});
|
|
1039
|
+
|
|
1040
|
+
const potentiallyOrphanedAssets = new Set();
|
|
772
1041
|
if (omitFallbacks) {
|
|
773
1042
|
for (const htmlOrSvgAsset of htmlOrSvgAssets) {
|
|
774
1043
|
const accumulatedFontFaceDeclarations =
|
|
@@ -842,94 +1111,8 @@ async function subsetFonts(
|
|
|
842
1111
|
formats
|
|
843
1112
|
);
|
|
844
1113
|
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
for (const {
|
|
849
|
-
htmlOrSvgAsset,
|
|
850
|
-
fontUsages,
|
|
851
|
-
accumulatedFontFaceDeclarations,
|
|
852
|
-
} of htmlOrSvgAssetTextsWithProps) {
|
|
853
|
-
for (const fontUsage of fontUsages) {
|
|
854
|
-
if (fontUsage.subsets) {
|
|
855
|
-
const characterSet = fontkit.create(
|
|
856
|
-
Object.values(fontUsage.subsets)[0]
|
|
857
|
-
).characterSet;
|
|
858
|
-
|
|
859
|
-
let missedAny = false;
|
|
860
|
-
for (const char of [...fontUsage.pageText]) {
|
|
861
|
-
// Turns out that browsers don't mind that these are missing:
|
|
862
|
-
if (char === '\t' || char === '\n') {
|
|
863
|
-
continue;
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
const codePoint = char.codePointAt(0);
|
|
867
|
-
|
|
868
|
-
const isMissing = !characterSet.includes(codePoint);
|
|
869
|
-
|
|
870
|
-
if (isMissing) {
|
|
871
|
-
let location;
|
|
872
|
-
const charIdx = htmlOrSvgAsset.text.indexOf(char);
|
|
873
|
-
|
|
874
|
-
if (charIdx === -1) {
|
|
875
|
-
location = `${htmlOrSvgAsset.urlOrDescription} (generated content)`;
|
|
876
|
-
} else {
|
|
877
|
-
const position = new LinesAndColumns(
|
|
878
|
-
htmlOrSvgAsset.text
|
|
879
|
-
).locationForIndex(charIdx);
|
|
880
|
-
location = `${htmlOrSvgAsset.urlOrDescription}:${
|
|
881
|
-
position.line + 1
|
|
882
|
-
}:${position.column + 1}`;
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
missingGlyphsErrors.push({
|
|
886
|
-
codePoint,
|
|
887
|
-
char,
|
|
888
|
-
htmlOrSvgAsset,
|
|
889
|
-
fontUsage,
|
|
890
|
-
location,
|
|
891
|
-
});
|
|
892
|
-
missedAny = true;
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
if (missedAny) {
|
|
896
|
-
const fontFaces = accumulatedFontFaceDeclarations.filter((fontFace) =>
|
|
897
|
-
fontUsage.fontFamilies.has(fontFace['font-family'])
|
|
898
|
-
);
|
|
899
|
-
for (const fontFace of fontFaces) {
|
|
900
|
-
const cssFontFaceSrc = fontFace.relations[0];
|
|
901
|
-
const fontFaceDeclaration = cssFontFaceSrc.node;
|
|
902
|
-
if (
|
|
903
|
-
!fontFaceDeclaration.some((node) => node.prop === 'unicode-range')
|
|
904
|
-
) {
|
|
905
|
-
fontFaceDeclaration.append({
|
|
906
|
-
prop: 'unicode-range',
|
|
907
|
-
value: unicodeRange(fontUsage.codepoints.original),
|
|
908
|
-
});
|
|
909
|
-
cssFontFaceSrc.from.markDirty();
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
if (missingGlyphsErrors.length) {
|
|
918
|
-
const errorLog = missingGlyphsErrors.map(
|
|
919
|
-
({ char, fontUsage, location }) =>
|
|
920
|
-
`- \\u{${char.codePointAt(0).toString(16)}} (${char}) in font-family '${
|
|
921
|
-
fontUsage.props['font-family']
|
|
922
|
-
}' (${fontUsage.props['font-weight']}/${
|
|
923
|
-
fontUsage.props['font-style']
|
|
924
|
-
}) at ${location}`
|
|
925
|
-
);
|
|
926
|
-
|
|
927
|
-
const message = `Missing glyph fallback detected.
|
|
928
|
-
When your primary webfont doesn't contain the glyphs you use, browsers that don't support unicode-range will load your fallback fonts, which will be a potential waste of bandwidth.
|
|
929
|
-
These glyphs are used on your site, but they don't exist in the font you applied to them:`;
|
|
930
|
-
|
|
931
|
-
assetGraph.info(new Error(`${message}\n${errorLog.join('\n')}`));
|
|
932
|
-
}
|
|
1114
|
+
warnAboutMissingGlyphs(htmlOrSvgAssetTextsWithProps, assetGraph);
|
|
1115
|
+
warnAboutUnusedCustomVariationAxes(htmlOrSvgAssetTextsWithProps, assetGraph);
|
|
933
1116
|
|
|
934
1117
|
// Insert subsets:
|
|
935
1118
|
|
|
@@ -1015,7 +1198,7 @@ These glyphs are used on your site, but they don't exist in the font you applied
|
|
|
1015
1198
|
text: subsetCssText,
|
|
1016
1199
|
});
|
|
1017
1200
|
|
|
1018
|
-
|
|
1201
|
+
await cssAsset.minify();
|
|
1019
1202
|
|
|
1020
1203
|
for (const [i, fontRelation] of cssAsset.outgoingRelations.entries()) {
|
|
1021
1204
|
const fontAsset = fontRelation.to;
|
|
@@ -1085,7 +1268,6 @@ These glyphs are used on your site, but they don't exist in the font you applied
|
|
|
1085
1268
|
const existingCssAsset = assetGraph.findAssets({ url: cssAssetUrl })[0];
|
|
1086
1269
|
if (existingCssAsset) {
|
|
1087
1270
|
assetGraph.removeAsset(cssAsset);
|
|
1088
|
-
subsetFontsToBeMinified.delete(cssAsset);
|
|
1089
1271
|
cssAsset = existingCssAsset;
|
|
1090
1272
|
} else {
|
|
1091
1273
|
cssAsset.url = cssAssetUrl;
|
|
@@ -1099,7 +1281,7 @@ These glyphs are used on your site, but they don't exist in the font you applied
|
|
|
1099
1281
|
|
|
1100
1282
|
if (
|
|
1101
1283
|
fontAsset.contentType === 'font/woff2' &&
|
|
1102
|
-
fontRelation.to.
|
|
1284
|
+
fontRelation.to.url.startsWith(subsetUrl)
|
|
1103
1285
|
) {
|
|
1104
1286
|
const fontFaceDeclaration = fontRelation.node;
|
|
1105
1287
|
const originalFontFamily = unquote(
|
|
@@ -1220,7 +1402,7 @@ These glyphs are used on your site, but they don't exist in the font you applied
|
|
|
1220
1402
|
assetGraph.removeAsset(cssAsset);
|
|
1221
1403
|
cssAsset = existingCssAsset;
|
|
1222
1404
|
} else {
|
|
1223
|
-
|
|
1405
|
+
await cssAsset.minify();
|
|
1224
1406
|
cssAsset.url = cssAssetUrl;
|
|
1225
1407
|
}
|
|
1226
1408
|
|
|
@@ -1252,8 +1434,9 @@ These glyphs are used on your site, but they don't exist in the font you applied
|
|
|
1252
1434
|
cssAsset.markDirty();
|
|
1253
1435
|
maybeEmptyCssAssets.add(cssAsset);
|
|
1254
1436
|
}
|
|
1437
|
+
|
|
1255
1438
|
for (const cssAsset of maybeEmptyCssAssets) {
|
|
1256
|
-
if (cssAsset
|
|
1439
|
+
if (cssAssetIsEmpty(cssAsset)) {
|
|
1257
1440
|
for (const incomingRelation of cssAsset.incomingRelations) {
|
|
1258
1441
|
incomingRelation.detach();
|
|
1259
1442
|
}
|
|
@@ -1302,9 +1485,10 @@ These glyphs are used on your site, but they don't exist in the font you applied
|
|
|
1302
1485
|
assetGraph,
|
|
1303
1486
|
googleFontStylesheetRelation.to,
|
|
1304
1487
|
formats,
|
|
1305
|
-
hrefType
|
|
1488
|
+
hrefType,
|
|
1489
|
+
subsetUrl
|
|
1306
1490
|
);
|
|
1307
|
-
|
|
1491
|
+
await selfHostedGoogleFontsCssAsset.minify();
|
|
1308
1492
|
selfHostedGoogleCssByUrl.set(
|
|
1309
1493
|
googleFontStylesheetRelation.to.url,
|
|
1310
1494
|
selfHostedGoogleFontsCssAsset
|
|
@@ -1367,7 +1551,9 @@ These glyphs are used on your site, but they don't exist in the font you applied
|
|
|
1367
1551
|
);
|
|
1368
1552
|
for (let i = 0; i < fontFamilies.length; i += 1) {
|
|
1369
1553
|
const subsetFontFamily =
|
|
1370
|
-
webfontNameMap[
|
|
1554
|
+
webfontNameMap[
|
|
1555
|
+
cssFontParser.parseFontFamily(fontFamilies[i])[0].toLowerCase()
|
|
1556
|
+
];
|
|
1371
1557
|
if (subsetFontFamily && !fontFamilies.includes(subsetFontFamily)) {
|
|
1372
1558
|
fontFamilies.splice(
|
|
1373
1559
|
i,
|
|
@@ -1427,7 +1613,7 @@ These glyphs are used on your site, but they don't exist in the font you applied
|
|
|
1427
1613
|
for (let i = 0; i < fontFamilies.length; i += 1) {
|
|
1428
1614
|
const subsetFontFamily =
|
|
1429
1615
|
webfontNameMap[
|
|
1430
|
-
|
|
1616
|
+
cssFontParser.parseFontFamily(fontFamilies[i])[0].toLowerCase()
|
|
1431
1617
|
];
|
|
1432
1618
|
if (subsetFontFamily && !fontFamilies.includes(subsetFontFamily)) {
|
|
1433
1619
|
fontFamilies.splice(
|
|
@@ -1441,7 +1627,7 @@ These glyphs are used on your site, but they don't exist in the font you applied
|
|
|
1441
1627
|
}
|
|
1442
1628
|
}
|
|
1443
1629
|
} else if (propName === 'font') {
|
|
1444
|
-
const fontProperties = cssFontParser(cssRule.value);
|
|
1630
|
+
const fontProperties = cssFontParser.parseFont(cssRule.value);
|
|
1445
1631
|
const fontFamilies =
|
|
1446
1632
|
fontProperties && fontProperties['font-family'].map(unquote);
|
|
1447
1633
|
if (fontFamilies) {
|
|
@@ -1485,11 +1671,6 @@ These glyphs are used on your site, but they don't exist in the font you applied
|
|
|
1485
1671
|
}
|
|
1486
1672
|
}
|
|
1487
1673
|
|
|
1488
|
-
// This is a bit awkward now, but if it's done sooner, it breaks the CSS source regexping:
|
|
1489
|
-
for (const cssAsset of subsetFontsToBeMinified) {
|
|
1490
|
-
await cssAsset.minify();
|
|
1491
|
-
}
|
|
1492
|
-
|
|
1493
1674
|
await assetGraph.serializeSourceMaps(undefined, {
|
|
1494
1675
|
type: 'Css',
|
|
1495
1676
|
outgoingRelations: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "subfont",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.10.0",
|
|
4
4
|
"description": "Speeds up your pages initial paint by automatically subsetting local or Google fonts and loading them optimally",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=10.0.0"
|
|
@@ -47,14 +47,14 @@
|
|
|
47
47
|
"homepage": "https://github.com/Munter/subfont#readme",
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@gustavnikolaj/async-main-wrap": "^3.0.1",
|
|
50
|
-
"
|
|
50
|
+
"@hookun/parse-animation-shorthand": "^0.1.4",
|
|
51
|
+
"assetgraph": "^7.8.1",
|
|
51
52
|
"browserslist": "^4.13.0",
|
|
52
|
-
"css-font-parser": "^0.
|
|
53
|
+
"css-font-parser": "^2.0.0",
|
|
53
54
|
"css-font-weight-names": "^0.2.1",
|
|
54
55
|
"css-list-helpers": "^2.0.0",
|
|
55
|
-
"font-family-papandreou": "^0.2.0-patch2",
|
|
56
56
|
"font-snapper": "^1.2.0",
|
|
57
|
-
"font-tracer": "^3.
|
|
57
|
+
"font-tracer": "^3.6.0",
|
|
58
58
|
"fontkit": "^1.8.0",
|
|
59
59
|
"fontverter": "^2.0.0",
|
|
60
60
|
"gettemporaryfilepath": "^1.0.1",
|