Iconify离线图标使用记录

2,612 阅读3分钟

前言

离线图标引入方式有多种, 可通过单图标 图标集合 离线api服务器方式来部署

通过新建项目来验证是否满足离线要求/打包后大小

vue项目创建

使用vite创建vue项目, 核心依赖unocss/@iconify/json/@iconify/vue

  "dependencies": {
    "vue": "^3.4.29"
  },
  "devDependencies": {
    "@vitejs/plugin-vue-jsx": "^4.0.1",
    "unocss": "^0.64.0",
    "@iconify/vue": "^4.1.2",
    "@iconify/json": "^2.2.268",
    "@vitejs/plugin-vue": "^5.0.5",
    "typescript": "^5.2.2",
    "vite": "^5.3.1",
    "vue-tsc": "^2.0.21"
  }

uno.config.ts

import { defineConfig, presetUno, presetIcons } from 'unocss';

export default defineConfig({
  presets: [presetUno(), presetIcons()],
});

核心presetIcons, 详见官网: unocss.dev/presets/ico… tailwindcss同理

这里提到If you prefer to install all the icon sets available on Iconify at once (~130MB):

使用iconify/json包会将图标打包 是否真的是这样呢 来测试一下

// test.tsx
import { defineComponent } from 'vue';

export default defineComponent({
  name: 'Test',
  setup() {
    return () => <div class="i-file-icons:config-typescript w-1em h-1em"></div>;
  },
});
<template>
  <div class="flex justify-center items-center">
    <div class="i-hugeicons:electric-home-02 w-3em h-3em"></div>
    <Test />
  </div>
</template>

<script setup lang="ts">
  import Test from './test';
</script>

图标都是随便在iconify找的

image.png

可以正常加载图标

image.png

打包看看 是否会在线请求还是离线图标

可以看到没有网络请求

image.png

两个图标都打包进了css

image.png

但是这种方式只适合固定的静态的图标 如果动态加载会怎样呢?

动态图标

将图标放在服务器返回 可以看到已经无法渲染了

<template>
  <div class="flex justify-center items-center">
    <div v-for="icon in icons" class="w-3em h-3em" :class="icon"></div>
  </div>
</template>

<script setup lang="ts">
  import { ref, onMounted } from 'vue';

  function wait(ms: number) {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }

  const icons = ref<string[]>([]);
  onMounted(async () => {
    await wait(1000);
    await fetch('http://localhost:8080/test').then(async (response) => {
      const iconList = await response.json();
      icons.value = iconList;
    });
  });
</script>

image.png

使用全部图标集

上面使用了三个图标集, 直接添加全部图标集

import { createApp } from 'vue';
import App from './App.vue';
import 'uno.css';

import { addCollection } from '@iconify/vue';
import mdi from '@iconify/json/json/mdi.json';
import vscode from '@iconify/json/json/vscode-icons.json';
import hugeicons from '@iconify/json/json/hugeicons.json';

addCollection(mdi);
addCollection(vscode);
addCollection(hugeicons);

createApp(App).mount('#app');
<template>
  <div class="flex justify-center items-center">
    <div v-for="icon in icons" class="w-3em h-3em">
      <Icon :icon="icon" />
    </div>
  </div>
</template>

<script setup lang="ts">
  import { ref, onMounted } from 'vue';
  import { Icon } from '@iconify/vue';

  function wait(ms: number) {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }

  const icons = ref<string[]>([]);
  onMounted(async () => {
    await wait(1000);
    await fetch('http://localhost:8080/test').then(async (response) => {
      const iconList = await response.json();
      icons.value = iconList;
    });
  });
</script>

可以正常加载, 没有网络请求

image.png

但是!! 打包看看

添加图标集后 image.png

可以看到图标集里的图片全部被打包进js了

image.png

添加图标集前 image.png

80K 加了三个图标飙升至9M大小 这种全量级别的添加肯定是不合适

使用单个图标

上面使用了三个图标集, 单个引入的话不能从iconify/json中引入, 需要下载对应的@iconify/icons-图标集npm包

pnpm i @iconify/icons-mdi -D
pnpm i @iconify/icons-vscode-icons -D
// 剩下一个没有npm包 也是第一次见  绝大部分都是有的

mian.ts

import { createApp } from 'vue';
import App from './App.vue';
import 'uno.css';
import { addIcon } from '@iconify/vue';

import icon1 from '@iconify/icons-mdi/language-typescript';
import icon2 from '@iconify/icons-vscode-icons/file-type-typescript';

addIcon('mdi:language-typescript', icon1);
addIcon('vscode-icons:file-type-typescript-official', icon2);

createApp(App).mount('#app');

这里需要注意图标名称必须对应, 我这里是后台返回图标两者必须相等

可以看到没添加离线图标的走的还是在线 剩下的都是离线

image.png

看看打包大小

image.png

只多了2K左右的大小 图标打包进js

image.png

总结

使用unocss/tailwindcss+@iconify/json 图标会被打包进css 不适合动态(后端返回)图标

<div class="i-file-icons:config-typescript w-1em h-1em"></div>

使用图标集/单个图标 图标会打包进js 可动态(后端返回)图标

<template>
  <Icon icon="xxx" />
</template>

<script>
import { Icon } from '@iconify/vue';
</script>

Icon在能找到本地图标(name对应)或图标集情况使用本地(离线)图标 否则会使用线上(cdn)图标

自动引入图标

安装依赖

pnpm i -D unplugin-icons

vite.config.ts

    import { defineConfig } from 'vite';
    import vue from '@vitejs/plugin-vue';
    import Unocss from 'unocss/vite';
    import useJsx from '@vitejs/plugin-vue-jsx';
    import Icons from 'unplugin-icons/vite';

    export default defineConfig({
      plugins: [vue(), Unocss(), useJsx(), Icons({ compiler: 'vue3' })],
    });

如果使用了ts, 需要添加类型  任选其一 <https://github.com/unplugin/unplugin-icons/issues/235>

    1. tsconfig.json
    "types": ["unplugin-icons/types/vue"]

    2. .d.ts

/// <reference types="unplugin-icons/types/vue" />


vue文件

<template>
  <div class="flex justify-center items-center">
    <IconParkFileStaff />
  </div>
</template>

<script setup lang="ts">
  import IconParkFileStaff from '~icons/icon-park/file-staff';
</script>

可以在这里找到导入

image.png

打包大小:

image.png

正常离线

image.png