unplugin-icons
Access thousands of icons as components on-demand universally.
Usage
安装
以 Vite + Vue 而言,我们需要安装插件,以及我们想要包含的图标集合,在这里可以找到所有有效的图标 iconesJs
$ npm i -D @iconify-json/twemoji unplugin-icons
配置和使用
在 vite.config.ts 中添加插件,然后就可以在任意的 .vue 文件当中使用所安装对应集合的图标
import Icons from 'unplugin-icons/vite'
export default defineConfig({
plugins: [
Icons({ /* options */ }),
],
})<script setup>
import Twemoji1stPlaceMedal from '~icons/twemoji/1st-place-medal'
</script>
<template>
<Twemoji1stPlaceMedal style="font-size: 2em; color: red" />
</template>原理
一些原理
Virtual Module
Virtual Modules Convention 是 Vite 插件 API 提供的一个功能,可以提供虚拟路径转换,将原本不存在的路径,转为插件内部提供的内容
对于 unplugin-icons 而言,就是将虚拟路径,例如上面的 ~icons/twemoji/1st-place-medal,转为 SVG 资源
在 resolveId 钩子中,通过 isIconPath 进行虚拟路径的匹配:
unplugin/unplugin-icons/src/index.ts
Lines 9 to 20 #5022512
9
10
11
12
13
14
15
16
17
18
19
20
命中之后,由 load 钩子提供返回的内容:
unplugin/unplugin-icons/src/index.ts
Lines 51 to 60 #5022512
51
52
53
54
55
56
57
58
59
60
在 generateComponentFromPath 中,主要做的有两件事情
- 根据 collection, icon 获得 SVG 字符串
来源于:iconify/iconify 这个库的内部暴露出来的方法
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- 调用
@vue/compiler-sfc将 SVG 字符串编译当作 Vue 组件进行编译,得到字符串
unplugin/unplugin-icons/src/core/compilers/vue3.ts
Lines 5 to 21 #5022512
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
所以,对于路径 ~icons/twemoji/1st-place-medal 而言,会被编译成如下字符串:
`import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
const _hoisted_1 = {
viewBox: "0 0 36 36",
width: "1.2em",
height: "1.2em"
}
const _hoisted_2 = /*#__PURE__*/_createElementVNode("path", {
fill: "#55ACEE",
d: "m18 8l-7-8H0l14 17l11.521-4.75z"
}, null, -1 /* HOISTED */)
const _hoisted_3 = /*#__PURE__*/_createElementVNode("path", {
fill: "#3B88C3",
d: "m25 0l-7 8l5.39 7.312l1.227-1.489L36 0z"
}, null, -1 /* HOISTED */)
const _hoisted_4 = /*#__PURE__*/_createElementVNode("path", {
fill: "#FFAC33",
d: "M23.205 16.026c.08-.217.131-.448.131-.693a2 2 0 0 0-2-2h-6.667a2 2 0 0 0-2 2c0 .245.05.476.131.693c-3.258 1.826-5.464 5.307-5.464 9.307C7.335 31.224 12.111 36 18.002 36s10.667-4.776 10.667-10.667c0-4-2.206-7.481-5.464-9.307z"
}, null, -1 /* HOISTED */)
const _hoisted_5 = /*#__PURE__*/_createElementVNode("path", {
fill: "#9E5200",
d: "M19.404 18.6h-1.721l-2.73 2.132a.528.528 0 0 0-.112.28v1.178c0 .186.15.354.337.354h1.795v8.414c0 .188.15.355.355.355h2.076c.186 0 .336-.168.336-.355V18.954c0-.186-.149-.354-.336-.354z"
}, null, -1 /* HOISTED */)
const _hoisted_6 = [
_hoisted_2,
_hoisted_3,
_hoisted_4,
_hoisted_5
]
function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("svg", _hoisted_1, [..._hoisted_6]))
}
export default { name: 'twemoji-1st-place-medal', render }
/* vite-plugin-components disabled */`这个字符串是一个有效的 ESM 导出,成功被赋值给了 Twemoji1stPlaceMedal,被当作 Vue 组件使用
<script setup>
import Twemoji1stPlaceMedal from '~icons/twemoji/1st-place-medal'
</script>
<template>
<Twemoji1stPlaceMedal style="font-size: 2em; color: red" />
</template>最终渲染为一个 SVG,即