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-offline-iconify

v1.1.0

Published

Bundle only the Iconify icons used by your app, with sprite and Iconify runtime modes.

Readme

unplugin-offline-iconify

按需打包项目实际使用的 Iconify 图标,生产环境无需从 Iconify API 下载图标。支持 SVG sprite 和 Iconify runtime 两种输出协议。

Vite adapter 在 transform(code, id) 阶段复用已经读取的源码,识别静态的 prefix:name,并为每个图标注入可去重的虚拟模块,不再在启动时额外全量读取源码。其他 adapter 因 JSON/SFC loader 顺序不同,当前使用共享扫描器的构建前全扫 fallback,避免向原始非 JS 内容追加 import;不能据此宣称它们已消除全量扫描。

安装

默认的 sprite 模式没有客户端运行时依赖:

pnpm add -D unplugin-offline-iconify

只有使用 iconify 模式时才需要安装可选 peer dependency:

pnpm add @iconify/iconify

配置

| 参数 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | mode | 'sprite' \| 'iconify' | 'sprite' | 选择 SVG symbol 或 Iconify addCollection() 协议 | | cwd | string | 'src' | 扫描根目录,相对于启动命令的工作目录 | | include | string \| string[] | '**/*.{js,jsx,ts,tsx,vue,json,astro}' | 参与 transform 扫描的文件 | | exclude | string \| string[] | [] | 额外排除规则,node_modules 始终排除 | | safelist | string[] | [] | 动态图标白名单,使用完整的 prefix:name |

以下以 Vite 为例。Webpack、Rollup、Rspack、esbuild、Farm、Astro 和 Nuxt 继续使用包内对应 adapter;Astro/Nuxt 选择 Vite builder 时走 Vite transform 路径,当前端到端验证以 Vite 为主。

Vite 版本兼容

  • Vite 6:真实 dev transform、生产 build 与 HMR hook 基线。
  • Vite 8:真实生产 build 同时覆盖 sprite 和 iconify;Vite 8 改用 Rolldown/Oxc 后,本插件使用的标准 resolveId、load、transform 和 HMR API 无需分支实现。
  • Vite 8 要求 Node.js 20.19+ 或 22.12+;这是 Vite 自身要求,不是 sprite/iconify mode 的差异。
  • peer 范围为 vite >=3 <9。Vite 3–5 保留兼容入口,但当前自动化矩阵直接验证的是 Vite 6 和 Vite 8。

Vite 8 的主要影响在构建器内部:Rollup/esbuild 分工变成 Rolldown/Oxc。图标扫描复用 Vite 传给插件的 code,不调用 transformWithEsbuild,因此不依赖旧的 esbuild 转换 API。

Vite 用户无需安装 esbuild。包中的 esbuild peer 是 optional,仅在显式使用 unplugin-offline-iconify/esbuild adapter 时由该类项目自行提供。

// vite.config.ts
import OfflineIconify from 'unplugin-offline-iconify/vite'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [
    OfflineIconify({
      // mode: 'sprite',
      safelist: ['mdi:account'],
    }),
  ],
})

在应用入口保留一次基础虚拟模块导入。静态图标也会通过 transform 自动注入图标子模块;显式导入可确保仅使用 safelist 时注册器仍会加载。

import 'virtual:offline-iconify'

TypeScript 项目可在环境声明中加入:

/// <reference types="unplugin-offline-iconify/client" />

Sprite 模式(默认)

默认行为与 1.0.1 兼容:插件把离线图标写入隐藏的 SVG sprite,每个 symbol ID 都是原始的 prefix:name。它不需要 @iconify/iconify。

function Icon(props: { name: string, size?: string }) {
  return (
    <svg style={{ width: props.size ?? '1em', height: props.size ?? '1em' }}>
      <use href={`#${props.name}`} />
    </svg>
  )
}

export function App() {
  return <Icon name="ant-design:account-book-twotone" size="40px" />
}

开发时新增、替换或删除图标会沿 Vite 模块图更新;虚拟图标模块带有 dispose 清理逻辑,不会在 sprite 中保留已删除且不再被其他模块引用的 symbol。

Iconify runtime 模式

此模式把同一份离线图标集合交给 @iconify/iconify 的 addCollection(),适合现有代码已经使用 renderSVG()、Iconify DOM 或其他 Iconify API 的项目。

// vite.config.ts
import OfflineIconify from 'unplugin-offline-iconify/vite'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [
    OfflineIconify({
      mode: 'iconify',
      safelist: ['mdi:account'],
    }),
  ],
})
import { renderSVG } from '@iconify/iconify'
import 'virtual:offline-iconify'

const svg = renderSVG('mdi:account')
if (svg)
  document.body.appendChild(svg)

所有静态识别或 safelist 中的图标数据均来自本地 @iconify/json 并随应用打包,虚拟模块不会请求远程图标。动态图标必须放入 safelist,否则 renderSVG() 无法从离线存储找到它。由于 Iconify runtime 只有追加注册 API,Vite 开发环境在源码变更时使用 full reload 清空旧存储,确保删除图标后状态正确。

从 sprite 迁移到 Iconify runtime

  1. 安装 @iconify/iconify。
  2. 将插件配置改为 mode: 'iconify'。
  3. 保留 import 'virtual:offline-iconify'。
  4. 把 <use href="#prefix:name"> 封装替换为现有的 renderSVG() 或 Iconify 组件/API。
  5. 将运行期拼接的图标名加入 safelist。

如果项目仍使用 <symbol>/<use>,无需迁移,也无需安装 @iconify/iconify。

静态扫描限制

以下内容可以自动识别并去重:

const icon = 'mdi:home'
const repeated = 'mdi:home'

运行时拼接无法静态确定,需要 safelist:

const icon = `mdi:${route.meta.icon}`
OfflineIconify({
  safelist: ['mdi:home', 'mdi:account'],
})

无效的 prefix 或不存在的图标名会被忽略。Iconify alias 会按请求名称解析并固化翻转、旋转等变换,因此两种 mode 使用完全相同的最终图形。

License

MIT