Nuxt Icon
基于 Iconify,为你的 Nuxt 应用添加 200,000 多个开箱即用的图标。
特性 ✨
- 支持 Nuxt 3
- SSR(服务端渲染)友好
- 通过 Iconify 支持 200,000 个开源矢量图标
- 支持 CSS 模式 / SVG 模式
- 支持自定义 SVG(通过 Vue 组件或本地 SVG 文件)
!注意 你当前正在查看该模块的
v1.0版本,这是为了更好的开发体验和性能而进行的完全重写。如果你是从v0.6迁移过来,请查看 此 PR 获取完整的变更列表。
安装 ⛓️
运行以下命令将模块添加到你的项目中
npx nuxi module add icon
就是这样,现在你可以在组件中使用 <Icon /> 了!
✨ 如果你使用 VS Code,可以使用 @antfu 开发的 Iconify IntelliSense 插件
手动安装
你可以手动安装该模块
npm i -D @nuxt/icon
更新你的 nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@nuxt/icon'
]
})
如果你安装了旧版的 nuxt-icon 模块,建议将其从 modules 列表中移除。
使用方法 👌
属性
name(必填):图标名称或全局组件名称size:图标大小(默认:1em)mode:图标渲染模式(svg或css,默认:css)
属性:
当使用 Iconify 图标时,会根据渲染模式创建 <span> 或 <svg>,你可以传入原生元素的所有 属性。
<Icon name="uil:github" style="color: black" />
TailwindCSS v4:
当在 css 模式下使用 TailwindCSS v4 时,你应该在 Nuxt 应用配置中设置 cssLayer
// ~/app.config.ts
export default defineAppConfig({
icon: {
mode: 'css',
cssLayer: 'base'
}
})
Iconify 数据集
你可以使用来自 https://icones.js.org 集合中的任何图标名称
<Icon name="uil:github" />
它支持 i- 前缀(例如 i-uil-github)。
强烈建议通过以下方式在本地安装图标数据
npm i -D @iconify-json/collection-name
例如,要使用 uil:github 图标,请使用 @iconify-json/uil 安装其集合。这样图标可以从本地或无服务器函数中提供,无论是在 SSR 还是客户端,速度都更快且更可靠。
!注意 你可能也知道可以安装
@iconify/json包来包含所有图标。不建议这样做,因为它会增加服务器包体积并降低构建性能。如果你选择这样做,建议明确指定你需要安装的集合名称。export default defineNuxtConfig({ modules: ['@nuxt/icon'], icon: { serverBundle: { collections: ['uil', 'mdi'] // <!--- this } } })
Vue 组件
当 name 与全局注册的组件匹配时,它将被渲染为该组件(此时 mode 将被忽略)
<Icon name="MyComponent" />
请注意,MyComponent 需要位于 components/global/ 文件夹中(参见 示例)。
!提示 你也可以通过以下方式更改组件名称
export default defineNuxtConfig({ icon: { componentName: 'NuxtIcon' } })
自定义本地集合
你可以使用本地 SVG 文件来创建自定义的 Iconify 集合。
例如,将图标的 SVG 文件放在你选择的文件夹中,例如 ./assets/my-icons
assets/my-icons
├── foo.svg
├── bar-outline.svg
在你的 nuxt.config.ts 中,向 icon.customCollections 添加一个条目
export default defineNuxtConfig({
modules: [
'@nuxt/icon'
],
icon: {
customCollections: [
{
prefix: 'my-icon',
dir: './assets/my-icons',
// if you want to include all the icons in nested directories:
// recursive: true,
},
],
},
})
!注意 如果你运行的是带有新
app目录的 Nuxt 4,assets 目录应为'./app/assets/*'而不是'./assets/*'。
然后你可以这样使用图标
<template>
<Icon name="my-icon:foo" />
<Icon name="my-icon:bar-outline" />
</template>
你也可以传入一个完整的自定义 IconifyJSON 对象
export default defineNuxtConfig({
modules: [
'@nuxt/icon'
],
icon: {
customCollections: [
{
prefix: 'paid-icons',
icons: {
'nuxt': { body: '<path d="M281.44 ... />' },
},
width: 512,
height: 512,
}
],
},
})
请注意,自定义本地集合需要有一个服务器来提供 API。当设置 ssr: false,或者使用 nuxt generate 生成静态应用时(等同于 ssr: false),提供者将默认使用 Iconify API(其中没有你的自定义图标)。如果你想构建一个带有服务器端点的 SPA,可以显式设置 provider: 'server'
export default defineNuxtConfig({
modules: [
'@nuxt/icon'
],
ssr: false,
icon: {
provider: 'server', // <-- this
customCollections: [
{
prefix: 'my-icon',
dir: './assets/my-icons'
},
],
},
})
或者,如果你想完全禁用动态图标获取并仅使用来自 客户端包 的图标,可以设置 provider: 'none'
export default defineNuxtConfig({
icon: {
provider: 'none',
clientBundle: {
scan: true,
// ...or other bundle options
},
}
})
区分大小写的自定义集合
在 v1.10 之前,由于 Iconify 之前约定的限制,所有自定义图标都会被标准化为 kebab-case(短横线命名)并伴有警告。感谢 Iconify 方面的更新,从 v1.10 开始,你可以选择使用区分大小写的自定义集合来跳过标准化。
export default defineNuxtConfig({
modules: [
'@nuxt/icon'
],
icon: {
customCollections: [
{
prefix: 'my-icon',
dir: './assets/my-icons',
normalizeIconName: false, // <-- this
},
],
},
})
这使得你可以使用 assets/my-icons/FooBar.svg 作为 my-icon:FooBar。
normalizeIconName 默认为 true 以实现向后兼容,并将在未来的主要版本中默认关闭。有关更多背景信息,请参阅 #265。
图标自定义
要更新 <Icon /> 的默认大小(1em),请创建一个带有 icon.size 属性的 app.config.ts。
使用 icon.class 属性更新 <Icon /> 的默认类名(.icon),对于无头图标,请设置 icon.class: ''。
你也可以利用 icon.aliases 属性定义别名,以便更轻松地更换图标。
!注意 请注意,运行时配置应使用
app.config.ts而不是nuxt.config.ts。
// app.config.ts
export default defineAppConfig({
icon: {
size: '24px', // default <Icon> size applied
class: 'icon', // default <Icon> class applied
mode: 'css', // default <Icon> mode applied
aliases: {
'nuxt': 'logos:nuxt-icon',
},
cssLayer: 'base' // set the css layer to inject to
}
})
图标将具有 24px 的默认大小,并且可以使用 nuxt 图标
<Icon name="nuxt" />
默认情况下,此模块将创建一个服务器端点 /api/_nuxt_icon/:collection 以从你的本地服务器包中提供图标(你可以通过将 icon.localApiEndpoint 设置为所需路径来覆盖默认路径)。当请求本地包中不存在的图标时,它将回退到请求 官方 Iconify API。你可以通过将 icon.fallbackToApi 设置为 false 来禁用回退,或者设置 你自己的 Iconify API 并更新 icon.iconifyApiEndpoint 指向你自己的 API 端点。
使用 customize 选项自定义图标
customize 选项允许你修改项目中使用的 SVG 图标的各个方面。通过此选项,你可以:
- 更改描边宽度
- 更改颜色
- 更改动画持续时间
- 更改不透明度
- 添加额外形状
通过这些自定义选项,你可以完全控制 SVG 内容。
在组件中,你可以定义一个 customize 函数来对图标应用各种修改。
<script setup lang="ts">
// Define the customize function to modify SVG content
const customize = (content: string, name: string, prefix: string, provider: string) => {
if (prefix !== 'tabler') return content // Ignore Prefix
return content
.replace(/stroke-width="[^"]*"/g, `stroke-width="2"`) // Change stroke width to 2
.replace(/stroke="[^"]*"/g, `stroke="#FF5733"`) // Change stroke color to red
.replace(/fill="[^"]*"/g, `fill="#FF5733"`) // Change fill color to red
.replace(/animation-duration="[^"]*"/g, `animation-duration="1s"`) // Change animation duration to 1s (for animated icons)
.replace(/opacity="[^"]*"/g, `opacity="0.8"`);// Change opacity to 0.8
}
</script>
<template>
<Icon name="tabler:star" :customize="customize" />
</template>
<!-- You can also use `:customize="false"` to disabled the global customization function per-usage -->
在应用配置文件中
或者,你可以在 app.config.ts 文件中全局应用这些自定义设置。
// app.config.ts
export default defineAppConfig({
icon: {
customize: (content: string, name: string, prefix: string, provider: string) => {
// ...
},
}
})
通过此配置,整个应用程序中的所有图标都将一致地应用这些自定义设置。
服务器包(Server Bundle)
从 @nuxt/icon v1.0 开始,我们引入了服务器包概念,从 Nuxt 服务器端点提供图标。这保持了客户端包的精简,能够按需加载图标,同时具备使用构建时未知的图标的所有动态功能。
服务器包模式:local
此模式会将你在本地安装的图标集合(如 @iconify-json/*)作为动态块打包到你的服务器包中。集合数据将按需加载,仅当你的客户端从该集合请求图标时才会加载。
服务器包模式:remote
在 @nuxt/icon v1.2 中引入,你现在可以使用 remote 服务器包从远程 CDN 提供图标。
export default defineNuxtConfig({
modules: [
'@nuxt/icon'
],
icon: {
serverBundle: 'remote',
},
})
或者你可以指定远程提供者
export default defineNuxtConfig({
modules: [
'@nuxt/icon'
],
icon: {
serverBundle: {
remote: 'jsdelivr', // 'unpkg' or 'github-raw', or a custom function
}
},
})
这将使服务器请求 https://cdn.jsdelivr.net.cn/npm/@iconify-json/ph/icons.json 以在运行时获取图标,而不是将它们与你的服务器打包在一起。
在底层,它不再将 () => import('@iconify-json/ph/icons.json') 捆绑到你的服务器中,而是会使用类似 () => fetch('https://cdn.jsdelivr.net.cn/npm/@iconify-json/ph/icons.json').then(res => res.json()) 的逻辑,集合不会被内联。
当服务器包体积受限时(例如在无服务器或 Worker 环境中),这非常有用。
服务器包模式:auto
这是默认选项,该模块会根据你的部署环境在 local 和 remote 之间进行选择。除非你部署到无服务器或 Worker 环境(如 Vercel Edge 或 Cloudflare Workers),否则将优先使用 local。
外部化图标 JSON
默认情况下,Nitro 会将你本地安装的图标集合(如 @iconify-json/*)作为动态块打包到服务器包中。当你拥有大量图标时,这可能会使打包过程缓慢且占用大量内存。你可以通过将 icon.serverBundle.externalizeIconsJson 设置为 true 来改为外部化图标 JSON 文件。
export default defineNuxtConfig({
modules: [
'@nuxt/icon'
],
icon: {
serverBundle: {
externalizeIconsJson: true,
}
},
})
请注意,这要求你的生产环境 Node.js 服务器能够导入 JSON 文件(注意,截至 Node.js v22,JSON 模块仍为实验性功能)。在最终构建中,它将包含类似 () => import('@iconify-json/ph/icons.json', { with: { type: 'json' } }) 的语句。
另请注意,在某些不支持动态导入的无服务器环境(如 Cloudflare Workers)中,无论此选项如何设置,它们都将被内联。
当启用 icon.serverBundle.remote 时,此选项将被忽略。
完全禁用服务器包
如果你想完全禁用服务器包,可以将 icon.serverBundle 设置为 false,并将 provider 设置为 iconify
export default defineNuxtConfig({
modules: [
'@nuxt/icon'
],
icon: {
provider: 'iconify',
serverBundle: false,
},
})
这将导致客户端每次请求图标时都会向 Iconify API 发送请求。除非其他选项不可行,否则我们不建议这样做。
客户端包(Client Bundle)
对于你知道会频繁使用的图标,你可以将它们打包到你的客户端包中以避免网络请求。
export default defineNuxtConfig({
modules: [
'@nuxt/icon'
],
icon: {
clientBundle: {
// list of icons to include in the client bundle
icons: [
'uil:github',
'logos:vitejs'
],
// scan all components in the project and include icons
scan: true,
// include all custom collections in the client bundle
includeCustomCollections: true,
// guard for uncompressed bundle size, will fail the build if exceeds
sizeLimitKb: 256,
},
},
})
includeCustomCollections 将把你在 icon.customCollections 中定义的所有自定义集合包含在客户端包中。它默认是禁用的,但在设置 ssr: false 时会自动启用。
扫描组件
当启用 scan 时,模块将扫描项目中的所有组件并将所使用的图标包含在客户端包中。这将显著减少静态已知图标所需的网络请求数量,但根据项目中使用的图标数量,也可能会增加客户端包的体积。
你还可以微调扫描目标,例如:
export default defineNuxtConfig({
modules: [
'@nuxt/icon'
],
icon: {
clientBundle: {
scan: {
// note that when you specify those values, the default behavior will be overridden
globInclude: ['components/**/*.vue', /* ... */],
globExclude: ['node_modules', 'dist', /* ... */],
},
},
},
})
!提示 扫描依赖于静态分析,这意味着只有字面上的用法才会被检测到。请尽可能避免动态构造图标名称。
<template> <!-- Avoid this --> <Icon :name="`carbon:${dark ? 'moon' : 'sun'}`" /> <!-- Prefer this --> <Icon :name="dark ? 'carbon:moon' : 'carbon:sun'" /> </template>
渲染函数
你可以在渲染函数中使用 Icon 组件(如果你创建函数式组件会很有用),为此你可以从 #components 导入它
import { Icon } from '#components'
查看 <MyIcon> 组件的示例
<script setup>
import { Icon } from '#components'
const MyIcon = h(Icon, { name: 'uil:twitter' })
</script>
<template>
<p><MyIcon /></p>
</template>
在组件测试中渲染图标
在浏览器内组件测试环境(如 Vitest Browser Mode 或 Cypress Component Testing)中,用于按需获取图标的内部 Nuxt 服务器路由是 不可用 的。因此,图标可能在测试期间无法渲染。
为了确保图标在组件测试中正确渲染,请配置 @nuxt/icon 在测试模式下运行以使用 客户端包。
注意 使用 @nuxt/ui 的项目必须执行此操作才能在组件测试期间看到任何 UI 图标。
要求
- 在本地安装你使用的图标集合(例如
@iconify-json/lucide)。 - 使用客户端包时,图标 不会 从远程获取。
仅测试配置
当 NODE_ENV === 'test' 时,在 Nuxt 配置中条件性地切换到客户端包
export default defineNuxtConfig({
modules: [
'@nuxt/icon',
],
icon: process.env.NODE_ENV !== 'test'
? {
// Production or development icon configuration
}
: {
// Disable all network icon fetching in component tests
provider: 'none',
clientBundle: {
// Explicitly include dynamically constructed icons
icons: ['lucide:check'],
// Scan your app and Nuxt UI runtime for static icon usage
scan: {
globInclude: [
'{app,shared}/**',
'node_modules/@nuxt/ui/dist/**',
],
globExclude: ['node_modules'],
},
},
},
})
提示
- 动态生成的图标名称可能无法被静态扫描检测到——请将它们显式添加到
icons中。- 对于大型应用,考虑将仅供测试的配置移至
vitest.config.ts或cypress.config.ts以保持清晰。
贡献 🙏
- 克隆此仓库
- 使用
pnpm install安装依赖(使用corepack enable安装pnpm,了解更多) - 运行
npm run dev:prepare以生成类型存根。 - 使用
npm run dev在开发模式下启动 演练场。
致谢 💌
- @benjamincanac(初始版本)
- @cyberalien(创建了 Iconify)