subfont 6.1.0 → 6.3.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/CHANGELOG.md CHANGED
@@ -1,3 +1,29 @@
1
+ ### v6.3.1 (2021-10-22)
2
+
3
+ - [Fix tests](https://github.com/Munter/subfont/commit/4f7ab7011220457bab087a7533dbcfd5f8c8020b) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
4
+ - [Update postcss to ^8.3.11](https://github.com/Munter/subfont/commit/2b63273784f89f5c1e2944eec238a1d3ab2a96db) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
5
+ - [Update font-tracer to ^3.0.1](https://github.com/Munter/subfont/commit/1f3ce78a64c995eee5c49f5ace0ff7a6f6a1f22c) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
6
+ - [Drop node.js 16 for the time being because of prebuilt canvas](https://github.com/Munter/subfont/commit/2b45d966c42f7391402dc79df85d2514c71eeee3) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
7
+ - [Replace Travis with Github Actions](https://github.com/Munter/subfont/commit/a3851f0ac60f1205977fc2616728c94bcf6dbab8) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
8
+
9
+ ### v6.3.0 (2021-09-16)
10
+
11
+ - [Update assetgraph to ^7.2.0, fixes \#152](https://github.com/Munter/subfont/commit/485e333202b935260e41f7996bbd96fca50d028a) ([Andreas Lind](mailto:andreas.lind@workday.com))
12
+
13
+ ### v6.2.1 (2021-09-05)
14
+
15
+ - [Add test case where the same font-family is defined in an SVG island and the surrounding HTML](https://github.com/Munter/subfont/commit/ea6709648141efcc24177e0461fc2eb5c72c6714) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
16
+ - [Avoid "inline SVG in ..." in assetFileName in fontInfo for SVG islands](https://github.com/Munter/subfont/commit/8fa6bfeb41a5e9addda4904810e630e81b4f79e9) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
17
+
18
+ ### v6.2.0 (2021-09-05)
19
+
20
+ - [Update to font-tracer 3.0.0](https://github.com/Munter/subfont/commit/5236fecd7a3c9387098fcd3f3b5c1ec5c73093fe) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
21
+ - [Rename htmlAsset vars\/params\/props for clarity](https://github.com/Munter/subfont/commit/0906ef4b70e45337c8008357d242bfdb237b9ca9) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
22
+ - [Handle inline SVGs correctly](https://github.com/Munter/subfont/commit/7920755e75130d89636239b6700ae048dc1c5ef7) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
23
+ - [Support tracing text in inline and external SVGs](https://github.com/Munter/subfont/commit/7852e82048c160a50406df9ee3fecf606d11cba0) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
24
+ - [Remove preload polyfill cruft](https://github.com/Munter/subfont/commit/9bfd5663a4d5bc77a27f68dec9c784835c6e27c9) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
25
+ - [+3 more](https://github.com/Munter/subfont/compare/v6.1.0...v6.2.0)
26
+
1
27
  ### v6.1.0 (2021-05-23)
2
28
 
3
29
  - [Remove the JavaScript-based preload polyfill](https://github.com/Munter/subfont/commit/b58bc351d8002d2aae1f4f9cf82126a3efcb997e) ([Andreas Lind](mailto:andreas.lind@workday.com))
@@ -230,16 +256,13 @@
230
256
  #### Pull requests
231
257
 
232
258
  - [#76](https://github.com/Munter/subfont/pull/76) Fix the prettier setup ([Andreas Lind](mailto:andreas.lind@peakon.com))
259
+ - [#75](https://github.com/Munter/subfont/pull/75) Fix omitFallbacks with Google Web Fonts ([Andreas Lind](mailto:andreas.lind@peakon.com))
233
260
 
234
261
  #### Commits to master
235
262
 
236
263
  - [Switch to the official css-font-parser now that bramstein\/css-font-parser\#7 has been merged and released](https://github.com/Munter/subfont/commit/457c7f0e4cef0a8c1bd8f816c23ace64c9987424) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
237
264
  - [Don't populate source map relations](https://github.com/Munter/subfont/commit/5c07218b6f1dcc6fad88702a3bcb7b33bf9df54e) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
238
265
 
239
- ### v4.1.2 (2020-01-09)
240
-
241
- - [#75](https://github.com/Munter/subfont/pull/75) Fix omitFallbacks with Google Web Fonts ([Andreas Lind](mailto:andreas.lind@peakon.com))
242
-
243
266
  ### v4.1.1 (2020-01-04)
244
267
 
245
268
  - [Add regression test](https://github.com/Munter/subfont/commit/46eddce9c09268dbde459b1f98fe5cec9e4c98f5) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
@@ -270,8 +293,7 @@
270
293
  - [Add vscode debugger launch configuration for the test suite](https://github.com/Munter/subfont/commit/f8f9abc42909c556765555cc49f44eb40a9194db) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
271
294
  - [Guard against an already detached relation when cleaning up](https://github.com/Munter/subfont/commit/6392fc359222772c9033a58a9020e3b35487d019) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
272
295
 
273
- ### v4.0.3 (2019-11-02)
274
-
296
+ ### v4.0.3
275
297
  #### Pull requests
276
298
 
277
299
  - [#67](https://github.com/Munter/subfont/pull/67) Only warn about missing fonttools install if we are actually trying t… ([Peter Müller](mailto:munter@fumle.dk))
@@ -19,6 +19,7 @@ module.exports = function gatherStylesheetsWithPredicates(
19
19
  type: {
20
20
  $in: [
21
21
  'HtmlStyle',
22
+ 'SvgStyle',
22
23
  'CssImport',
23
24
  'HtmlConditionalComment',
24
25
  'HtmlNoscript',
@@ -41,7 +41,7 @@ function getCssRulesByProperty(properties, cssSource, existingPredicates) {
41
41
  existingPredicates = existingPredicates || {};
42
42
 
43
43
  const parseTree = postcss.parse(cssSource);
44
- let defaultNamespaceURI = 'http://www.w3.org/1999/xhtml';
44
+ let defaultNamespaceURI;
45
45
  parseTree.walkAtRules('namespace', (rule) => {
46
46
  const fragments = rule.params.split(/\s+/);
47
47
  if (fragments.length === 1) {
package/lib/subfont.js CHANGED
@@ -212,7 +212,7 @@ module.exports = async function subfont(
212
212
  isInline: false,
213
213
  isLoaded: true,
214
214
  type: {
215
- $in: ['Html', 'Css', 'JavaScript'],
215
+ $in: ['Html', 'Svg', 'Css', 'JavaScript'],
216
216
  },
217
217
  })) {
218
218
  sumSizesBefore += asset.rawSrc.length;
@@ -233,7 +233,7 @@ module.exports = async function subfont(
233
233
  isInline: false,
234
234
  isLoaded: true,
235
235
  type: {
236
- $in: ['Html', 'Css', 'JavaScript'],
236
+ $in: ['Html', 'Svg', 'Css', 'JavaScript'],
237
237
  },
238
238
  })) {
239
239
  sumSizesAfter += asset.rawSrc.length;
@@ -247,23 +247,6 @@ module.exports = async function subfont(
247
247
  relation.omitFunctionCall();
248
248
  }
249
249
 
250
- // Compress inserted javascript
251
- const preloadPolyfillScripts = assetGraph.findRelations({
252
- type: 'HtmlScript',
253
- to: {
254
- isInline: true,
255
- outgoingRelations: (relation) => relation.type === 'JavaScriptStaticUrl',
256
- },
257
- });
258
- await assetGraph.compressJavaScript({
259
- type: 'JavaScript',
260
- isLoaded: true,
261
- outgoingRelations: (relation) => relation.type === 'JavaScriptStaticUrl',
262
- });
263
- for (const relation of preloadPolyfillScripts) {
264
- relation.inline();
265
- }
266
-
267
250
  for (const asset of assetGraph.findAssets({
268
251
  isDirty: true,
269
252
  isInline: false,
@@ -323,7 +306,7 @@ module.exports = async function subfont(
323
306
  }
324
307
 
325
308
  let totalSavings = sumSizesBefore - sumSizesAfter;
326
- for (const { htmlAsset, fontUsages } of fontInfo) {
309
+ for (const { assetFileName, fontUsages } of fontInfo) {
327
310
  let sumSmallestSubsetSize = 0;
328
311
  let sumSmallestOriginalSize = 0;
329
312
  let maxUsedCodePoints = 0;
@@ -346,7 +329,7 @@ module.exports = async function subfont(
346
329
  );
347
330
  const numFonts = Object.keys(fontUsagesByFontFamily).length;
348
331
  log(
349
- `${htmlAsset}: ${numFonts} font${numFonts === 1 ? '' : 's'} (${
332
+ `${assetFileName}: ${numFonts} font${numFonts === 1 ? '' : 's'} (${
350
333
  fontUsages.length
351
334
  } variant${fontUsages.length === 1 ? '' : 's'}) in use, ${prettyBytes(
352
335
  sumSmallestOriginalSize
@@ -387,7 +370,9 @@ module.exports = async function subfont(
387
370
  }
388
371
  }
389
372
  log(
390
- `HTML/JS/CSS size increase: ${prettyBytes(sumSizesAfter - sumSizesBefore)}`
373
+ `HTML/SVG/JS/CSS size increase: ${prettyBytes(
374
+ sumSizesAfter - sumSizesBefore
375
+ )}`
391
376
  );
392
377
  log(`Total savings: ${prettyBytes(totalSavings)}`);
393
378
  if (!dryRun) {
@@ -100,7 +100,7 @@ function getFontFaceDeclarationText(node, relations) {
100
100
 
101
101
  // Takes the output of fontTracer
102
102
  function groupTextsByFontFamilyProps(
103
- htmlAsset,
103
+ htmlOrSvgAsset,
104
104
  globalTextByPropsArray,
105
105
  pageTextByPropsArray,
106
106
  availableFontFaceDeclarations
@@ -138,7 +138,7 @@ function groupTextsByFontFamilyProps(
138
138
  const fontUrl = getPreferredFontUrl(relations);
139
139
 
140
140
  return {
141
- htmlAsset: textAndProps.htmlAsset,
141
+ htmlOrSvgAsset: textAndProps.htmlOrSvgAsset,
142
142
  text: textAndProps.text,
143
143
  props,
144
144
  fontRelations: relations,
@@ -175,7 +175,7 @@ function groupTextsByFontFamilyProps(
175
175
  texts,
176
176
  pageText: uniqueChars(
177
177
  textsPropsArray
178
- .filter((textsProps) => textsProps.htmlAsset === htmlAsset)
178
+ .filter((textsProps) => textsProps.htmlOrSvgAsset === htmlOrSvgAsset)
179
179
  .map((obj) => obj.text)
180
180
  .join('')
181
181
  ),
@@ -188,7 +188,7 @@ function groupTextsByFontFamilyProps(
188
188
  });
189
189
  }
190
190
 
191
- function getParents(assetGraph, asset, assetQuery) {
191
+ function getParents(asset, assetQuery) {
192
192
  const assetMatcher = compileQuery(assetQuery);
193
193
  const seenAssets = new Set();
194
194
  const parents = [];
@@ -211,13 +211,13 @@ function getParents(assetGraph, asset, assetQuery) {
211
211
  }
212
212
 
213
213
  function asyncLoadStyleRelationWithFallback(
214
- htmlAsset,
214
+ htmlOrSvgAsset,
215
215
  originalRelation,
216
216
  hrefType
217
217
  ) {
218
218
  // Async load google font stylesheet
219
219
  // Insert async CSS loading <script>
220
- const asyncCssLoadingRelation = htmlAsset.addRelation(
220
+ const asyncCssLoadingRelation = htmlOrSvgAsset.addRelation(
221
221
  {
222
222
  type: 'HtmlScript',
223
223
  hrefType: 'inline',
@@ -226,9 +226,9 @@ function asyncLoadStyleRelationWithFallback(
226
226
  text: `
227
227
  (function () {
228
228
  var el = document.createElement('link');
229
- el.href = '${htmlAsset.assetGraph.buildHref(
229
+ el.href = '${htmlOrSvgAsset.assetGraph.buildHref(
230
230
  originalRelation.to.url,
231
- htmlAsset.url,
231
+ htmlOrSvgAsset.url,
232
232
  { hrefType }
233
233
  )}'.toString('url');
234
234
  el.rel = 'stylesheet';
@@ -246,7 +246,7 @@ function asyncLoadStyleRelationWithFallback(
246
246
  );
247
247
 
248
248
  // Insert <noscript> fallback sync CSS loading
249
- const noScriptFallbackRelation = htmlAsset.addRelation(
249
+ const noScriptFallbackRelation = htmlOrSvgAsset.addRelation(
250
250
  {
251
251
  type: 'HtmlNoscript',
252
252
  to: {
@@ -269,7 +269,7 @@ function asyncLoadStyleRelationWithFallback(
269
269
 
270
270
  noScriptFallbackRelation.inline();
271
271
  asyncCssLoadingRelation.to.minify();
272
- htmlAsset.markDirty();
272
+ htmlOrSvgAsset.markDirty();
273
273
  }
274
274
 
275
275
  function getSubsetPromiseId(fontUsage, format) {
@@ -278,12 +278,12 @@ function getSubsetPromiseId(fontUsage, format) {
278
278
 
279
279
  async function getSubsetsForFontUsage(
280
280
  assetGraph,
281
- htmlAssetTextsWithProps,
281
+ htmlOrSvgAssetTextsWithProps,
282
282
  formats
283
283
  ) {
284
284
  const allFonts = [];
285
285
 
286
- for (const item of htmlAssetTextsWithProps) {
286
+ for (const item of htmlOrSvgAssetTextsWithProps) {
287
287
  for (const fontUsage of item.fontUsages) {
288
288
  if (!fontUsage.fontUrl) {
289
289
  continue;
@@ -316,7 +316,7 @@ async function getSubsetsForFontUsage(
316
316
 
317
317
  const subsetPromiseMap = {};
318
318
 
319
- for (const item of htmlAssetTextsWithProps) {
319
+ for (const item of htmlOrSvgAssetTextsWithProps) {
320
320
  for (const fontUsage of item.fontUsages) {
321
321
  const fontBuffer = originalFontBuffers[fontUsage.fontUrl];
322
322
  const text = fontUsage.text;
@@ -552,7 +552,7 @@ async function subsetFonts(
552
552
  fontDisplay = undefined;
553
553
  }
554
554
 
555
- const htmlAssetTextsWithProps = [];
555
+ const htmlOrSvgAssetTextsWithProps = [];
556
556
  const subsetUrl = urltools.ensureTrailingSlash(assetGraph.root + subsetPath);
557
557
 
558
558
  await assetGraph.applySourceMaps({ type: 'Css' });
@@ -578,11 +578,21 @@ async function subsetFonts(
578
578
  // Collect texts by page
579
579
 
580
580
  const memoizedGetCssRulesByProperty = memoizeSync(getCssRulesByProperty);
581
- const htmlAssets = assetGraph.findAssets({ type: 'Html', isInline: false });
581
+ const htmlOrSvgAssets = assetGraph.findAssets({
582
+ $or: [
583
+ {
584
+ type: 'Html',
585
+ isInline: false,
586
+ },
587
+ {
588
+ type: 'Svg',
589
+ },
590
+ ],
591
+ });
582
592
  const traversalRelationQuery = {
583
593
  $or: [
584
594
  {
585
- type: { $in: ['HtmlStyle', 'CssImport'] },
595
+ type: { $in: ['HtmlStyle', 'SvgStyle', 'CssImport'] },
586
596
  },
587
597
  {
588
598
  to: {
@@ -597,20 +607,20 @@ async function subsetFonts(
597
607
  // Minifying them along the way currently doesn't work because some of the
598
608
  // manipulation is sensitive to the exact text contents. We should fix that.
599
609
  const subsetFontsToBeMinified = new Set();
600
- const fontFaceDeclarationsByHtmlAsset = new Map();
610
+ const fontFaceDeclarationsByHtmlOrSvgAsset = new Map();
601
611
  const potentiallyOrphanedAssets = new Set();
602
612
 
603
613
  const headlessBrowser = dynamic && new HeadlessBrowser({ console });
604
614
  const globalTextByProps = [];
605
615
  try {
606
- for (const htmlAsset of htmlAssets) {
616
+ for (const htmlOrSvgAsset of htmlOrSvgAssets) {
607
617
  const accumulatedFontFaceDeclarations = [];
608
- fontFaceDeclarationsByHtmlAsset.set(
609
- htmlAsset,
618
+ fontFaceDeclarationsByHtmlOrSvgAsset.set(
619
+ htmlOrSvgAsset,
610
620
  accumulatedFontFaceDeclarations
611
621
  );
612
622
  assetGraph.eachAssetPreOrder(
613
- htmlAsset,
623
+ htmlOrSvgAsset,
614
624
  traversalRelationQuery,
615
625
  (asset) => {
616
626
  if (asset.type === 'Css' && asset.isLoaded) {
@@ -666,23 +676,25 @@ async function subsetFonts(
666
676
  seenFontFaceCombos.add(key);
667
677
  }
668
678
 
669
- const textByProps = fontTracer(htmlAsset.parseTree, {
679
+ const textByProps = fontTracer(htmlOrSvgAsset.parseTree, {
670
680
  stylesheetsWithPredicates: gatherStylesheetsWithPredicates(
671
- htmlAsset.assetGraph,
672
- htmlAsset
681
+ htmlOrSvgAsset.assetGraph,
682
+ htmlOrSvgAsset
673
683
  ),
674
684
  getCssRulesByProperty: memoizedGetCssRulesByProperty,
675
- htmlAsset,
685
+ asset: htmlOrSvgAsset,
676
686
  });
677
687
  if (headlessBrowser) {
678
- textByProps.push(...(await headlessBrowser.tracePage(htmlAsset)));
688
+ textByProps.push(
689
+ ...(await headlessBrowser.tracePage(htmlOrSvgAsset))
690
+ );
679
691
  }
680
692
  for (const textByPropsEntry of textByProps) {
681
- textByPropsEntry.htmlAsset = htmlAsset;
693
+ textByPropsEntry.htmlOrSvgAsset = htmlOrSvgAsset;
682
694
  }
683
695
  globalTextByProps.push(...textByProps);
684
- htmlAssetTextsWithProps.push({
685
- htmlAsset,
696
+ htmlOrSvgAssetTextsWithProps.push({
697
+ htmlOrSvgAsset,
686
698
  textByProps,
687
699
  accumulatedFontFaceDeclarations,
688
700
  });
@@ -694,11 +706,11 @@ async function subsetFonts(
694
706
  }
695
707
  }
696
708
 
697
- for (const htmlAssetTextsWithPropsEntry of htmlAssetTextsWithProps) {
698
- const { htmlAsset, textByProps, accumulatedFontFaceDeclarations } =
699
- htmlAssetTextsWithPropsEntry;
700
- htmlAssetTextsWithPropsEntry.fontUsages = groupTextsByFontFamilyProps(
701
- htmlAsset,
709
+ for (const htmlOrSvgAssetTextsWithPropsEntry of htmlOrSvgAssetTextsWithProps) {
710
+ const { htmlOrSvgAsset, textByProps, accumulatedFontFaceDeclarations } =
711
+ htmlOrSvgAssetTextsWithPropsEntry;
712
+ htmlOrSvgAssetTextsWithPropsEntry.fontUsages = groupTextsByFontFamilyProps(
713
+ htmlOrSvgAsset,
702
714
  globalTextByProps,
703
715
  textByProps,
704
716
  accumulatedFontFaceDeclarations
@@ -706,9 +718,9 @@ async function subsetFonts(
706
718
  }
707
719
 
708
720
  if (omitFallbacks) {
709
- for (const htmlAsset of htmlAssets) {
721
+ for (const htmlOrSvgAsset of htmlOrSvgAssets) {
710
722
  const accumulatedFontFaceDeclarations =
711
- fontFaceDeclarationsByHtmlAsset.get(htmlAsset);
723
+ fontFaceDeclarationsByHtmlOrSvgAsset.get(htmlOrSvgAsset);
712
724
  // Remove the original @font-face rules:
713
725
  for (const { relations } of accumulatedFontFaceDeclarations) {
714
726
  for (const relation of relations) {
@@ -719,21 +731,21 @@ async function subsetFonts(
719
731
  relation.remove();
720
732
  }
721
733
  }
722
- htmlAsset.markDirty();
734
+ htmlOrSvgAsset.markDirty();
723
735
  }
724
736
  }
725
737
 
726
738
  if (fontDisplay) {
727
- for (const htmlAssetTextWithProps of htmlAssetTextsWithProps) {
728
- for (const fontUsage of htmlAssetTextWithProps.fontUsages) {
739
+ for (const htmlOrSvgAssetTextWithProps of htmlOrSvgAssetTextsWithProps) {
740
+ for (const fontUsage of htmlOrSvgAssetTextWithProps.fontUsages) {
729
741
  fontUsage.props['font-display'] = fontDisplay;
730
742
  }
731
743
  }
732
744
  }
733
745
 
734
746
  // Generate codepoint sets for original font, the used subset and the unused subset
735
- for (const htmlAssetTextWithProps of htmlAssetTextsWithProps) {
736
- for (const fontUsage of htmlAssetTextWithProps.fontUsages) {
747
+ for (const htmlOrSvgAssetTextWithProps of htmlOrSvgAssetTextsWithProps) {
748
+ for (const fontUsage of htmlOrSvgAssetTextWithProps.fontUsages) {
737
749
  const originalFont = assetGraph.findAssets({
738
750
  url: fontUsage.fontUrl,
739
751
  })[0];
@@ -762,24 +774,30 @@ async function subsetFonts(
762
774
 
763
775
  if (onlyInfo) {
764
776
  return {
765
- fontInfo: htmlAssetTextsWithProps.map(({ fontUsages, htmlAsset }) => ({
766
- htmlAsset: htmlAsset.urlOrDescription,
767
- fontUsages: fontUsages,
768
- })),
777
+ fontInfo: htmlOrSvgAssetTextsWithProps.map(
778
+ ({ fontUsages, htmlOrSvgAsset }) => ({
779
+ assetFileName: htmlOrSvgAsset.nonInlineAncestor.urlOrDescription,
780
+ fontUsages: fontUsages,
781
+ })
782
+ ),
769
783
  };
770
784
  }
771
785
 
772
786
  // Generate subsets:
773
- await getSubsetsForFontUsage(assetGraph, htmlAssetTextsWithProps, formats);
787
+ await getSubsetsForFontUsage(
788
+ assetGraph,
789
+ htmlOrSvgAssetTextsWithProps,
790
+ formats
791
+ );
774
792
 
775
793
  // Warn about missing glyphs
776
794
  const missingGlyphsErrors = [];
777
795
 
778
796
  for (const {
779
- htmlAsset,
797
+ htmlOrSvgAsset,
780
798
  fontUsages,
781
799
  accumulatedFontFaceDeclarations,
782
- } of htmlAssetTextsWithProps) {
800
+ } of htmlOrSvgAssetTextsWithProps) {
783
801
  for (const fontUsage of fontUsages) {
784
802
  if (fontUsage.subsets) {
785
803
  const characterSet = fontkit.create(
@@ -799,23 +817,23 @@ async function subsetFonts(
799
817
 
800
818
  if (isMissing) {
801
819
  let location;
802
- const charIdx = htmlAsset.text.indexOf(char);
820
+ const charIdx = htmlOrSvgAsset.text.indexOf(char);
803
821
 
804
822
  if (charIdx === -1) {
805
- location = `${htmlAsset.urlOrDescription} (generated content)`;
823
+ location = `${htmlOrSvgAsset.urlOrDescription} (generated content)`;
806
824
  } else {
807
825
  const position = new LinesAndColumns(
808
- htmlAsset.text
826
+ htmlOrSvgAsset.text
809
827
  ).locationForIndex(charIdx);
810
- location = `${htmlAsset.urlOrDescription}:${position.line + 1}:${
811
- position.column + 1
812
- }`;
828
+ location = `${htmlOrSvgAsset.urlOrDescription}:${
829
+ position.line + 1
830
+ }:${position.column + 1}`;
813
831
  }
814
832
 
815
833
  missingGlyphsErrors.push({
816
834
  codePoint,
817
835
  char,
818
- htmlAsset,
836
+ htmlOrSvgAsset,
819
837
  fontUsage,
820
838
  location,
821
839
  });
@@ -865,13 +883,13 @@ These glyphs are used on your site, but they don't exist in the font you applied
865
883
 
866
884
  let numFontUsagesWithSubset = 0;
867
885
  for (const {
868
- htmlAsset,
886
+ htmlOrSvgAsset,
869
887
  fontUsages,
870
888
  accumulatedFontFaceDeclarations,
871
- } of htmlAssetTextsWithProps) {
889
+ } of htmlOrSvgAssetTextsWithProps) {
872
890
  const insertionPoint = assetGraph.findRelations({
873
- type: 'HtmlStyle',
874
- from: htmlAsset,
891
+ type: `${htmlOrSvgAsset.type}Style`,
892
+ from: htmlOrSvgAsset,
875
893
  })[0];
876
894
  const subsetFontUsages = fontUsages.filter(
877
895
  (fontUsage) => fontUsage.subsets
@@ -884,7 +902,7 @@ These glyphs are used on your site, but they don't exist in the font you applied
884
902
  for (const fontUsage of fontUsages) {
885
903
  for (const relation of assetGraph.findRelations({
886
904
  type: { $in: ['HtmlPrefetchLink', 'HtmlPreloadLink'] },
887
- from: htmlAsset,
905
+ from: htmlOrSvgAsset,
888
906
  to: {
889
907
  url: fontUsage.fontUrl,
890
908
  },
@@ -911,7 +929,7 @@ These glyphs are used on your site, but they don't exist in the font you applied
911
929
  // Insert <link rel="preload">
912
930
  unsubsettedFontUsagesToPreload.map((fontUsage) => {
913
931
  // Always preload unsubsetted font files, they might be any format, so can't be clever here
914
- return htmlAsset.addRelation(
932
+ return htmlOrSvgAsset.addRelation(
915
933
  {
916
934
  type: 'HtmlPreloadLink',
917
935
  hrefType,
@@ -959,8 +977,8 @@ These glyphs are used on your site, but they don't exist in the font you applied
959
977
  if (
960
978
  formats.length === 1 &&
961
979
  fontUsage &&
962
- (!inlineCss || htmlAssetTextsWithProps.length === 1) &&
963
- htmlAssetTextsWithProps.every(({ fontUsages }) =>
980
+ (!inlineCss || htmlOrSvgAssetTextsWithProps.length === 1) &&
981
+ htmlOrSvgAssetTextsWithProps.every(({ fontUsages }) =>
964
982
  fontUsages.some(
965
983
  ({ fontUrl, pageText }) => pageText && fontUrl === fontUsage.fontUrl
966
984
  )
@@ -1051,22 +1069,25 @@ These glyphs are used on your site, but they don't exist in the font you applied
1051
1069
  // - https://caniuse.com/#search=woff2
1052
1070
  // - https://caniuse.com/#search=preload
1053
1071
 
1054
- htmlAsset.addRelation(
1055
- {
1056
- type: 'HtmlPreloadLink',
1057
- hrefType,
1058
- to: fontAsset,
1059
- as: 'font',
1060
- },
1061
- 'before',
1062
- insertionPoint
1063
- );
1072
+ if (htmlOrSvgAsset.type === 'Html') {
1073
+ htmlOrSvgAsset.addRelation(
1074
+ {
1075
+ type: 'HtmlPreloadLink',
1076
+ hrefType,
1077
+ to: fontAsset,
1078
+ as: 'font',
1079
+ },
1080
+ 'before',
1081
+ insertionPoint
1082
+ );
1083
+ }
1064
1084
  }
1065
1085
  }
1066
- const cssRelation = htmlAsset.addRelation(
1086
+ const cssRelation = htmlOrSvgAsset.addRelation(
1067
1087
  {
1068
- type: 'HtmlStyle',
1069
- hrefType: inlineCss ? 'inline' : hrefType,
1088
+ type: `${htmlOrSvgAsset.type}Style`,
1089
+ hrefType:
1090
+ inlineCss || htmlOrSvgAsset.type === 'Svg' ? 'inline' : hrefType,
1070
1091
  to: cssAsset,
1071
1092
  },
1072
1093
  'before',
@@ -1075,7 +1096,7 @@ These glyphs are used on your site, but they don't exist in the font you applied
1075
1096
 
1076
1097
  if (!omitFallbacks && inlineCss && unusedVariantsCss) {
1077
1098
  // The fallback CSS for unused variants needs to go into its own stylesheet after the crude version of the JS-based preload "polyfill"
1078
- const cssAsset = htmlAsset.addRelation(
1099
+ const cssAsset = htmlOrSvgAsset.addRelation(
1079
1100
  {
1080
1101
  type: 'HtmlStyle',
1081
1102
  to: {
@@ -1100,9 +1121,9 @@ These glyphs are used on your site, but they don't exist in the font you applied
1100
1121
 
1101
1122
  // Lazy load the original @font-face declarations of self-hosted fonts (unless omitFallbacks)
1102
1123
  const originalRelations = new Set();
1103
- for (const htmlAsset of htmlAssets) {
1124
+ for (const htmlOrSvgAsset of htmlOrSvgAssets) {
1104
1125
  const accumulatedFontFaceDeclarations =
1105
- fontFaceDeclarationsByHtmlAsset.get(htmlAsset);
1126
+ fontFaceDeclarationsByHtmlOrSvgAsset.get(htmlOrSvgAsset);
1106
1127
  // TODO: Maybe group by media?
1107
1128
  const containedRelationsByFontFaceRule = new Map();
1108
1129
  for (const { relations } of accumulatedFontFaceDeclarations) {
@@ -1151,18 +1172,20 @@ These glyphs are used on your site, but they don't exist in the font you applied
1151
1172
  cssAsset.url = cssAssetUrl;
1152
1173
  }
1153
1174
 
1154
- // Create a <link rel="stylesheet"> that asyncLoadStyleRelationWithFallback can convert to async with noscript fallback:
1155
- const fallbackHtmlStyle = htmlAsset.addRelation({
1156
- type: 'HtmlStyle',
1157
- to: cssAsset,
1158
- });
1175
+ if (htmlOrSvgAsset.type === 'Html') {
1176
+ // Create a <link rel="stylesheet"> that asyncLoadStyleRelationWithFallback can convert to async with noscript fallback:
1177
+ const fallbackHtmlStyle = htmlOrSvgAsset.addRelation({
1178
+ type: 'HtmlStyle',
1179
+ to: cssAsset,
1180
+ });
1159
1181
 
1160
- asyncLoadStyleRelationWithFallback(
1161
- htmlAsset,
1162
- fallbackHtmlStyle,
1163
- hrefType
1164
- );
1165
- relationsToRemove.add(fallbackHtmlStyle);
1182
+ asyncLoadStyleRelationWithFallback(
1183
+ htmlOrSvgAsset,
1184
+ fallbackHtmlStyle,
1185
+ hrefType
1186
+ );
1187
+ relationsToRemove.add(fallbackHtmlStyle);
1188
+ }
1166
1189
  }
1167
1190
  }
1168
1191
 
@@ -1199,12 +1222,14 @@ These glyphs are used on your site, but they don't exist in the font you applied
1199
1222
 
1200
1223
  if (googleFontStylesheetRelation.type === 'CssImport') {
1201
1224
  // Gather Html parents. Relevant if we are dealing with CSS @import relations
1202
- htmlParents = getParents(assetGraph, googleFontStylesheetRelation.to, {
1203
- type: 'Html',
1225
+ htmlParents = getParents(googleFontStylesheetRelation.to, {
1226
+ type: { $in: ['Html', 'Svg'] },
1204
1227
  isInline: false,
1205
1228
  isLoaded: true,
1206
1229
  });
1207
- } else if (googleFontStylesheetRelation.from.type === 'Html') {
1230
+ } else if (
1231
+ ['Html', 'Svg'].includes(googleFontStylesheetRelation.from.type)
1232
+ ) {
1208
1233
  htmlParents = [googleFontStylesheetRelation.from];
1209
1234
  } else {
1210
1235
  htmlParents = [];
@@ -1235,18 +1260,20 @@ These glyphs are used on your site, but they don't exist in the font you applied
1235
1260
  }
1236
1261
  const selfHostedFallbackRelation = htmlParent.addRelation(
1237
1262
  {
1238
- type: 'HtmlStyle',
1263
+ type: `${htmlParent.type}Style`,
1239
1264
  to: selfHostedGoogleFontsCssAsset,
1240
1265
  hrefType,
1241
1266
  },
1242
1267
  'lastInBody'
1243
1268
  );
1244
1269
  relationsToRemove.add(selfHostedFallbackRelation);
1245
- asyncLoadStyleRelationWithFallback(
1246
- htmlParent,
1247
- selfHostedFallbackRelation,
1248
- hrefType
1249
- );
1270
+ if (htmlParent.type === 'Html') {
1271
+ asyncLoadStyleRelationWithFallback(
1272
+ htmlParent,
1273
+ selfHostedFallbackRelation,
1274
+ hrefType
1275
+ );
1276
+ }
1250
1277
  }
1251
1278
  relationsToRemove.add(googleFontStylesheetRelation);
1252
1279
  }
@@ -1263,7 +1290,7 @@ These glyphs are used on your site, but they don't exist in the font you applied
1263
1290
 
1264
1291
  const webfontNameMap = {};
1265
1292
 
1266
- for (const { fontUsages } of htmlAssetTextsWithProps) {
1293
+ for (const { fontUsages } of htmlOrSvgAssetTextsWithProps) {
1267
1294
  for (const { subsets, fontFamilies, props } of fontUsages) {
1268
1295
  if (subsets) {
1269
1296
  for (const fontFamily of fontFamilies) {
@@ -1276,7 +1303,37 @@ These glyphs are used on your site, but they don't exist in the font you applied
1276
1303
  }
1277
1304
 
1278
1305
  let customPropertyDefinitions; // Avoid computing this unless necessary
1279
- // Inject subset font name before original webfont
1306
+ // Inject subset font name before original webfont in SVG font-family attributes
1307
+ const svgAssets = assetGraph.findAssets({ type: 'Svg' });
1308
+ for (const svgAsset of svgAssets) {
1309
+ let changesMade = false;
1310
+ for (const element of Array.from(
1311
+ svgAsset.parseTree.querySelectorAll('[font-family]')
1312
+ )) {
1313
+ const fontFamilies = cssListHelpers.splitByCommas(
1314
+ element.getAttribute('font-family')
1315
+ );
1316
+ for (let i = 0; i < fontFamilies.length; i += 1) {
1317
+ const subsetFontFamily =
1318
+ webfontNameMap[fontFamily.parse(fontFamilies[i])[0].toLowerCase()];
1319
+ if (subsetFontFamily && !fontFamilies.includes(subsetFontFamily)) {
1320
+ fontFamilies.splice(
1321
+ i,
1322
+ omitFallbacks ? 1 : 0,
1323
+ cssQuoteIfNecessary(subsetFontFamily)
1324
+ );
1325
+ i += 1;
1326
+ element.setAttribute('font-family', fontFamilies.join(', '));
1327
+ changesMade = true;
1328
+ }
1329
+ }
1330
+ }
1331
+ if (changesMade) {
1332
+ svgAsset.markDirty();
1333
+ }
1334
+ }
1335
+
1336
+ // Inject subset font name before original webfont in CSS
1280
1337
  const cssAssets = assetGraph.findAssets({
1281
1338
  type: 'Css',
1282
1339
  isLoaded: true,
@@ -1408,10 +1465,12 @@ These glyphs are used on your site, but they don't exist in the font you applied
1408
1465
 
1409
1466
  // Hand out some useful info about the detected subsets:
1410
1467
  return {
1411
- fontInfo: htmlAssetTextsWithProps.map(({ fontUsages, htmlAsset }) => ({
1412
- htmlAsset: htmlAsset.urlOrDescription,
1413
- fontUsages: fontUsages.map((fontUsage) => _.omit(fontUsage, 'subsets')),
1414
- })),
1468
+ fontInfo: htmlOrSvgAssetTextsWithProps.map(
1469
+ ({ fontUsages, htmlOrSvgAsset }) => ({
1470
+ assetFileName: htmlOrSvgAsset.nonInlineAncestor.urlOrDescription,
1471
+ fontUsages: fontUsages.map((fontUsage) => _.omit(fontUsage, 'subsets')),
1472
+ })
1473
+ ),
1415
1474
  };
1416
1475
  }
1417
1476
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "subfont",
3
- "version": "6.1.0",
3
+ "version": "6.3.1",
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,21 +47,21 @@
47
47
  "homepage": "https://github.com/Munter/subfont#readme",
48
48
  "dependencies": {
49
49
  "@gustavnikolaj/async-main-wrap": "^3.0.1",
50
- "assetgraph": "^6.5.0",
50
+ "assetgraph": "^7.2.0",
51
51
  "browserslist": "^4.13.0",
52
52
  "css-font-parser": "^0.3.0",
53
53
  "css-font-weight-names": "^0.2.1",
54
54
  "css-list-helpers": "^2.0.0",
55
55
  "font-family-papandreou": "^0.2.0-patch2",
56
56
  "font-snapper": "^1.2.0",
57
- "font-tracer": "^2.0.1",
57
+ "font-tracer": "^3.0.1",
58
58
  "fontkit": "^1.8.0",
59
59
  "fontverter": "^2.0.0",
60
60
  "gettemporaryfilepath": "^1.0.1",
61
61
  "lines-and-columns": "^1.1.6",
62
62
  "lodash": "^4.17.15",
63
63
  "memoizesync": "^1.1.1",
64
- "postcss": "^7.0.32",
64
+ "postcss": "^8.3.11",
65
65
  "postcss-value-parser": "^4.0.2",
66
66
  "pretty-bytes": "^5.1.0",
67
67
  "puppeteer-core": "^8.0.0",