subfont 6.12.4 → 7.0.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,3 +1,22 @@
1
+ ### v7.0.0 (2023-04-08)
2
+
3
+ #### Pull requests
4
+
5
+ - [#169](https://github.com/Munter/subfont/pull/169) Support full instancing of variable fonts ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
6
+
7
+ #### Commits to master
8
+
9
+ - [Also tell prettier to ignore the puppeteer-browsers dir](https://github.com/Munter/subfont/commit/0e55e8838902d4c4730176313359abbda1c8ebd6) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
10
+ - [Revert "Drop node.js 14"](https://github.com/Munter/subfont/commit/5e54905f05bc398b4aebdbefeb766c42664866b3) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
11
+ - [Tell eslint to ignore the puppeteer-browsers dir](https://github.com/Munter/subfont/commit/99bca776a0bd7fab4c3e9c1084c23ae5f7c4e18b) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
12
+ - [Drop node.js 14](https://github.com/Munter/subfont/commit/0dcf1ed53fa20f7eb4585e6e3813fa8d97aefae5) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
13
+ - [Tolerate different moch console call orders](https://github.com/Munter/subfont/commit/046971fa1b9fb4096b108cd777f18c34bb938438) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
14
+ - [+10 more](https://github.com/Munter/subfont/compare/v6.12.4...v7.0.0)
15
+
16
+ ### v6.12.4 (2023-01-06)
17
+
18
+ - [Adapt to a backwards incompatible change in @hookun\/parse-animation-shorthand 0.1.5](https://github.com/Munter/subfont/commit/0d024aeaca1ac4ebb52ecacf9e20151d3102b1df) ([Andreas Lind](mailto:andreas.lind@workday.com))
19
+
1
20
  ### v6.12.3 (2023-01-06)
2
21
 
3
22
  - [Update @hookun\/parse-animation-shorthand to ^0.1.5, fixes \#168](https://github.com/Munter/subfont/commit/ec19b28392e02c2a4cc42e0124cca5fce4c2ba32) ([Andreas Lind](mailto:andreas.lind@workday.com))
@@ -54,9 +73,13 @@
54
73
  - [Update subset-font to ^1.5.0](https://github.com/Munter/subfont/commit/ba79ef6db81cedfd0e52672b530ca3afddd68a94) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
55
74
  - [Fix warning about missing glyphs for BMP chars](https://github.com/Munter/subfont/commit/5ba0168f35bfef33f9bb9cc8a6d64de8fa1d5585) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
56
75
  - [Fix CHANGELOG generation in preversion script](https://github.com/Munter/subfont/commit/3ea696f8c336c6072411c9817c0c2f5b8d8d61b9) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
76
+
77
+ ### v6.6.1 (2022-07-09)
78
+
79
+ - [ugrvw](https://github.com/Munter/subfont/commit/5ccb873025f9790faf65641551df1a7e65fbfdbf) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
57
80
  - [Fix CHANGELOG https:\/\/github.com\/Munter\/subfont\/commit\/5365689a5a925304a158fddef2b6af702857371c\#r78084394](https://github.com/Munter/subfont/commit/d42c7a2cffd33662d42d4532c45cb8b90080f128) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
58
81
  - [Expect browserslist to only prescribe woff I guess the browser features + usage statistics finally changed so woff isn't needed](https://github.com/Munter/subfont/commit/b70db9b769955cabbda2f2a76f2e7758f9968ec7) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
59
- - [+1 more](https://github.com/Munter/subfont/compare/v6.6.0...v6.7.0)
82
+ - [Tests: Tolerate u+ in unicode-range \(I guess an in-range dep changed\)](https://github.com/Munter/subfont/commit/92a7871457246b64a997c0bffd9bb2766655d811) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
60
83
 
61
84
  ### v6.6.0 (2022-07-09)
62
85
 
@@ -343,16 +366,13 @@
343
366
  #### Pull requests
344
367
 
345
368
  - [#76](https://github.com/Munter/subfont/pull/76) Fix the prettier setup ([Andreas Lind](mailto:andreas.lind@peakon.com))
369
+ - [#75](https://github.com/Munter/subfont/pull/75) Fix omitFallbacks with Google Web Fonts ([Andreas Lind](mailto:andreas.lind@peakon.com))
346
370
 
347
371
  #### Commits to master
348
372
 
349
373
  - [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))
350
374
  - [Don't populate source map relations](https://github.com/Munter/subfont/commit/5c07218b6f1dcc6fad88702a3bcb7b33bf9df54e) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
351
375
 
352
- ### v4.1.2 (2020-01-09)
353
-
354
- - [#75](https://github.com/Munter/subfont/pull/75) Fix omitFallbacks with Google Web Fonts ([Andreas Lind](mailto:andreas.lind@peakon.com))
355
-
356
376
  ### v4.1.1 (2020-01-04)
357
377
 
358
378
  - [Add regression test](https://github.com/Munter/subfont/commit/46eddce9c09268dbde459b1f98fe5cec9e4c98f5) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
@@ -383,8 +403,7 @@
383
403
  - [Add vscode debugger launch configuration for the test suite](https://github.com/Munter/subfont/commit/f8f9abc42909c556765555cc49f44eb40a9194db) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
384
404
  - [Guard against an already detached relation when cleaning up](https://github.com/Munter/subfont/commit/6392fc359222772c9033a58a9020e3b35487d019) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
385
405
 
386
- ### v4.0.3 (2019-11-02)
387
-
406
+ ### v4.0.3
388
407
  #### Pull requests
389
408
 
390
409
  - [#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))
package/README.md CHANGED
@@ -3,7 +3,6 @@
3
3
  [![NPM version](https://badge.fury.io/js/subfont.svg)](http://badge.fury.io/js/subfont)
4
4
  [![Build Status](https://travis-ci.org/Munter/subfont.svg?branch=master)](https://travis-ci.org/Munter/subfont)
5
5
  [![Coverage Status](https://img.shields.io/coveralls/Munter/subfont.svg)](https://coveralls.io/r/Munter/subfont?branch=master)
6
- [![Dependency Status](https://david-dm.org/Munter/subfont.svg)](https://david-dm.org/Munter/subfont) [![Greenkeeper badge](https://badges.greenkeeper.io/Munter/subfont.svg)](https://greenkeeper.io/)
7
6
 
8
7
  A command line tool to statically analyse your page in order to generate the most optimal web font subsets, then inject them into your page.
9
8
 
@@ -25,7 +24,7 @@ Subfont will:
25
24
  Currently supported font services:
26
25
 
27
26
  - Google fonts
28
- - Local fonts (with [fonttools](https://github.com/fonttools/fonttools))
27
+ - Local fonts
29
28
 
30
29
  **If you know of font services with liberal font usage licenses, open an issue and we'll add support for them**
31
30
 
@@ -1,5 +1,6 @@
1
1
  const urlTools = require('urltools');
2
2
  const puppeteer = require('puppeteer-core');
3
+ const pathModule = require('path');
3
4
 
4
5
  async function transferResults(jsHandle) {
5
6
  const results = await jsHandle.jsonValue();
@@ -12,8 +13,10 @@ async function transferResults(jsHandle) {
12
13
  }
13
14
 
14
15
  async function downloadOrLocatePreferredBrowserRevision() {
15
- const browserFetcher = puppeteer.createBrowserFetcher();
16
- const preferredRevision = puppeteer._launcher._preferredRevision;
16
+ const browserFetcher = new puppeteer.BrowserFetcher({
17
+ path: pathModule.resolve(__dirname, '..', 'puppeteer-browsers'),
18
+ });
19
+ const preferredRevision = puppeteer.default.defaultBrowserRevision;
17
20
  const localRevisions = await browserFetcher.localRevisions();
18
21
  let revisionInfo;
19
22
  if (localRevisions.includes(preferredRevision)) {
@@ -92,6 +92,12 @@ module.exports = function parseCommandLineOptions(argv) {
92
92
  type: 'boolean',
93
93
  default: false,
94
94
  })
95
+ .options('instance', {
96
+ describe:
97
+ 'Experimentally instance variable fonts when every variation axis only has one value (only supports full instancing for now)',
98
+ type: 'boolean',
99
+ default: false,
100
+ })
95
101
  .options('silent', {
96
102
  alias: 's',
97
103
  describe: `Do not write anything to stdout`,
package/lib/subfont.js CHANGED
@@ -23,6 +23,7 @@ module.exports = async function subfont(
23
23
  relativeUrls = false,
24
24
  fallbacks = true,
25
25
  dynamic = false,
26
+ instance = false,
26
27
  browsers,
27
28
  text,
28
29
  },
@@ -227,6 +228,7 @@ module.exports = async function subfont(
227
228
  hrefType: relativeUrls ? 'relative' : 'rootRelative',
228
229
  text,
229
230
  dynamic,
231
+ instance,
230
232
  console,
231
233
  });
232
234
 
@@ -357,6 +359,9 @@ module.exports = async function subfont(
357
359
  fontUsage.smallestOriginalSize !== undefined &&
358
360
  fontUsage.smallestSubsetSize !== undefined
359
361
  ) {
362
+ if (fontUsage.variationAxes) {
363
+ status += ', fully instanced';
364
+ }
360
365
  status += `, ${prettyBytes(fontUsage.smallestOriginalSize)} (${
361
366
  fontUsage.smallestOriginalFormat
362
367
  }) => ${prettyBytes(fontUsage.smallestSubsetSize)} (${
@@ -374,14 +374,69 @@ function asyncLoadStyleRelationWithFallback(
374
374
  htmlOrSvgAsset.markDirty();
375
375
  }
376
376
 
377
- function getSubsetPromiseId(fontUsage, format) {
378
- return [fontUsage.text, fontUsage.fontUrl, format].join('\x1d');
377
+ function getSubsetPromiseId(fontUsage, format, variationAxes = null) {
378
+ return [
379
+ fontUsage.text,
380
+ fontUsage.fontUrl,
381
+ format,
382
+ JSON.stringify(variationAxes),
383
+ ].join('\x1d');
384
+ }
385
+
386
+ function createFontkitMemoizer(assetGraph) {
387
+ return memoizeSync(function (url) {
388
+ return fontkit.create(assetGraph.findAssets({ url })[0].rawSrc);
389
+ });
390
+ }
391
+
392
+ function getFullyPinnedVariationAxes(
393
+ fontkitMemoizer,
394
+ fontUrl,
395
+ seenAxisValuesByFontUrlAndAxisName
396
+ ) {
397
+ let font;
398
+ try {
399
+ font = fontkitMemoizer(fontUrl);
400
+ } catch (err) {
401
+ // Don't break if we encounter an invalid font or one that's unsupported by fontkit
402
+ return;
403
+ }
404
+ let variationAxes;
405
+ const fontVariationEntries = Object.entries(font.variationAxes);
406
+ const seenAxisValuesByAxisName =
407
+ seenAxisValuesByFontUrlAndAxisName.get(fontUrl);
408
+ if (fontVariationEntries.length > 0 && seenAxisValuesByAxisName) {
409
+ variationAxes = {};
410
+ let everyAxisPinned = true;
411
+ for (const [
412
+ axisName,
413
+ { min, max, default: defaultValue },
414
+ ] of fontVariationEntries) {
415
+ let seenAxisValues = seenAxisValuesByAxisName.get(axisName);
416
+ if (!seenAxisValues && !ignoredVariationAxes.has(axisName)) {
417
+ seenAxisValues = new Set([defaultValue]);
418
+ }
419
+ if (seenAxisValues && seenAxisValues.size === 1) {
420
+ variationAxes[axisName] = _.clamp([...seenAxisValues][0], min, max);
421
+ } else {
422
+ everyAxisPinned = false;
423
+ }
424
+ }
425
+ if (!everyAxisPinned) {
426
+ // Not all variation axes can be fully pinned, bail out
427
+ variationAxes = undefined;
428
+ }
429
+ }
430
+ return variationAxes;
379
431
  }
380
432
 
381
433
  async function getSubsetsForFontUsage(
382
434
  assetGraph,
383
435
  htmlOrSvgAssetTextsWithProps,
384
- formats
436
+ formats,
437
+ seenAxisValuesByFontUrlAndAxisName,
438
+ fontkitMemoizer,
439
+ instance = false
385
440
  ) {
386
441
  const allFonts = [];
387
442
 
@@ -417,17 +472,35 @@ async function getSubsetsForFontUsage(
417
472
  }, {});
418
473
 
419
474
  const subsetPromiseMap = {};
475
+ const notFullyInstancedFontUrls = new Set();
420
476
 
421
477
  for (const item of htmlOrSvgAssetTextsWithProps) {
422
478
  for (const fontUsage of item.fontUsages) {
423
479
  const fontBuffer = originalFontBuffers[fontUsage.fontUrl];
424
480
  const text = fontUsage.text;
481
+ let variationAxes;
482
+ if (instance) {
483
+ variationAxes = getFullyPinnedVariationAxes(
484
+ fontkitMemoizer,
485
+ fontUsage.fontUrl,
486
+ seenAxisValuesByFontUrlAndAxisName
487
+ );
488
+ }
489
+ if (!variationAxes) {
490
+ notFullyInstancedFontUrls.add(fontUsage.fontUrl);
491
+ }
492
+
425
493
  for (const targetFormat of formats) {
426
- const promiseId = getSubsetPromiseId(fontUsage, targetFormat);
494
+ const promiseId = getSubsetPromiseId(
495
+ fontUsage,
496
+ targetFormat,
497
+ variationAxes
498
+ );
427
499
 
428
500
  if (!subsetPromiseMap[promiseId]) {
429
501
  subsetPromiseMap[promiseId] = subsetFont(fontBuffer, text, {
430
502
  targetFormat,
503
+ variationAxes,
431
504
  }).catch((err) => {
432
505
  const error = new Error(err.message);
433
506
  error.asset = assetGraph.findAssets({
@@ -451,6 +524,7 @@ async function getSubsetsForFontUsage(
451
524
  ) {
452
525
  fontUsage.smallestSubsetSize = size;
453
526
  fontUsage.smallestSubsetFormat = targetFormat;
527
+ fontUsage.variationAxes = variationAxes;
454
528
  }
455
529
  }
456
530
  });
@@ -459,6 +533,8 @@ async function getSubsetsForFontUsage(
459
533
  }
460
534
 
461
535
  await Promise.all(Object.values(subsetPromiseMap));
536
+
537
+ return { notFullyInstancedFontUrls };
462
538
  }
463
539
 
464
540
  const fontOrder = ['woff2', 'woff', 'truetype'];
@@ -788,10 +864,7 @@ function renderNumberRange(min, max) {
788
864
  }
789
865
  }
790
866
 
791
- function warnAboutUnusedVariationAxes(
792
- htmlOrSvgAssetTextsWithProps,
793
- assetGraph
794
- ) {
867
+ function getVariationAxisUsage(htmlOrSvgAssetTextsWithProps) {
795
868
  const seenAxisValuesByFontUrlAndAxisName = new Map();
796
869
  const outOfBoundsAxesByFontUrl = new Map();
797
870
 
@@ -802,9 +875,9 @@ function warnAboutUnusedVariationAxes(
802
875
  seenAxisValuesByFontUrlAndAxisName.set(fontUrl, seenAxes);
803
876
  }
804
877
  if (seenAxes.has(axisName)) {
805
- seenAxes.get(axisName).push(axisValue);
878
+ seenAxes.get(axisName).add(axisValue);
806
879
  } else {
807
- seenAxes.set(axisName, [axisValue]);
880
+ seenAxes.set(axisName, new Set([axisValue]));
808
881
  }
809
882
  }
810
883
 
@@ -877,15 +950,28 @@ function warnAboutUnusedVariationAxes(
877
950
  }
878
951
  }
879
952
 
953
+ return { seenAxisValuesByFontUrlAndAxisName, outOfBoundsAxesByFontUrl };
954
+ }
955
+
956
+ function warnAboutUnusedVariationAxes(
957
+ assetGraph,
958
+ seenAxisValuesByFontUrlAndAxisName,
959
+ outOfBoundsAxesByFontUrl,
960
+ notFullyInstancedFontUrls,
961
+ fontkitMemoizer
962
+ ) {
880
963
  const warnings = [];
881
964
  for (const [
882
965
  fontUrl,
883
966
  seenAxisValuesByAxisName,
884
967
  ] of seenAxisValuesByFontUrlAndAxisName.entries()) {
968
+ if (!notFullyInstancedFontUrls.has(fontUrl)) {
969
+ continue;
970
+ }
885
971
  const outOfBoundsAxes = outOfBoundsAxesByFontUrl.get(fontUrl) || new Set();
886
972
  let font;
887
973
  try {
888
- font = fontkit.create(assetGraph.findAssets({ url: fontUrl })[0].rawSrc);
974
+ font = fontkitMemoizer(fontUrl);
889
975
  } catch (err) {
890
976
  // Don't break if we encounter an invalid font or one that's unsupported by fontkit
891
977
  continue;
@@ -1110,6 +1196,7 @@ async function subsetFonts(
1110
1196
  formats = ['woff2', 'woff'],
1111
1197
  subsetPath = 'subfont/',
1112
1198
  omitFallbacks = false,
1199
+ instance = false,
1113
1200
  inlineCss,
1114
1201
  fontDisplay,
1115
1202
  hrefType = 'rootRelative',
@@ -1233,15 +1320,29 @@ async function subsetFonts(
1233
1320
  };
1234
1321
  }
1235
1322
 
1323
+ const { seenAxisValuesByFontUrlAndAxisName, outOfBoundsAxesByFontUrl } =
1324
+ getVariationAxisUsage(htmlOrSvgAssetTextsWithProps);
1325
+
1326
+ const fontkitMemoizer = createFontkitMemoizer(assetGraph);
1327
+
1236
1328
  // Generate subsets:
1237
- await getSubsetsForFontUsage(
1329
+ const { notFullyInstancedFontUrls } = await getSubsetsForFontUsage(
1238
1330
  assetGraph,
1239
1331
  htmlOrSvgAssetTextsWithProps,
1240
- formats
1332
+ formats,
1333
+ seenAxisValuesByFontUrlAndAxisName,
1334
+ fontkitMemoizer,
1335
+ instance
1241
1336
  );
1242
1337
 
1243
1338
  warnAboutMissingGlyphs(htmlOrSvgAssetTextsWithProps, assetGraph);
1244
- warnAboutUnusedVariationAxes(htmlOrSvgAssetTextsWithProps, assetGraph);
1339
+ warnAboutUnusedVariationAxes(
1340
+ assetGraph,
1341
+ seenAxisValuesByFontUrlAndAxisName,
1342
+ outOfBoundsAxesByFontUrl,
1343
+ notFullyInstancedFontUrls,
1344
+ fontkitMemoizer
1345
+ );
1245
1346
 
1246
1347
  // Insert subsets:
1247
1348
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "subfont",
3
- "version": "6.12.4",
3
+ "version": "7.0.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"
@@ -64,9 +64,9 @@
64
64
  "postcss": "^8.3.11",
65
65
  "postcss-value-parser": "^4.0.2",
66
66
  "pretty-bytes": "^5.1.0",
67
- "puppeteer-core": "^8.0.0",
67
+ "puppeteer-core": "^19.8.5",
68
68
  "specificity": "^0.4.1",
69
- "subset-font": "^1.5.0",
69
+ "subset-font": "^2.1.0",
70
70
  "urltools": "^0.4.1",
71
71
  "yargs": "^15.4.0"
72
72
  },
@@ -90,11 +90,11 @@
90
90
  "offline-github-changelog": "^1.6.1",
91
91
  "prettier": "~2.3.0",
92
92
  "proxyquire": "^2.1.1",
93
- "puppeteer": "^8.0.0",
93
+ "puppeteer": "^19.8.5",
94
94
  "sinon": "^9.0.2",
95
95
  "unexpected": "^11.8.1",
96
96
  "unexpected-check": "^2.3.1",
97
- "unexpected-resemble": "^4.3.0",
97
+ "unexpected-resemble": "^5.0.1",
98
98
  "unexpected-set": "^2.0.1",
99
99
  "unexpected-sinon": "^10.11.2"
100
100
  }