UNPKG

@unocss/preset-web-fonts

Version:

Web Fonts support for Uno CSS

96 lines (92 loc) 3.44 kB
import { Buffer } from 'node:buffer'; import { createHash } from 'node:crypto'; import fs from 'node:fs'; import fsp from 'node:fs/promises'; import { resolve, join } from 'node:path'; import process from 'node:process'; import '@unocss/core'; import { fetch } from 'ofetch'; function replaceAsync(string, searchValue, replacer) { try { if (typeof replacer === "function") { const values = []; String.prototype.replace.call(string, searchValue, (...args) => { values.push(replacer(...args)); return ""; }); return Promise.all(values).then((resolvedValues) => { return String.prototype.replace.call(string, searchValue, () => { return resolvedValues.shift() || ""; }); }); } else { return Promise.resolve( String.prototype.replace.call(string, searchValue, replacer) ); } } catch (error) { return Promise.reject(error); } } const fontUrlRegex = /[-\w@:%+.~#?&/=]+\.(?:woff2?|eot|ttf|otf|svg)/gi; const urlProtocolRegex = /^[\s\w\0+.-]{2,}:([/\\]{1,2})/; function createLocalFontProcessor(options) { const cwd = options?.cwd || process.cwd(); const cacheDir = resolve(cwd, options?.cacheDir || "node_modules/.cache/unocss/fonts"); const fontAssetsDir = resolve(cwd, options?.fontAssetsDir || "public/assets/fonts"); const fontServeBaseUrl = options?.fontServeBaseUrl || "/assets/fonts"; async function _downloadFont(url, assetPath) { const response = await fetch(url).then((r) => r.arrayBuffer()); await fsp.mkdir(fontAssetsDir, { recursive: true }); await fsp.writeFile(assetPath, Buffer.from(response)); } const cache = /* @__PURE__ */ new Map(); function downloadFont(url, assetPath) { if (!cache.has(url)) cache.set(url, _downloadFont(url, assetPath)); return cache.get(url); } return { async getCSS(fonts, providers, getCSSDefault) { const hash = getHash(JSON.stringify(fonts)); const cachePath = join(cacheDir, `${hash}.css`); if (fs.existsSync(cachePath)) { return fsp.readFile(cachePath, "utf-8"); } const css = await getCSSDefault(fonts, providers); await fsp.mkdir(cacheDir, { recursive: true }); await fsp.writeFile(cachePath, css, "utf-8"); return css; }, async transformCSS(css) { return await replaceAsync(css, fontUrlRegex, async (url) => { const hash = getHash(url); const ext = url.split(".").pop(); let name = ""; const match1 = url.match(/\/s\/([^/]+)\//); if (match1) name = match1[1].replace(/\W/g, " ").trim().replace(/\s+/, "-").toLowerCase(); const filename = `${[name, hash].filter(Boolean).join("-")}.${ext}`; const assetPath = join(fontAssetsDir, filename); if (!fs.existsSync(assetPath)) { const _url = hasProtocol(url) ? url : withProtocol(url); await downloadFont(_url, assetPath); } return `${fontServeBaseUrl}/${filename}`; }); } }; } function getHash(input, length = 8) { return createHash("sha256").update(input).digest("hex").slice(0, length); } function hasProtocol(input) { return urlProtocolRegex.test(input); } function withProtocol(input, protocol = "https://") { const match = input.match(/^\/{2,}/); if (!match) return protocol + input; return protocol + input.slice(match[0].length); } export { createLocalFontProcessor };