UNPKG

vite-plugin-icons

Version:

Access thousands of icons as Vue components in Vite

195 lines (186 loc) 5.36 kB
var __require = (x) => { if (typeof require !== "undefined") return require(x); throw new Error('Dynamic require of "' + x + '" is not supported'); }; // src/loader.ts import { SVG, Collection } from "@iconify/json-tools"; // src/compiler/vue2.ts function Vue2Compiler(svg, name, icon) { const { compile } = __require("vue-template-compiler"); const transpile = __require("vue-template-es2015-compiler"); const { render } = compile(svg); const toFunction = (code2) => { return `function () {${code2}}`; }; let code = transpile(`var __render__ = ${toFunction(render)} `, {}); code = code.replace(/\s__(render|staticRenderFns)__\s/g, " $1 "); code += ` /* vite-plugin-components disabled */ export default { render: render, name: '${name}-${icon}', } `; return code; } // src/compiler/vue3.ts function Vue3Compiler(svg, name, icon) { const { compileTemplate } = __require("@vue/compiler-sfc"); let { code } = compileTemplate({ source: svg, id: `${name}:${icon}`, filename: `${name}-${icon}.vue` }); code = code.replace(/^export /g, ""); code += ` export default { name: '${name}-${icon}', render }`; code += "\n/* vite-plugin-components disabled */"; return code; } // src/constants.ts var URL_PREFIXES = ["/@vite-icons/", "@vite-icons/", "virtual:vite-icons/"]; // src/loader.ts var iconPathRE = new RegExp(`${URL_PREFIXES.map((v) => `^${v}`).join("|")}`); function isIconPath(path) { return iconPathRE.test(path); } function normalizeIconPath(path) { return path.replace(iconPathRE, URL_PREFIXES[0]); } function resolveIconsPath(path) { if (!isIconPath(path)) return null; path = path.replace(iconPathRE, ""); const query = {}; const queryIndex = path.indexOf("?"); if (queryIndex !== -1) { const queryRaw = path.slice(queryIndex + 1); path = path.slice(0, queryIndex); new URLSearchParams(queryRaw).forEach((value, key) => { query[value] = key; }); } if (path.endsWith(".vue")) path = path.slice(0, -4); const [collection, icon] = path.split("/"); return { collection, icon, query }; } var _collections = {}; var _idTransforms = [ (str) => str, (str) => str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(), (str) => str.replace(/([a-z])(\d+)/g, "$1-$2") ]; function getCollection(name) { if (!_collections[name]) { const collection = new Collection(); collection.loadIconifyCollection(name); _collections[name] = collection; } return _collections[name]; } function getIcon(name, icon) { const collection = getCollection(name); if (!collection) return null; let data; for (const trans of _idTransforms) { data = collection.getIconData(trans(icon)); if (data) return data; } return null; } async function generateComponent({ collection: name, icon }, options) { const data = getIcon(name, icon); const { scale, defaultStyle, defaultClass } = options; const svg = new SVG(data); const svgText = svg.getSVG({ height: `${scale}em`, width: `${scale}em`, style: defaultStyle, class: defaultClass }); if (!svgText) return null; if (options.compiler === "vue2") return Vue2Compiler(svgText, name, icon); else return Vue3Compiler(svgText, name, icon); } async function generateComponentFromPath(path, options) { const resolved = resolveIconsPath(path); if (!resolved) return null; return generateComponent(resolved, options); } // src/resolver.ts import Data from "@iconify/json"; function camelToKebab(key) { const result = key.replace(/:/g, "-").replace(/([A-Z])/g, " $1").trim(); return result.split(/\s+/g).join("-").toLowerCase(); } function ViteIconsResolver(options = {}) { const { componentPrefix = "i", enabledCollections = Object.keys(Data.collections()) } = options; const prefix = componentPrefix ? `${camelToKebab(componentPrefix)}-` : ""; enabledCollections.sort((a, b) => b.length - a.length); return (name) => { const kebab = camelToKebab(name); if (!kebab.startsWith(prefix)) return; const slice = kebab.slice(prefix.length); const collection = enabledCollections.find((i) => slice.startsWith(`${i}-`)) || enabledCollections.find((i) => slice.startsWith(i)); if (!collection) return; let icon = slice.slice(collection.length); if (icon[0] === "-") icon = icon.slice(1); if (!icon) return; if (!getIcon(collection, icon)) return; return `virtual:vite-icons/${collection}/${icon}`; }; } // src/index.ts function VitePluginIcons(userOptions = {}) { let options; return { name: "vite-plugin-icons", enforce: "post", configResolved(config) { options = Object.assign({ scale: 1.2, defaultStyle: "", defaultClass: "", compiler: config.plugins.find((i) => i.name === "vite-plugin-vue2") ? "vue2" : "vue3" }, userOptions); }, resolveId(id) { if (isIconPath(id)) { return normalizeIconPath(id).replace(/\.vue$/i, "").replace(/^\//, ""); } return null; }, async load(id) { if (isIconPath(id)) return await generateComponentFromPath(id, options) || null; return null; } }; } var src_default = VitePluginIcons; export { VitePluginIcons as Plugin, ViteIconsResolver, src_default as default };