generate-fa5-icons.php read fa-{brands,regular,solid}.svg from
webfonts/, but only woff/woff2 ship with the theme, so the generator
died on file_get_contents() and the committed fa5-icons.php could not
be regenerated from what the theme actually distributes.
Decode the style split from each shipped woff's cmap table instead.
The split has to come from the font: FA5 assigns different drawings to
the same codepoint per style, so fas/far/fab membership is unanswerable
from the CSS alone. Output is byte-identical to the committed catalog
(1001/151/456), so the picker is unaffected.
all.min.css also declared eot / eot?#iefix / ttf / svg fallbacks for all
three families while webfonts/ holds only woff2 + woff, so a browser
that stops at woff requested six files that do not exist. Add
tools/strip-fa5-legacy-fonts.mjs to keep the src: list to what ships;
it is idempotent and touches nothing but the @font-face blocks.
57 lines
2.4 KiB
JavaScript
57 lines
2.4 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Strip the font formats we do not ship from the bundled Font Awesome 5 CSS.
|
|
*
|
|
* assets/fontawesome5/webfonts only contains woff2 + woff, but all.min.css
|
|
* still advertises eot / ttf / svg fallbacks. A browser that stops at woff
|
|
* (IE11, older Safari) requests files that were never distributed, so each of
|
|
* the three styles 404s once per page load.
|
|
*
|
|
* The rewrite is scoped to @font-face src: declarations only — glyph rules,
|
|
* utilities and the license header are left untouched.
|
|
*/
|
|
import { readFileSync, writeFileSync } from 'node:fs';
|
|
import { dirname, join } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const root = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
const target = join(root, 'assets/fontawesome5/css/all.min.css');
|
|
|
|
const css = readFileSync(target, 'utf8');
|
|
|
|
// Each @font-face carries two src statements: the IE-only eot shim
|
|
// (`src:url(...eot);`) and the formatted source list (`src:url(...),url(...)`).
|
|
// Match the whole run of consecutive src statements up to the closing brace so
|
|
// both dangling statements collapse into one clean list.
|
|
const SHIPPED = new Set(['woff2', 'woff']);
|
|
const srcRun = /(?:src:[^;{}]*(?:;[^;{}]*?)?)*(?=\})/gi;
|
|
|
|
const rewritten = css.replace(srcRun, (run) => {
|
|
// Only touch runs that are actually src declarations, not other properties.
|
|
if (!/^src:/.test(run)) return run;
|
|
|
|
const sources = [...run.matchAll(/url\(([^)]+)\)\s*(?:format\(["']?([a-z0-9-]+)["']?\))?/gi)]
|
|
.map(([, url, format]) => ({ url: url.trim(), format: (format || '').toLowerCase() }));
|
|
// Drop every source whose format we do not ship; a source with no format()
|
|
// is the eot shim, which no browser that loads this file can use.
|
|
const kept = sources.filter((s) => SHIPPED.has(s.format));
|
|
if (!kept.length) return run;
|
|
|
|
const declaration = `src:${kept.map((s) => `url(${s.url}) format("${s.format}")`).join(',')}`;
|
|
// Already clean: re-running the script must stay a no-op rather than a failure.
|
|
return declaration === run ? run : declaration;
|
|
});
|
|
|
|
const dropped = [...css.matchAll(/url\(([^)]*webfonts[^)]*)\)/g)]
|
|
.map((m) => m[1])
|
|
.filter((url) => !/\.woff2?(\?|\)|$)/.test(url));
|
|
|
|
const alreadyClean = rewritten === css;
|
|
if (!alreadyClean) writeFileSync(target, rewritten);
|
|
|
|
if (dropped.length) {
|
|
console.log(`dropped ${dropped.length} non-shipped font references: ${[...new Set(dropped)].join(', ')}`);
|
|
} else {
|
|
console.log('all.min.css already ships only woff2 + woff — nothing to do');
|
|
}
|