Munter / subfont

Command line tool to optimize your webfont loading. Aggressive subsetting based on your font use, self-hosting of Google fonts and preloading
MIT License
1.56k stars 29 forks source link

Unicode range outside of css block in fallback file #130

Closed ghost closed 3 years ago

ghost commented 3 years ago

Full example

initial index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0, shrink-to-fit=no"
    />
    <title>debug_subfont</title>
    <link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css" />
    <link
      rel="stylesheet"
      href="https://fonts.googleapis.com/css?family=Alice"
    />
  </head>

  <body class="text-center">
    <h1 style="font-family: Alice, serif">
      Christmas Images - Adorable boy with a dog
    </h1>
    <a
      class="d-block"
      href="https://thegraphicsfairy.com/vintage-christmas-image-boy-snow/"
      >https://thegraphicsfairy.com/vintage-christmas-image-boy-snow/</a
    ><img
      src="assets/img/Free-Christmas-Picture-Boy-Dog-GraphicsFairy-658x1024.jpg"
      style="height: 600px"
    />
    <script src="assets/js/jquery.min.js"></script>
    <script src="assets/bootstrap/js/bootstrap.min.js"></script>
  </body>
</html>

font faces from Alice font from google fonts:

/* cyrillic-ext */
@font-face {
  font-family: 'Alice';
  font-style: normal;
  font-weight: 400;
  src: url(https://fonts.gstatic.com/s/alice/v12/OpNCnoEEmtHa6GcDrg7shw.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: 'Alice';
  font-style: normal;
  font-weight: 400;
  src: url(https://fonts.gstatic.com/s/alice/v12/OpNCnoEEmtHa6GcKrg7shw.woff2) format('woff2');
  unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* latin */
@font-face {
  font-family: 'Alice';
  font-style: normal;
  font-weight: 400;
  src: url(https://fonts.gstatic.com/s/alice/v12/OpNCnoEEmtHa6GcOrg4.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

command: subfont index.html -o ./ -i -r

command output:

Guessing --root from input files: file:///home/user/html_project/
 ✔ 0.001 secs: logEvents
(node:62526) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(Use `node --trace-warnings ...` to show where the warning was created)
 ✔ 0.071 secs: loadAssets
(node:62526) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:62526) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:62526) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:62526) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:62526) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:62526) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:62526) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:62526) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:62526) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:62526) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:62526) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:62526) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:62526) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:62526) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
 ✔ 1.786 secs: populate
 ✔ 0.003 secs: checkIncompatibleTypes
 ✔ 0.001 secs: applySourceMaps
 ✔ 0.001 secs: populate
 ✔ 0.003 secs: populate
 ⚠ WARN: https://fonts.gstatic.com/s/alice/v12/OpNCnoEEmtHa6GcOrgs.ttf - Command failed: pyftsubset /tmp/input-120113-62526-3-37mlp9.5qpmy.woff --output-file=/tmp/output-120113-62526-4-1gb79tk.qlw8.woff --obfuscate_names --text=" -ACIabdeghilmorstwy" --with-zopfli --flavor=woff
         Traceback (most recent call last):
           File "/home/user/.local/bin/pyftsubset", line 8, in <module>
             sys.exit(main())
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/misc/loggingTools.py", line 375, in wrapper
             return func(*args, **kwds)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/subset/__init__.py", line 2881, in main
             save_font(font, outfile, options)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/misc/loggingTools.py", line 375, in wrapper
             return func(*args, **kwds)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/subset/__init__.py", line 2728, in save_font
             font.save(outfile, reorderTables=options.canonical_order)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/ttLib/ttFont.py", line 173, in save
             writer_reordersTables = self._save(tmp)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/ttLib/ttFont.py", line 212, in _save
             self._writeTable(tag, writer, done, tableCache)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/ttLib/ttFont.py", line 629, in _writeTable
             self._writeTable(masterTable, writer, done, tableCache)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/ttLib/ttFont.py", line 629, in _writeTable
             self._writeTable(masterTable, writer, done, tableCache)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/ttLib/ttFont.py", line 641, in _writeTable
             writer[tag] = tabledata
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/ttLib/sfnt.py", line 264, in __setitem__
             entry.saveData(self.file, data)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/ttLib/sfnt.py", line 486, in saveData
             data = self.encodeData(data)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/ttLib/sfnt.py", line 531, in encodeData
             compressedData = compress(data, self.zlibCompressionLevel)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/ttLib/sfnt.py", line 187, in compress
             from zopfli.zlib import compress
         ImportError: No module named zopfli.zlib

         Including assets:
             https://fonts.googleapis.com/css?family=Alice

(node:62526) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
 ✔ 0.001 secs: serializeSourceMaps
 ✔ 0.058 secs: compressJavaScript
 ✔ 0.010 secs: writeAssetsToDisc
index.html: 1 font (1 variant) in use, 61.4 kB total. Created subsets: 5.54 kB total
  Alice:
    400 : 20/215 codepoints used, 61.4 kB (ttf) => 5.54 kB (woff2)
HTML/JS/CSS size increase: 978 B
Total savings: 54.9 kB
Output written to file:///home/user/html_project/
❯ subfont index.html -o ./ -r
Guessing --root from input files: file:///home/user/html_project/
 ✔ 0.002 secs: logEvents
(node:63809) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(Use `node --trace-warnings ...` to show where the warning was created)
 ✔ 0.079 secs: loadAssets
(node:63809) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:63809) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:63809) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:63809) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:63809) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:63809) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:63809) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:63809) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:63809) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:63809) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:63809) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:63809) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:63809) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
(node:63809) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
 ✔ 1.848 secs: populate
 ✔ 0.004 secs: checkIncompatibleTypes
 ✔ 0.001 secs: applySourceMaps
 ✔ 0.001 secs: populate
 ✔ 0.003 secs: populate
 ⚠ WARN: https://fonts.gstatic.com/s/alice/v12/OpNCnoEEmtHa6GcOrgs.ttf - Command failed: pyftsubset /tmp/input-120113-63809-3-32dr80.ek8sp.woff --output-file=/tmp/output-120113-63809-4-13b7d8l.3dsa.woff --obfuscate_names --text=" -ACIabdeghilmorstwy" --with-zopfli --flavor=woff
         Traceback (most recent call last):
           File "/home/user/.local/bin/pyftsubset", line 8, in <module>
             sys.exit(main())
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/misc/loggingTools.py", line 375, in wrapper
             return func(*args, **kwds)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/subset/__init__.py", line 2881, in main
             save_font(font, outfile, options)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/misc/loggingTools.py", line 375, in wrapper
             return func(*args, **kwds)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/subset/__init__.py", line 2728, in save_font
             font.save(outfile, reorderTables=options.canonical_order)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/ttLib/ttFont.py", line 173, in save
             writer_reordersTables = self._save(tmp)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/ttLib/ttFont.py", line 212, in _save
             self._writeTable(tag, writer, done, tableCache)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/ttLib/ttFont.py", line 629, in _writeTable
             self._writeTable(masterTable, writer, done, tableCache)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/ttLib/ttFont.py", line 629, in _writeTable
             self._writeTable(masterTable, writer, done, tableCache)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/ttLib/ttFont.py", line 641, in _writeTable
             writer[tag] = tabledata
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/ttLib/sfnt.py", line 264, in __setitem__
             entry.saveData(self.file, data)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/ttLib/sfnt.py", line 486, in saveData
             data = self.encodeData(data)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/ttLib/sfnt.py", line 531, in encodeData
             compressedData = compress(data, self.zlibCompressionLevel)
           File "/home/user/.local/lib/python2.7/site-packages/fontTools/ttLib/sfnt.py", line 187, in compress
             from zopfli.zlib import compress
         ImportError: No module named zopfli.zlib

         Including assets:
             https://fonts.googleapis.com/css?family=Alice

(node:63809) Warning: a promise was created in a handler at internal/timers.js:458:21 but was not returned from it, see http://goo.gl/rRqMUw
    at new Promise (/home/user/.config/yarn/global/node_modules/bluebird/js/release/promise.js:103:10)
 ✔ 0.004 secs: serializeSourceMaps
 ✔ 0.050 secs: compressJavaScript
 ✔ 0.009 secs: writeAssetsToDisc
index.html: 1 font (1 variant) in use, 61.4 kB total. Created subsets: 5.54 kB total
  Alice:
    400 : 20/215 codepoints used, 61.4 kB (ttf) => 5.54 kB (woff2)
HTML/JS/CSS size increase: 978 B
Total savings: 54.9 kB
Output written to file:///home/user/html_project/

result index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0, shrink-to-fit=no"
    />
    <title>debug_subfont</title>
    <link
      rel="preload"
      as="font"
      type="font/woff2"
      crossorigin="anonymous"
      href="/subfont/Alice-400-ab52a3064c.woff2"
    />
    <script>
      try {
        new FontFace(
          "Alice__subset",
          "url(/subfont/Alice-400-ab52a3064c.woff2) format('woff2')",
          {}
        ).load();
      } catch (e) {}
    </script>
    <link rel="stylesheet" href="/subfont/fonts-2f47494d1d.css" />
    <link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css" />
  </head>

  <body class="text-center">
    <h1 style="font-family: Alice__subset, Alice, serif">
      Christmas Images - Adorable boy with a dog
    </h1>
    <a
      class="d-block"
      href="https://thegraphicsfairy.com/vintage-christmas-image-boy-snow/"
      >https://thegraphicsfairy.com/vintage-christmas-image-boy-snow/</a
    ><img
      src="assets/img/Free-Christmas-Picture-Boy-Dog-GraphicsFairy-658x1024.jpg"
      style="height: 600px"
    />
    <script src="assets/js/jquery.min.js"></script>
    <script src="assets/bootstrap/js/bootstrap.min.js"></script>

    <script>
      !(function () {
        var el = document.createElement("link");
        (el.href = "/subfont/fallback-94148c0c6e.css"),
          (el.rel = "stylesheet"),
          document.body.appendChild(el);
      })();
    </script>
    <noscript
      ><link rel="stylesheet" href="/subfont/fallback-94148c0c6e.css"
    /></noscript>
  </body>
</html>

subfont/fallback-94148c0c6e.css (here's the problem):

@font-face {
  font-family: Alice;
  font-style: normal;
  font-weight: 400;
  src: url(/subfont/OpNCnoEEmtHa6GcOrgs-d20675bb02.woff2) format("woff2"),
    url(/subfont/OpNCnoEEmtHa6GcOrgs-fea7d90d85.woff) format("woff");
}
unicode-range: U+d, U+20-7e, U+a0-ff, U+131, U+152-153, U+2bc, U+2c6, U+2da,
  U+2dc, U+2013-2014, U+2018-201a, U+201c-201e, U+2022, U+2039-203a, U+2044,
  U+2074, U+20ac, U+2212, U+ffff;

as you can see there's the css property unicode-range that was put outside of the css block and my css linter complains.

subfont/fonts-2f47494d1d.css

here the unicode is inside the block:

@font-face {
  font-display: swap;
  font-family: Alice__subset;
  font-stretch: normal;
  font-style: normal;
  font-weight: 400;
  src: url(/subfont/Alice-400-ab52a3064c.woff2) format("woff2");
  unicode-range: U+20, U+2d, U+41, U+43, U+49, U+61-62, U+64-65, U+67-69,
    U+6c-6d, U+6f, U+72-74, U+77, U+79;
}
ghost commented 3 years ago

I'm using subfont 5.2.2

Munter commented 3 years ago

Definitely a bug, and I'm a bit confused why that slipped through our tests.

I'm also a bit concerned about the log output you are getting. The missing zopfli dependency for pyftsubset I understand, but the promise warnings I haven't seen before. The log output is not supposed to be that noisy

Munter commented 3 years ago

This is the problem: https://github.com/Munter/subfont/blob/79c52aa93aae32b1bb2836bd134750e3e4a8b253/lib/subsetFonts.js#L609-L614

papandreou commented 3 years ago

Fixed in 5.2.3, thanks for reporting it! :bow:

ghost commented 3 years ago

thanks for the great work! I've updated #131 to reflect the new version.