vite-plugin-font
Version:
An automatic Web Font optimization plugin that supports many platforms such as Vite, Next, Nuxt, and more.
111 lines (108 loc) • 3.4 kB
JavaScript
import { BundlePlugin, getFileName } from './index.mjs';
import { glob } from 'glob';
import fs from 'fs-extra';
import crypto from 'node:crypto';
import path from 'path';
import { minimatch } from 'minimatch';
class SubsetUtils {
static isSubsetLink(p) {
const [idString, params] = p.split("?");
const searchParams = new URLSearchParams(params);
const isSubset = searchParams.has("subsets");
return { idString, isSubset, searchParams };
}
static emptyCacheDir(config) {
if (!config.cacheDir)
throw new Error("vite-plugin-font | cacheDir missed");
const dir = path.resolve(config.cacheDir, ".subsets");
return fs.emptyDir(dir);
}
}
class SubsetBundlePlugin extends BundlePlugin {
constructor(config, key) {
super(config, key);
this.usedSubsets = /* @__PURE__ */ new Set();
this.isSubsetLink = SubsetUtils.isSubsetLink;
this.subsetConfig = config;
this.subsetCacheDir = config.cacheDir;
}
getCachedPath(p) {
const { isSubset, idString } = this.isSubsetLink(p);
return path.resolve(
isSubset ? this.subsetCacheDir : this.config.cacheDir,
getFileName(idString)
);
}
async createSubsetsHash() {
if (!this.subsetConfig.scanFiles) return;
this.getWhiteListSubsets();
await this.updateScanFiles();
const subsetsArr = [...this.usedSubsets].sort((a, b) => a - b);
this.subsets = [subsetsArr];
const hash = crypto.createHash("md5").update(String.fromCodePoint(...subsetsArr)).digest("hex");
this.subsetCacheDir = path.resolve(
this.config.cacheDir,
".subsets",
hash
);
return hash;
}
/** 匹配绝对路径是否被获取到 */
isMatchScanArea(p) {
const globStr = this.getGlobArea();
if (!globStr) return false;
const resolvePath = (p2) => path.resolve(process.cwd(), p2);
if (globStr instanceof Array) {
return globStr.some((i) => minimatch(p, resolvePath(i)));
}
return minimatch(p, resolvePath(globStr));
}
/** 获取配置中的 scanFiles 字段 */
getGlobArea() {
if (typeof this.subsetConfig.scanFiles === "object" && !(this.subsetConfig.scanFiles instanceof Array)) {
return this.subsetConfig.scanFiles[this.key];
} else {
return this.subsetConfig.scanFiles;
}
}
async updateScanFiles() {
const globStr = this.getGlobArea();
if (!globStr) return;
const files = await glob(globStr, {
absolute: true,
nodir: true,
ignore: this.subsetConfig.ignore ?? ["node_modules/**"]
});
return Promise.all(
files.map((i) => {
return new Promise((res, rej) => {
const stream = fs.createReadStream(i, {
encoding: "utf8"
});
stream.on("data", (i2) => {
[...i2].forEach(
(char) => this.usedSubsets.add(char.codePointAt(0))
);
});
stream.on("end", () => {
res(null);
});
stream.on("error", (err) => {
rej(err);
});
});
})
);
}
getWhiteListSubsets() {
let whiteList = this.subsetConfig.whiteList ?? [];
if (!(whiteList instanceof Array)) {
whiteList = [whiteList];
}
const set = this.usedSubsets;
whiteList.forEach(
(str) => [...str].forEach((char) => set.add(char.codePointAt(0)))
);
}
}
export { SubsetBundlePlugin, SubsetUtils };