npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

unplugin-tdesign-icons

v0.2.0

Published

An unplugin for on-demand importing TDesign icons (vue / vue-next / react / web-components). Auto rewrites `import { XxxIcon } from 'tdesign-icons-xxx'` to the exact icon module, avoiding bundling all 2000+ icons.

Downloads

409

Readme

unplugin-tdesign-icons

NPM version

On-demand import of TDesign Icons for Vue 2 (tdesign-icons-vue), Vue 3 (tdesign-icons-vue-next), React (tdesign-icons-react) and Web Components (tdesign-icons-web-components).

在任意构建工具中按需引入 TDesign 图标,只为实际用到的图标打包。

TDesign 图标库包含 2354 个图标,直接从桶入口 import { CloseIcon } from 'tdesign-icons-vue-next' 会一次性引入全部图标,导致:

  • 开发期:Vite 预打包生成 ~13.5MB 的依赖文件(包含全部 2354 个图标),浏览器每次刷新都要拉取/解析,冷启动慢、请求多;
  • 构建期:需要 transform 全部 2354 个模块(实测约 5.6s)。

本插件在编译期把具名图标导入自动改写为单图标深层导入,只打包实际用到的图标(实测约 16 个模块、0.5s):

// 源码(写法不变)
import { CloseIcon } from 'tdesign-icons-vue-next'

// 插件自动改写为
import CloseIcon from 'tdesign-icons-vue-next/esm/components/close.js'

特性

  • 🚀 按需引入:只转换显式导入的图标,绝不全量引入;
  • 🧩 四套框架支持:Vue 2 / Vue 3 / React / Web Components 按框架绑定插件工厂,互不干扰;
  • 🔌 多构建工具:基于 unplugin,一套代码支持 Vite / Rollup / Rolldown / Webpack / esbuild / Rspack;
  • 🗺️ 零配置映射:直接从图标包内置的 esm/manifest.js 读取 图标名 ↔ 文件名 映射,无需手动维护;
  • 🛡️ 安全解析:基于 es-module-lexer 精确解析 import 语句,字符串/注释中的伪导入不会被误伤;
  • 🎯 SFC 模板改写<script setup>(Vue 2.7+/Vue 3)与 Vue 2 经典 <script> 中的静态 <Icon name="..." /> 自动改写为单图标组件 <SneerIcon />
  • ✂️ 智能混用:同一行里图标 + 非图标(如 IconBase)导入会拆成多条,非图标保留桶导入。

Install

pnpm add -D unplugin-tdesign-icons
pnpm add tdesign-icons-vue-next # 按需替换为对应框架的图标包
// vite.config.ts
import { TDesignIconsVueNext } from 'unplugin-tdesign-icons/vite'

export default defineConfig({
  plugins: [
    TDesignIconsVueNext({ /* options */ }),
  ],
})

// rollup.config.js
import { TDesignIconsReact } from 'unplugin-tdesign-icons/rollup'

export default {
  plugins: [
    TDesignIconsReact({ /* options */ }),
  ],
}

// rolldown.config.js
import { TDesignIconsReact } from 'unplugin-tdesign-icons/rolldown'

export default {
  plugins: [
    TDesignIconsReact({ /* options */ }),
  ],
}

// webpack.config.js
const { TDesignIconsVueNext } = require('unplugin-tdesign-icons/webpack')

module.exports = {
  plugins: [
    TDesignIconsVueNext({ /* options */ }),
  ],
}

// rspack.config.js
const { TDesignIconsReact } = require('unplugin-tdesign-icons/rspack')

module.exports = {
  plugins: [
    TDesignIconsReact({ /* options */ }),
  ],
}

// esbuild.config.js
import { build } from 'esbuild'
import { TDesignIconsReact } from 'unplugin-tdesign-icons/esbuild'

build({
  plugins: [
    TDesignIconsReact({ /* options */ }),
  ],
})

每个构建工具子路径都导出 TDesignIconsVueTDesignIconsVueNextTDesignIconsReactTDesignIconsWebComponents。框架参数由工厂绑定,不需要传入 framework

Usage

插件启用后,业务代码继续从对应的 TDesign 图标包导入,插件会在编译期自动改写为单图标深层导入:

<script setup>
import { CloseIcon } from 'tdesign-icons-vue-next'
</script>

<template>
  <CloseIcon />
</template>

Vue SFC 模板改写(<Icon name="..." />

对 Vue 3 <script setup> 或 Vue 2 经典 <script>(Options API)单文件组件,插件会把模板里的静态 <Icon name="..." /> 改写为单图标组件,并自动注入对应的深层导入:

<script setup>
import { Icon } from 'tdesign-icons-vue-next'
</script>
<template>
  <Icon name="sneer" size="large" />
</template>

会被编译为:

<script setup>
import SneerIcon from 'tdesign-icons-vue-next/esm/components/sneer.js'
</script>
<template>
  <SneerIcon size="large" />
</template>

Vue 2 经典 <script>(Options API)写法同样支持,改写后会自动更新 components 注册(Vue 2 运行时通过 components 选项解析模板里的组件名):

<script>
import { Icon } from 'tdesign-icons-vue'
export default {
  name: 'App',
  components: { Icon }
}
</script>
<template>
  <Icon name="sneer" size="large" />
</template>

会被编译为:

<script>
import SneerIcon from 'tdesign-icons-vue/esm/components/sneer.js'
export default {
  name: 'App',
  components: { SneerIcon }
}
</script>
<template>
  <SneerIcon size="large" />
</template>

规则与说明:

  • 只处理静态 name:动态名称(:name="iconName")和不存在的图标名称保持原样,Icon 导入/注册会继续保留;
  • name 支持多种写法sneerChart3Dchart-3d 均可正确解析到对应图标;
  • 图标名以 Icon 结尾的(如 file-iconFileIconIcon)也能正确处理;
  • 模板里同时有可改写与不可改写<Icon> 时,Icon 桶导入保留给不可改写的那部分;
  • 经典 <script>components: { Icon } 注册:没有注册时 <Icon> 被视为全局/自定义组件,模板不做改写(普通 import 改写仍生效);
  • 需要 @vue/compiler-sfc:优先使用项目自身已安装的版本(与 vue 依赖对齐),未安装时该功能自动降级,仅保留普通的 import 改写。

示例(Examples)

参考 unplugin-icons,本仓库在 examples/ 提供了可直接运行的示例工程,覆盖 Vue 2 / Vue 3 / React / Web Components 与 Vite / Webpack / Rollup / Rolldown / Rspack / esbuild 等主流组合:

| 示例 | 说明 | | --- | --- | | examples/vite-vue3 | Vite + Vue 3,import { TDesignIconsVueNext } from 'unplugin-tdesign-icons/vite' | | examples/vite-vue2 | Vite + Vue 2,import { TDesignIconsVue } from 'unplugin-tdesign-icons/vite' | | examples/vite-react | Vite + React,import { TDesignIconsReact } from 'unplugin-tdesign-icons/vite' | | examples/vite-web-components | Vite + Web Components,import { TDesignIconsWebComponents } from 'unplugin-tdesign-icons/vite' | | examples/webpack-vue3 | Webpack 5 + Vue 3,const { TDesignIconsVueNext } = require('unplugin-tdesign-icons/webpack')(CJS) | | examples/rollup-react | Rollup + React,import { TDesignIconsReact } from 'unplugin-tdesign-icons/rollup' | | examples/rolldown-react | Rolldown + React,import { TDesignIconsReact } from 'unplugin-tdesign-icons/rolldown' | | examples/rspack-react | Rspack + React,import { TDesignIconsReact } from 'unplugin-tdesign-icons/rspack' | | examples/esbuild-react | esbuild + React,import { TDesignIconsReact } from 'unplugin-tdesign-icons/esbuild' |

示例通过 pnpm workspace 的 workspace:* 引用仓库根包,首次运行前需要在仓库根目录安装依赖并构建插件;具体步骤和各构建工具的命令详见 examples/README.md

验证

以下构建工具均已通过集成测试,确认按需导入生效(只打包用到的图标、不再含桶入口):

| 构建工具 | 结果 | | --- | --- | | Vite | ✅ | | Rollup | ✅(配合 @rollup/plugin-node-resolve) | | Rolldown | ✅ | | Webpack | ✅ | | Rspack | ✅ | | esbuild | ✅ |

选项

以注释形式展示全部可配置项(用法与 unplugin-icons 一致,直接传入插件工厂):

TDesignIconsVueNext({
  // 构建时下载 CDN sprite 到应用产物,并为 Icon 注入本地 URL
  localIcons: {
    // sourceUrl 默认从当前图标包的 svg-sprite 模块读取
    // 只保留这些图标到本地 sprite;未配置时保留全部图标
    // icons: ['close', 'add'],
    fileName: 'assets/tdesign-icons.js',
    publicPath: './',
  },
  // 组件库封装标签 → 桶导出的映射
  // aliases: { 'my-t-icon': 'Icon' },
  // 只处理路径包含这些片段的文件
  // includeSource: ['src'],
  // 跳过的路径
  // exclude: [/node_modules/],
})

| 名称 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | localIcons | boolean \| LocalIconsOptions | false | 下载 CDN svg-sprite 到构建产物,并为 Icon 注入本地 URL;对象形式可配置图标筛选、下载源、文件名和公开路径 | | localIcons.icons | string[] | 未配置 | 本地 sprite 中保留的图标名称,例如 ['close', 'add'];配置后未列出的图标不会存在于本地 sprite | | aliases | Record<string, string> | vue/vue-next 默认 { 't-icon': 'Icon' },其余 {} | 组件库封装标签 → 桶导出的映射,localIcons 据此处理 <t-icon> 等自定义标签 | | includeSource | string[] | [] | 只处理路径包含这些片段的文件 | | exclude | (string \| RegExp)[] | [/node_modules/] | 跳过的路径 |

运行时离线:localIcons 开关

默认情况下,TDesign 的 <Icon name="xxx" /> 组件会在浏览器运行时从 CDN 拉取全量 svg-sprite。在内网或浏览器无法访问外网时,图标会渲染不出来。

开启 localIcons 后,插件会在构建期完成以下处理:

  1. 从已安装图标包的 esm/svg-sprite/svg-sprite.js 读取 CDN_ICONFONT_URLCDN_SVGSPRITE_URL
  2. 下载 sprite 脚本,把 symbol 的 t-icon- 前缀转换为自定义 URL 模式需要的 ID;
  3. 输出 assets/tdesign-icons.js,并给 <Icon> / <t-icon> 注入该地址和 loadDefaultIcons=false

这保留了原始 name,所以静态、Vue 动态绑定和 React 表达式都可以使用本地 sprite。构建机需要能访问 CDN;浏览器运行时不再请求 CDN。

如果只需要本地保留部分图标,可以配置 localIcons.icons。插件仍会为识别到的图标标签注入本地 sprite URL,因此未列入列表的图标在本地 sprite 中不存在时不会显示,这是预期行为。

// vite.config.ts
import { defineConfig } from 'vite'
import { TDesignIconsVueNext } from 'unplugin-tdesign-icons/vite'

export default defineConfig({
  plugins: [
    TDesignIconsVueNext({
      localIcons: {
        icons: ['close', 'add'],
        fileName: 'assets/tdesign-icons.js',
        publicPath: '/my-app/',
        // sourceUrl: 'https://your-cdn.example.com/icons.js',
      },
    }),
  ],
})
<template>
  <Icon name="sneer" />
  <Icon :name="currentIcon" />
</template>
<script setup>
import { Icon } from 'tdesign-icons-vue-next'
</script>

构建时会为标签注入:

<template>
  <Icon name="sneer" url="/my-app/assets/tdesign-icons.js" :load-default-icons="false" />
  <Icon :name="currentIcon" url="/my-app/assets/tdesign-icons.js" :load-default-icons="false" />
</template>
<script setup>
import { Icon } from 'tdesign-icons-vue-next'
</script>

TDesign Vue 组件库的 <t-icon> 封装

TDesign Vue 组件库为了方便用户习惯,把 Icon 封装成了 <t-icon>(全局注册)。 vue / vue-next 框架开启 localIcons 后默认也会识别这种写法,并注入相同的本地 URL:

import { createApp } from 'vue'
import { Icon } from 'tdesign-vue-next'

createApp(App).use(Icon).mount('#app')
<!-- 源码:TDesign Vue 组件库的 <t-icon> 封装 -->
<template>
  <t-icon name="sneer" />
</template>

如果项目没有安装并全局注册 TDesign Vue 组件库,仅使用 tdesign-icons-vue-next, 需要显式提供 TIcon 组件绑定:

<script setup>
import { Icon as TIcon } from 'tdesign-icons-vue-next'
</script>
<template>
  <t-icon name="sneer" />
</template>

构建后等价于:

<template>
  <t-icon name="sneer" url="./assets/tdesign-icons.js" :load-default-icons="false" />
</template>

如果你的组件库把 Icon 封装成了其它标签(例如 React 的 <MyTIcon>),可以用 aliases 选项自定义:

// vite.config.ts
import { TDesignIconsReact } from 'unplugin-tdesign-icons/vite'

export default defineConfig({
  plugins: [
    // 给 <MyTIcon name="xxx" /> 注入本地 sprite URL
    TDesignIconsReact({ localIcons: true, aliases: { 'my-t-icon': 'Icon' } }),
  ],
})
  • 支持 Vue 2 / Vue 3 / React 的静态与动态 name,以及导入别名的 kebab-case 标签。
  • Vue / Vue Next 默认识别 TDesign Vue 组件库全局注册的 <t-icon>;其它框架可通过 aliases 配置封装标签。
  • publicPath 默认是 ./。应用部署到子路径或使用嵌套路由时,应显式设置为应用公开 base。
  • 已有 url / loadDefaultIcons 会被本地配置覆盖;字符串和注释中的标签文本不会被修改。
  • Web Components 的 <t-icon name="xxx" /> 本身就使用本地 JSON 渲染、不依赖 CDN,无需开启。

工作原理

  1. es-module-lexer 精确解析出代码中所有 import { ... } from 'tdesign-icons-xxx' 语句;
  2. 从图标包内置的 esm/manifest.js 构建 导出名 → 文件名(stem) 映射(导出名 = manifest.icon + 'Icon');
  3. 未开启 localIcons 时,Vue SFC 静态 <Icon name> 继续按原逻辑转换为深层单图标组件;
  4. 开启 localIcons 时,下载并发射 sprite,通过字符串掩码扫描为 Icon 和别名标签覆盖本地 URL;
  5. CloseIcon 等具名导入仍改写为 tdesign-icons-xxx/esm/components/close.js,不受 sprite 本地化影响;
  6. 同一语句中的 IconIconBaseIconFont 等非单图标导出保留桶导入。

⚠️ 改写后的深层导入带 .js 后缀,Node/SSR/严格 ESM 环境下也能正常解析。

License

MIT