subfont 7.0.0 → 7.1.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,11 @@
1
+ ### v7.1.1 (2023-05-07)
2
+
3
+ - [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
+
5
+ ### v7.1.0 (2023-04-15)
6
+
7
+ - [#170](https://github.com/Munter/subfont/pull/170) Use harfbuzzjs instead of fontkit ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
8
+
1
9
  ### v7.0.0 (2023-04-08)
2
10
 
3
11
  #### Pull requests
@@ -0,0 +1,27 @@
1
+ const fontverter = require('fontverter');
2
+
3
+ async function getFontInfoFromBuffer(buffer) {
4
+ const harfbuzzJs = await require('harfbuzzjs');
5
+
6
+ const blob = harfbuzzJs.createBlob(await fontverter.convert(buffer, 'sfnt')); // Load the font data into something Harfbuzz can use
7
+ const face = harfbuzzJs.createFace(blob, 0); // Select the first font in the file (there's normally only one!)
8
+
9
+ const fontInfo = {
10
+ characterSet: Array.from(face.collectUnicodes()),
11
+ variationAxes: face.getAxisInfos(),
12
+ };
13
+
14
+ face.destroy();
15
+ blob.destroy();
16
+
17
+ return fontInfo;
18
+ }
19
+
20
+ const fontInfoPromiseByBuffer = new WeakMap();
21
+
22
+ module.exports = function getFontInfo(buffer) {
23
+ if (!fontInfoPromiseByBuffer.has(buffer)) {
24
+ fontInfoPromiseByBuffer.set(buffer, getFontInfoFromBuffer(buffer));
25
+ }
26
+ return fontInfoPromiseByBuffer.get(buffer);
27
+ };
@@ -20,13 +20,13 @@ const injectSubsetDefinitions = require('./injectSubsetDefinitions');
20
20
  const cssFontParser = require('css-font-parser');
21
21
  const cssListHelpers = require('css-list-helpers');
22
22
  const LinesAndColumns = require('lines-and-columns').default;
23
- const fontkit = require('fontkit');
24
23
  const crypto = require('crypto');
25
24
 
26
25
  const unquote = require('./unquote');
27
26
  const normalizeFontPropertyValue = require('./normalizeFontPropertyValue');
28
27
  const getCssRulesByProperty = require('./getCssRulesByProperty');
29
28
  const unicodeRange = require('./unicodeRange');
29
+ const getFontInfo = require('./getFontInfo');
30
30
 
31
31
  const googleFontsCssUrlRegex = /^(?:https?:)?\/\/fonts\.googleapis\.com\/css/;
32
32
 
@@ -383,26 +383,17 @@ function getSubsetPromiseId(fontUsage, format, variationAxes = null) {
383
383
  ].join('\x1d');
384
384
  }
385
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,
386
+ async function getFullyPinnedVariationAxes(
387
+ assetGraph,
394
388
  fontUrl,
395
389
  seenAxisValuesByFontUrlAndAxisName
396
390
  ) {
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
- }
391
+ const fontInfo = await getFontInfo(
392
+ assetGraph.findAssets({ url: fontUrl })[0].rawSrc
393
+ );
394
+
404
395
  let variationAxes;
405
- const fontVariationEntries = Object.entries(font.variationAxes);
396
+ const fontVariationEntries = Object.entries(fontInfo.variationAxes);
406
397
  const seenAxisValuesByAxisName =
407
398
  seenAxisValuesByFontUrlAndAxisName.get(fontUrl);
408
399
  if (fontVariationEntries.length > 0 && seenAxisValuesByAxisName) {
@@ -435,7 +426,6 @@ async function getSubsetsForFontUsage(
435
426
  htmlOrSvgAssetTextsWithProps,
436
427
  formats,
437
428
  seenAxisValuesByFontUrlAndAxisName,
438
- fontkitMemoizer,
439
429
  instance = false
440
430
  ) {
441
431
  const allFonts = [];
@@ -480,8 +470,8 @@ async function getSubsetsForFontUsage(
480
470
  const text = fontUsage.text;
481
471
  let variationAxes;
482
472
  if (instance) {
483
- variationAxes = getFullyPinnedVariationAxes(
484
- fontkitMemoizer,
473
+ variationAxes = await getFullyPinnedVariationAxes(
474
+ assetGraph,
485
475
  fontUsage.fontUrl,
486
476
  seenAxisValuesByFontUrlAndAxisName
487
477
  );
@@ -681,7 +671,7 @@ async function createSelfHostedGoogleFontsCssAsset(
681
671
  lines.push(` src: ${srcFragments.join(', ')};`);
682
672
  lines.push(
683
673
  ` unicode-range: ${unicodeRange(
684
- fontkit.create(cssFontFaceSrc.to.rawSrc).characterSet
674
+ (await getFontInfo(cssFontFaceSrc.to.rawSrc)).characterSet
685
675
  )};`
686
676
  );
687
677
  lines.push('}');
@@ -761,7 +751,10 @@ function parseFontStretchRange(str) {
761
751
  return [minFontStretch, maxFontStretch];
762
752
  }
763
753
 
764
- function warnAboutMissingGlyphs(htmlOrSvgAssetTextsWithProps, assetGraph) {
754
+ async function warnAboutMissingGlyphs(
755
+ htmlOrSvgAssetTextsWithProps,
756
+ assetGraph
757
+ ) {
765
758
  const missingGlyphsErrors = [];
766
759
 
767
760
  for (const {
@@ -771,9 +764,9 @@ function warnAboutMissingGlyphs(htmlOrSvgAssetTextsWithProps, assetGraph) {
771
764
  } of htmlOrSvgAssetTextsWithProps) {
772
765
  for (const fontUsage of fontUsages) {
773
766
  if (fontUsage.subsets) {
774
- const characterSet = fontkit.create(
767
+ const { characterSet } = await getFontInfo(
775
768
  Object.values(fontUsage.subsets)[0]
776
- ).characterSet;
769
+ );
777
770
 
778
771
  let missedAny = false;
779
772
  for (const char of [...fontUsage.pageText]) {
@@ -953,12 +946,11 @@ function getVariationAxisUsage(htmlOrSvgAssetTextsWithProps) {
953
946
  return { seenAxisValuesByFontUrlAndAxisName, outOfBoundsAxesByFontUrl };
954
947
  }
955
948
 
956
- function warnAboutUnusedVariationAxes(
949
+ async function warnAboutUnusedVariationAxes(
957
950
  assetGraph,
958
951
  seenAxisValuesByFontUrlAndAxisName,
959
952
  outOfBoundsAxesByFontUrl,
960
- notFullyInstancedFontUrls,
961
- fontkitMemoizer
953
+ notFullyInstancedFontUrls
962
954
  ) {
963
955
  const warnings = [];
964
956
  for (const [
@@ -969,17 +961,20 @@ function warnAboutUnusedVariationAxes(
969
961
  continue;
970
962
  }
971
963
  const outOfBoundsAxes = outOfBoundsAxesByFontUrl.get(fontUrl) || new Set();
972
- let font;
964
+ let fontInfo;
973
965
  try {
974
- font = fontkitMemoizer(fontUrl);
966
+ fontInfo = await getFontInfo(
967
+ assetGraph.findAssets({ url: fontUrl })[0].rawSrc
968
+ );
975
969
  } catch (err) {
976
- // Don't break if we encounter an invalid font or one that's unsupported by fontkit
970
+ // Don't break if we encounter an invalid font
977
971
  continue;
978
972
  }
973
+
979
974
  const unusedAxes = [];
980
975
  const underutilizedAxes = [];
981
976
  for (const [name, { min, max, default: defaultValue }] of Object.entries(
982
- font.variationAxes
977
+ fontInfo.variationAxes
983
978
  )) {
984
979
  if (ignoredVariationAxes.has(name)) {
985
980
  continue;
@@ -1290,7 +1285,8 @@ async function subsetFonts(
1290
1285
  let originalCodepoints;
1291
1286
  try {
1292
1287
  // Guard against 'Unknown font format' errors
1293
- originalCodepoints = fontkit.create(originalFont.rawSrc).characterSet;
1288
+ originalCodepoints = (await getFontInfo(originalFont.rawSrc))
1289
+ .characterSet;
1294
1290
  } catch (err) {}
1295
1291
  if (originalCodepoints) {
1296
1292
  const usedCodepoints = getCodepoints(fontUsage.text);
@@ -1323,25 +1319,21 @@ async function subsetFonts(
1323
1319
  const { seenAxisValuesByFontUrlAndAxisName, outOfBoundsAxesByFontUrl } =
1324
1320
  getVariationAxisUsage(htmlOrSvgAssetTextsWithProps);
1325
1321
 
1326
- const fontkitMemoizer = createFontkitMemoizer(assetGraph);
1327
-
1328
1322
  // Generate subsets:
1329
1323
  const { notFullyInstancedFontUrls } = await getSubsetsForFontUsage(
1330
1324
  assetGraph,
1331
1325
  htmlOrSvgAssetTextsWithProps,
1332
1326
  formats,
1333
1327
  seenAxisValuesByFontUrlAndAxisName,
1334
- fontkitMemoizer,
1335
1328
  instance
1336
1329
  );
1337
1330
 
1338
- warnAboutMissingGlyphs(htmlOrSvgAssetTextsWithProps, assetGraph);
1339
- warnAboutUnusedVariationAxes(
1331
+ await warnAboutMissingGlyphs(htmlOrSvgAssetTextsWithProps, assetGraph);
1332
+ await warnAboutUnusedVariationAxes(
1340
1333
  assetGraph,
1341
1334
  seenAxisValuesByFontUrlAndAxisName,
1342
1335
  outOfBoundsAxesByFontUrl,
1343
- notFullyInstancedFontUrls,
1344
- fontkitMemoizer
1336
+ notFullyInstancedFontUrls
1345
1337
  );
1346
1338
 
1347
1339
  // Insert subsets:
@@ -1483,9 +1475,11 @@ async function subsetFonts(
1483
1475
  .split(/\s+/)
1484
1476
  .map((token) => normalizeFontPropertyValue('font-weight', token))
1485
1477
  .join('_');
1486
- const fileNamePrefix = `${unquote(nameProps[0])
1478
+ const fileNamePrefix = `${unquote(
1479
+ cssFontParser.parseFontFamily(nameProps[0])[0]
1480
+ )
1487
1481
  .replace(/__subset$/, '')
1488
- .replace(/ /g, '_')}-${fontWeightRangeStr}${
1482
+ .replace(/[^a-z0-9_-]/gi, '_')}-${fontWeightRangeStr}${
1489
1483
  nameProps[2] === 'italic' ? 'i' : ''
1490
1484
  }`;
1491
1485
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "subfont",
3
- "version": "7.0.0",
3
+ "version": "7.1.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"
@@ -55,9 +55,9 @@
55
55
  "css-list-helpers": "^2.0.0",
56
56
  "font-snapper": "^1.2.0",
57
57
  "font-tracer": "^3.6.0",
58
- "fontkit": "^1.8.0",
59
58
  "fontverter": "^2.0.0",
60
59
  "gettemporaryfilepath": "^1.0.1",
60
+ "harfbuzzjs": "^0.3.3",
61
61
  "lines-and-columns": "^1.1.6",
62
62
  "lodash": "^4.17.15",
63
63
  "memoizesync": "^1.1.1",