subfont 7.1.1 → 7.2.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 CHANGED
@@ -1,4 +1,14 @@
1
- ### v7.1.1 (2023-05-07)
1
+ ### v7.2.0 (2024-03-24)
2
+
3
+ #### Pull requests
4
+
5
+ - [#172](https://github.com/Munter/subfont/pull/172) Support partial instancing of variable fonts ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
6
+
7
+ #### Commits to master
8
+
9
+ - [Update subset-font to ^2.2.0](https://github.com/Munter/subfont/commit/1cf16cb1769c65e3a5b34d440b619b238a27141b) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
10
+
11
+ ### v7.1.1 (2023-05-08)
2
12
 
3
13
  - [Fix file name generation when the font-family contains backslash Fixes \#171](https://github.com/Munter/subfont/commit/1cff3c4095680569ecf50d017035730eb4bd0cc0) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
4
14
 
@@ -19,7 +29,11 @@
19
29
  - [Tell eslint to ignore the puppeteer-browsers dir](https://github.com/Munter/subfont/commit/99bca776a0bd7fab4c3e9c1084c23ae5f7c4e18b) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
20
30
  - [Drop node.js 14](https://github.com/Munter/subfont/commit/0dcf1ed53fa20f7eb4585e6e3813fa8d97aefae5) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
21
31
  - [Tolerate different moch console call orders](https://github.com/Munter/subfont/commit/046971fa1b9fb4096b108cd777f18c34bb938438) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
22
- - [+10 more](https://github.com/Munter/subfont/compare/v6.12.4...v7.0.0)
32
+ - [+10 more](https://github.com/Munter/subfont/compare/v6.12.5...v7.0.0)
33
+
34
+ ### v6.12.5 (2023-05-08)
35
+
36
+ - [Fix file name generation when the font-family contains backslash Fixes \#171](https://github.com/Munter/subfont/commit/5619db3bbbcffa41871b2bc04d4cafa15d409bde) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
23
37
 
24
38
  ### v6.12.4 (2023-01-06)
25
39
 
package/README.md CHANGED
@@ -107,6 +107,8 @@ Options:
107
107
  [boolean] [default: false]
108
108
  --relative-urls Issue relative urls instead of root-relative ones
109
109
  [boolean] [default: false]
110
+ --instance Experimentally instance variable fonts when the variation
111
+ space isn't fully used [boolean] [default: false]
110
112
  --silent, -s Do not write anything to stdout [boolean] [default: false]
111
113
  --debug, -d Verbose insights into font glyph detection
112
114
  [boolean] [default: false]
@@ -75,7 +75,7 @@ module.exports = function parseCommandLineOptions(argv) {
75
75
  default: false,
76
76
  })
77
77
  .options('font-display', {
78
- describe: 'Injects a font-display value into the @font-face CSS.',
78
+ describe: 'Injects a font-display value into the @font-face CSS',
79
79
  type: 'string',
80
80
  default: 'swap',
81
81
  choices: ['auto', 'block', 'swap', 'fallback', 'optional'],
@@ -94,7 +94,7 @@ module.exports = function parseCommandLineOptions(argv) {
94
94
  })
95
95
  .options('instance', {
96
96
  describe:
97
- 'Experimentally instance variable fonts when every variation axis only has one value (only supports full instancing for now)',
97
+ "Experimentally instance variable fonts when the variation space isn't fully used",
98
98
  type: 'boolean',
99
99
  default: false,
100
100
  })
package/lib/subfont.js CHANGED
@@ -359,8 +359,30 @@ module.exports = async function subfont(
359
359
  fontUsage.smallestOriginalSize !== undefined &&
360
360
  fontUsage.smallestSubsetSize !== undefined
361
361
  ) {
362
- if (fontUsage.variationAxes) {
362
+ if (fontUsage.fullyInstanced) {
363
363
  status += ', fully instanced';
364
+ } else if (fontUsage.numAxesReduced > 0 || fontUsage.numAxesPinned) {
365
+ const instancingInfos = [];
366
+ if (fontUsage.numAxesPinned > 0) {
367
+ instancingInfos.push(
368
+ `${fontUsage.numAxesPinned} ${
369
+ fontUsage.numAxesPinned === 1 ? 'axis' : 'axes'
370
+ } pinned`
371
+ );
372
+ }
373
+ if (fontUsage.numAxesReduced) {
374
+ instancingInfos.push(
375
+ `${fontUsage.numAxesReduced}${
376
+ fontUsage.numAxesPinned > 0
377
+ ? ''
378
+ : fontUsage.numAxesReduced === 1
379
+ ? ' axis'
380
+ : ' axes'
381
+ } reduced`
382
+ );
383
+ }
384
+
385
+ status += `, partially instanced (${instancingInfos.join(', ')})`;
364
386
  }
365
387
  status += `, ${prettyBytes(fontUsage.smallestOriginalSize)} (${
366
388
  fontUsage.smallestOriginalFormat
@@ -383,7 +383,7 @@ function getSubsetPromiseId(fontUsage, format, variationAxes = null) {
383
383
  ].join('\x1d');
384
384
  }
385
385
 
386
- async function getFullyPinnedVariationAxes(
386
+ async function getVariationAxisBounds(
387
387
  assetGraph,
388
388
  fontUrl,
389
389
  seenAxisValuesByFontUrlAndAxisName
@@ -392,13 +392,14 @@ async function getFullyPinnedVariationAxes(
392
392
  assetGraph.findAssets({ url: fontUrl })[0].rawSrc
393
393
  );
394
394
 
395
- let variationAxes;
395
+ const variationAxes = {};
396
+ let fullyInstanced = true;
397
+ let numAxesPinned = 0;
398
+ let numAxesReduced = 0;
396
399
  const fontVariationEntries = Object.entries(fontInfo.variationAxes);
397
400
  const seenAxisValuesByAxisName =
398
401
  seenAxisValuesByFontUrlAndAxisName.get(fontUrl);
399
402
  if (fontVariationEntries.length > 0 && seenAxisValuesByAxisName) {
400
- variationAxes = {};
401
- let everyAxisPinned = true;
402
403
  for (const [
403
404
  axisName,
404
405
  { min, max, default: defaultValue },
@@ -409,16 +410,27 @@ async function getFullyPinnedVariationAxes(
409
410
  }
410
411
  if (seenAxisValues && seenAxisValues.size === 1) {
411
412
  variationAxes[axisName] = _.clamp([...seenAxisValues][0], min, max);
412
- } else {
413
- everyAxisPinned = false;
413
+ numAxesPinned += 1;
414
+ } else if (seenAxisValues) {
415
+ const minSeenValue = Math.min(...seenAxisValues);
416
+ const maxSeenValue = Math.max(...seenAxisValues);
417
+ variationAxes[axisName] = {
418
+ min: Math.min(minSeenValue, min),
419
+ max: Math.min(maxSeenValue, max),
420
+ };
421
+ fullyInstanced = false;
422
+ if (minSeenValue > min || maxSeenValue < max) {
423
+ numAxesReduced += 1;
424
+ }
414
425
  }
415
426
  }
416
- if (!everyAxisPinned) {
417
- // Not all variation axes can be fully pinned, bail out
418
- variationAxes = undefined;
419
- }
420
427
  }
421
- return variationAxes;
428
+ return {
429
+ fullyInstanced,
430
+ numAxesReduced,
431
+ numAxesPinned,
432
+ variationAxes,
433
+ };
422
434
  }
423
435
 
424
436
  async function getSubsetsForFontUsage(
@@ -462,22 +474,25 @@ async function getSubsetsForFontUsage(
462
474
  }, {});
463
475
 
464
476
  const subsetPromiseMap = {};
465
- const notFullyInstancedFontUrls = new Set();
466
477
 
467
478
  for (const item of htmlOrSvgAssetTextsWithProps) {
468
479
  for (const fontUsage of item.fontUsages) {
469
480
  const fontBuffer = originalFontBuffers[fontUsage.fontUrl];
470
481
  const text = fontUsage.text;
471
482
  let variationAxes;
483
+ let fullyInstanced = false;
484
+ let numAxesReduced = 0;
485
+ let numAxesPinned = 0;
472
486
  if (instance) {
473
- variationAxes = await getFullyPinnedVariationAxes(
487
+ const res = await getVariationAxisBounds(
474
488
  assetGraph,
475
489
  fontUsage.fontUrl,
476
490
  seenAxisValuesByFontUrlAndAxisName
477
491
  );
478
- }
479
- if (!variationAxes) {
480
- notFullyInstancedFontUrls.add(fontUsage.fontUrl);
492
+ variationAxes = res.variationAxes;
493
+ fullyInstanced = res.fullyInstanced;
494
+ numAxesReduced = res.numAxesReduced;
495
+ numAxesPinned = res.numAxesPinned;
481
496
  }
482
497
 
483
498
  for (const targetFormat of formats) {
@@ -515,6 +530,9 @@ async function getSubsetsForFontUsage(
515
530
  fontUsage.smallestSubsetSize = size;
516
531
  fontUsage.smallestSubsetFormat = targetFormat;
517
532
  fontUsage.variationAxes = variationAxes;
533
+ fontUsage.fullyInstanced = fullyInstanced;
534
+ fontUsage.numAxesPinned = numAxesPinned;
535
+ fontUsage.numAxesReduced = numAxesReduced;
518
536
  }
519
537
  }
520
538
  });
@@ -523,8 +541,6 @@ async function getSubsetsForFontUsage(
523
541
  }
524
542
 
525
543
  await Promise.all(Object.values(subsetPromiseMap));
526
-
527
- return { notFullyInstancedFontUrls };
528
544
  }
529
545
 
530
546
  const fontOrder = ['woff2', 'woff', 'truetype'];
@@ -949,17 +965,13 @@ function getVariationAxisUsage(htmlOrSvgAssetTextsWithProps) {
949
965
  async function warnAboutUnusedVariationAxes(
950
966
  assetGraph,
951
967
  seenAxisValuesByFontUrlAndAxisName,
952
- outOfBoundsAxesByFontUrl,
953
- notFullyInstancedFontUrls
968
+ outOfBoundsAxesByFontUrl
954
969
  ) {
955
970
  const warnings = [];
956
971
  for (const [
957
972
  fontUrl,
958
973
  seenAxisValuesByAxisName,
959
974
  ] of seenAxisValuesByFontUrlAndAxisName.entries()) {
960
- if (!notFullyInstancedFontUrls.has(fontUrl)) {
961
- continue;
962
- }
963
975
  const outOfBoundsAxes = outOfBoundsAxesByFontUrl.get(fontUrl) || new Set();
964
976
  let fontInfo;
965
977
  try {
@@ -1030,7 +1042,7 @@ async function warnAboutUnusedVariationAxes(
1030
1042
  new Error(`🪓 Unused variation axes detected in your variable fonts.
1031
1043
  The below variable fonts contain custom axes that do not appear to be fully used on any of your pages.
1032
1044
  This bloats your fonts and also the subset fonts that subfont creates.
1033
- Consider removing the unused axis ranges using a tool like Slice <https://slice-gui.netlify.app/>
1045
+ Consider removing the unused axis ranges by specifying the --instance switch
1034
1046
  ${warnings.join('\n')}`)
1035
1047
  );
1036
1048
  }
@@ -1320,7 +1332,7 @@ async function subsetFonts(
1320
1332
  getVariationAxisUsage(htmlOrSvgAssetTextsWithProps);
1321
1333
 
1322
1334
  // Generate subsets:
1323
- const { notFullyInstancedFontUrls } = await getSubsetsForFontUsage(
1335
+ await getSubsetsForFontUsage(
1324
1336
  assetGraph,
1325
1337
  htmlOrSvgAssetTextsWithProps,
1326
1338
  formats,
@@ -1329,12 +1341,13 @@ async function subsetFonts(
1329
1341
  );
1330
1342
 
1331
1343
  await warnAboutMissingGlyphs(htmlOrSvgAssetTextsWithProps, assetGraph);
1332
- await warnAboutUnusedVariationAxes(
1333
- assetGraph,
1334
- seenAxisValuesByFontUrlAndAxisName,
1335
- outOfBoundsAxesByFontUrl,
1336
- notFullyInstancedFontUrls
1337
- );
1344
+ if (!instance) {
1345
+ await warnAboutUnusedVariationAxes(
1346
+ assetGraph,
1347
+ seenAxisValuesByFontUrlAndAxisName,
1348
+ outOfBoundsAxesByFontUrl
1349
+ );
1350
+ }
1338
1351
 
1339
1352
  // Insert subsets:
1340
1353
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "subfont",
3
- "version": "7.1.1",
3
+ "version": "7.2.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"
@@ -66,7 +66,7 @@
66
66
  "pretty-bytes": "^5.1.0",
67
67
  "puppeteer-core": "^19.8.5",
68
68
  "specificity": "^0.4.1",
69
- "subset-font": "^2.1.0",
69
+ "subset-font": "^2.2.0",
70
70
  "urltools": "^0.4.1",
71
71
  "yargs": "^15.4.0"
72
72
  },