UNPKG

unplugin-fonts

Version:
136 lines (135 loc) 3.95 kB
import { basename, extname, join, relative } from "pathe"; import fg from "fast-glob"; //#region src/loaders/custom.ts function resolveUserOption(options) { let { families = [], preload = true, prefetchPrefix = "", prefetch = false, injectTo = "head-prepend", display = "auto", stripPrefix = "public/", linkFilter } = options; if (!Array.isArray(families)) families = Object.entries(families).map(([name, family]) => Array.isArray(family) || typeof family === "string" ? { name, src: family } : { name, ...family }); return { families, preload, prefetchPrefix, prefetch, injectTo, display, stripPrefix, linkFilter }; } function customVirtualModule(userOptions, root) { const options = resolveUserOption(userOptions); const css = []; for (const family of options.families) { const faces = resolveFontFiles(family, options, root); for (const face of faces) css.push(generateFontCSS(face)); } return css.join("\n"); } function resolveFontFiles(family, options, root) { const sources = Array.isArray(family.src) ? family.src : [family.src]; const facesMap = {}; for (const source of sources) { const results = fg.sync(join(root, source), { absolute: true, cwd: root, onlyFiles: true }); for (const file of results) { const ext = extname(file); const basename$1 = basename(file, ext); let format = ""; switch (ext) { case ".woff": format = "woff"; break; case ".woff2": format = "woff2"; break; case ".ttf": format = "truetype"; break; case ".otf": format = "opentype"; break; case ".svg": format = "svg"; break; default: format = ext.replace(".", ""); } facesMap[basename$1] ||= { source, name: family.name, basename: basename$1, weight: extractWeight(basename$1), style: extractStyle(basename$1), local: family.local, display: options.display, files: [] }; facesMap[basename$1].files.push({ src: file, path: join("/", relative(root, file.replace(options.stripPrefix, ""))), format, ext }); } } const faces = []; for (const face of Object.values(facesMap)) { if (!family.transform) { faces.push(face); continue; } const transformed = family.transform(face); if (transformed) faces.push(transformed); } return faces; } function extractWeight(filename) { if (!filename) return 400; filename = filename.toLowerCase(); if (filename.includes("thin")) return 100; if (filename.includes("extralight")) return 200; if (filename.includes("ultralight")) return 200; if (filename.includes("light")) return 300; if (filename.includes("normal")) return 400; if (filename.includes("medium")) return 500; if (filename.includes("semibold")) return 600; if (filename.includes("demibold")) return 600; if (filename.includes("extrabold")) return 800; if (filename.includes("ultrabold")) return 800; if (filename.includes("bold")) return 700; if (filename.includes("black")) return 900; if (filename.includes("heavy")) return 900; return 400; } function extractStyle(filename) { if (!filename) return "normal"; filename = filename.toLowerCase(); if (filename.includes("normal")) return "normal"; if (filename.includes("italic")) return "italic"; if (filename.includes("oblique")) return "oblique"; return "normal"; } function generateFontCSS(face) { const srcs = face.files.map((file) => { return `url('${file.path}') format('${file.format}')`; }).join(",\n "); const locals = (Array.isArray(face.local) ? face.local : [face.local]).filter(Boolean).map((x) => `local('${x}')`).join(", "); return [ "@font-face {", ` font-family: '${face.name}';`, ` src: ${[srcs, locals].filter(Boolean).join(",")};`, ` font-weight: ${face.weight};`, ` font-style: ${face.style};`, ` font-display: ${face.display};`, "}" ].join("\n"); } //#endregion export { customVirtualModule, resolveFontFiles, resolveUserOption };