fontmin-spider
Version:
Analyze which fonts are used on the page and eliminate the ones that are not used to get a smaller font file
118 lines (117 loc) • 5.84 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const node_fs_1 = require("node:fs");
const node_path_1 = require("node:path");
const htmlparser2_1 = require("htmlparser2");
const css_select_1 = __importDefault(require("css-select"));
const domutils_1 = require("domutils");
const parse_family_map_1 = require("./utils/parse-family-map");
const utils_1 = require("./utils");
/**
* Parsing the fonts used
* @param { string } basePath You can think of it as the root of the website
* @param { string[] } files Array of html files
* @param { Function } filter Execute when all the used fonts are parsed
* (the strings are not parsed, you can use the afterFilter method if you need to process the strings)
* @param { Function } afterFilter After parsing is complete, execute
* @returns { TdeclaredFamilyMap }
*/
/* eslint-disable max-depth,max-statements */
function parse(basePath, files, filter, afterFilter) {
const declaredFamilyMap = {};
const caches = new Map();
const cacheDocment = new Map();
const cacheDocments = new Map();
const getDocument = (file) => (0, htmlparser2_1.parseDocument)((0, node_fs_1.readFileSync)(file).toString());
try {
for (const file of files) {
const doc = cacheDocment.has(file) ? cacheDocment.get(file) : getDocument(file);
const sources = cacheDocments.has(file)
? cacheDocments.get(file)
: (0, css_select_1.default)('style,link[href],[style]', doc);
cacheDocment.set(file, doc);
cacheDocments.set(file, sources);
for (const source of sources) {
// handler style tags
if (source.name === 'style') {
const StyleTextContent = (0, domutils_1.textContent)(source);
const hash = (0, utils_1.getHash)(StyleTextContent);
if (!caches.has(hash)) {
caches.set(hash, StyleTextContent);
(0, parse_family_map_1.parseUseFamily)(basePath, declaredFamilyMap, StyleTextContent, file);
}
continue;
}
// handler link tags
const sourcePath = (0, utils_1.removeParam)(source.attribs.href || '');
const sourceAbsolutePath = (0, utils_1.getAbsolutePath)(basePath, file, sourcePath);
if ((0, node_path_1.extname)(sourcePath) === '.css' &&
(0, node_fs_1.existsSync)(sourceAbsolutePath) &&
(0, node_fs_1.statSync)(sourceAbsolutePath).isFile() &&
!caches.has(sourceAbsolutePath)) {
const data = (0, node_fs_1.readFileSync)(sourceAbsolutePath);
caches.set(sourceAbsolutePath, data);
(0, parse_family_map_1.parseUseFamily)(basePath, declaredFamilyMap, data, sourceAbsolutePath);
continue;
}
}
}
// custom filter font
filter && filter(declaredFamilyMap);
for (const file of files) {
const doc = cacheDocment.has(file) ? cacheDocment.get(file) : getDocument(file);
const sources = cacheDocments.has(file)
? cacheDocments.get(file)
: (0, css_select_1.default)('style,link[href],[style]', doc);
for (const source of sources) {
// handler style tags
if (source.name === 'style') {
const StyleTextContent = (0, domutils_1.textContent)(source);
(0, parse_family_map_1.parseSelector)(declaredFamilyMap, StyleTextContent);
continue;
}
// handler link tags
const sourcePath = (0, utils_1.removeParam)(source.attribs.href || '');
const sourceAbsolutePath = (0, utils_1.getAbsolutePath)(basePath, file, sourcePath);
if ((0, node_path_1.extname)(sourcePath) === '.css' && (0, node_fs_1.existsSync)(sourceAbsolutePath) && (0, node_fs_1.statSync)(sourceAbsolutePath).isFile()) {
const data = caches.has(sourceAbsolutePath)
? caches.get(sourceAbsolutePath)
: (0, node_fs_1.readFileSync)(sourceAbsolutePath);
(0, parse_family_map_1.parseSelector)(declaredFamilyMap, data);
continue;
}
const AttrStyleContent = source.attribs.style || '';
if (!AttrStyleContent)
continue;
const family = (0, parse_family_map_1.getUseFamily)(declaredFamilyMap, AttrStyleContent);
if (declaredFamilyMap[family]) {
declaredFamilyMap[family].chars += (0, domutils_1.textContent)(source);
}
}
getText(doc, declaredFamilyMap);
}
// custom filter font
afterFilter && afterFilter(declaredFamilyMap);
}
catch (error) {
// eslint-disable-next-line no-console
console.error('\x1b[31mfontmin-spider Error:\x1b[39m', error);
}
return declaredFamilyMap;
}
exports.default = parse;
/* eslint-enable */
function getText(dom, familyMap) {
for (const key in familyMap) {
const value = familyMap[key];
if (!value)
continue;
value.selector.map((item) => {
const node = (0, css_select_1.default)(item, dom);
familyMap[key].chars += (0, domutils_1.textContent)(node);
});
}
}