通过 100 多个技巧学习 Nuxt!
发布·  

Nuxt Icon v1 发布

探索 Nuxt Icon v1 - 为您的 Nuxt 项目提供的现代、通用且可定制的图标解决方案。

图标对于现代 Web 界面至关重要。它们简化导航,阐明功能并增强视觉吸引力。然而,高效地实现图标涉及可伸缩性、动态加载和服务器端渲染 (SSR) 兼容性等挑战。

为了应对这些挑战,我们开发了 Nuxt Icon v1 — 一种为 Nuxt 项目量身定制的通用、现代解决方案。通过建立在已建立的图标渲染技术并引入新颖的方法,Nuxt Icon 弥合了性能、可用性和灵活性之间的差距。

在这篇文章中,我们将探讨图标渲染的挑战、图标解决方案的演变,以及 Nuxt Icon 如何结合这些方法的最佳方面,为开发人员提供无缝体验。


为什么图标具有挑战性?

乍一看,图标似乎很简单 - 它们本质上只是微小的图像元素,可以增强用户界面,提供视觉提示并提高可用性。

Icons Showcases

但是,从工程角度来看,它们带来了一些挑战。理想的图标应该是

  • 可着色的:可适应主题和配色方案。
  • 可伸缩的:在各种尺寸和分辨率下清晰渲染。
  • 可管理的:图标集可以包含数百或数千个图标。
  • 高效捆绑的:最大限度地减少网络请求。
  • 优化加载的:影响应用程序性能和用户体验。
  • 动态的:支持动态加载用户生成或运行时定义的图标。

Engineering Challenges with Icons

满足所有这些需求需要精心设计的解决方案,以平衡权衡。让我们探讨图标解决方案的演变以及它们如何应对这些挑战。


图标解决方案之旅

多年来,开发人员尝试了各种技术来高效地渲染图标。让我们探讨这些解决方案的演变以及它们面临的挑战。

1. <img> 标签:早期

最直接的解决方案:使用 <img> 标签。这是 Web 早期时代的常用方法。

您需要托管您的图像资源,并使用 <img> 标签链接到该图像,指定其宽度和高度。它很简单,不需要设置或运行时依赖项,并且在浏览器中原生工作。

Solution 1

但是,存在一些缺点。图像可能会变得像素化、缺乏颜色控制并且无法很好地缩放。每个图标都是单独的图像文件,会导致许多网络请求,这可能会很慢,尤其是在 HTTP 1.1 时代。在图像下载之前,您可能会看到图标闪烁不可见,这会损害用户体验。最后,编写起来非常冗长,因为您需要指定图像的完整路径并管理相对路径。这解释了为什么这种方法在现代网站上很少使用。


2. Web 字体:图标字体

作为图标演变的下一步,Web 字体成为一种流行的解决方案。字体本质上是矢量化的且可着色的,使其自然适合图标。

图标集提供商通常将其图标编译成特殊的字体文件,为每个图标分配一个唯一的 Unicode 字符。这附带一个 CSS 文件,该文件将这些 Unicode 值映射到特定的图标类。

这种方法的优点是显而易见的:它易于使用、可着色、可伸缩,并且只需要一个请求即可加载所有图标。

Solution 2

但是,也存在一些缺点。预先加载大型字体文件可能会很慢,并且自定义图标集具有挑战性。此外,您可能会在字体加载之前遇到图标闪烁不可见的情况,因为没有可用的后备字体。


3. 内联 SVG:基于组件的图标

随着现代前端框架的出现,重用 HTML 元素变得容易得多。这导致了直接内联 SVG 标签作为组件的想法。

为了支持这种方法,许多图标集提供了针对每个框架定制的包装器包。例如,MDI 图标使用共享组件并将图标数据作为 props 传递,而 Tabler 图标为每个图标提供专用组件。

由于这些是 SVG,因此它们本质上是可着色、可伸缩的,并保留了 SVG 的所有功能。通常,图标会捆绑到应用程序中,消除额外的网络请求并确保它们是 SSR 友好的,并且在首次渲染时可见。

Solution 3

但是,这种方法也有其缺点。它会生成大量 SVG DOM 元素,当使用许多图标时,这会影响性能。它还会增加捆绑包大小,并且需要每个图标集和框架组合的特定集成支持,从而导致一定程度的供应商锁定。这使得切换到不同的图标集或框架具有挑战性。

尽管存在这些权衡,但这种方法在今天被广泛采用,因为对于大多数项目来说,切换图标集或框架并不是频繁的必需品。


4. Iconify 运行时:动态 API 访问

Iconify 通过聚合 100 多个集合中的超过 200,000 个图标,彻底改变了图标的使用方式。它的运行时解决方案通过 API 动态获取图标,从而可以动态访问任何图标,而无需预先捆绑。

这非常适合渲染来自用户提供的内容或其他您在构建时不知道的动态内容的图标。它也超级容易设置,因为您甚至可以将其用作 CDN,而无需任何构建工具。

Solution 4

虽然此方法提供了很大的灵活性,但它确实带来了一些权衡。它引入了运行时依赖项,这意味着图标仅在 JavaScript 加载且图标数据获取后才会呈现。这种方法还对服务器端渲染 (SSR) 和缓存层(例如渐进式 Web 应用程序 (PWA) 中使用的那些)提出了挑战。


5. 按需组件图标

借助 Iconify 的统一界面和 Vite 的按需方法,我们开发了 unplugin-icons。此工具允许您按需导入任何图标作为组件。

作为 unplugin,它支持所有流行的构建工具,包括 Vite、webpack 和 rspack。我们为流行的框架(如 Vue、React、Svelte 和 Solid)提供编译器。借助 Iconify,您可以在任何框架中使用任何图标,从而最大限度地减少供应商锁定。

Solution 5

虽然此技术与之前的组件图标解决方案具有相同的优点和缺点,但与构建工具的集成使我们能够提供完整的 Iconify 集合,同时仅交付您实际使用的图标。但是,DOM 元素管理等运行时问题仍然存在。


6. 纯 CSS 图标

作为开发 UnoCSS 的副作用,我们发现了完全在 CSS 中嵌入图标的潜力,从而产生了 纯 CSS 图标 的创新解决方案。

此方法涉及将 SVG 图标内联为数据 URL,并提供单个类来显示图标。通过一些调整,这些图标变得可着色、可伸缩,甚至能够显示 SVG 动画。

浏览器可以缓存 CSS 规则,并且每个图标仅需要 一个 DOM 元素 即可渲染。此方法将图标与单个 CSS 文件一起交付,无需额外的请求。由于它是纯 CSS,因此图标与 UI 的其余部分一起显示,无需运行时,并且自然地与 SSR 一起工作——您的服务器在服务器端不需要任何额外的工作。

Solution 6

唯一的缺点是 SVG 内部元素的完整自定义的缺乏以及需要在构建时捆绑图标,这不是动态的。


在 Nuxt 中集成的挑战

虽然我会说 纯 CSS 图标按需组件图标 对于大多数静态用法来说已经足够了,但 Nuxt 作为一个功能齐全的框架,为了高效地集成图标,有更多的要求

  • SSR/CSR:Nuxt 在服务器端渲染 (SSR) 和客户端渲染 (CSR) 模式下工作。我们非常关心最终用户体验,并且我们希望确保图标立即渲染而不会闪烁。
  • 动态图标:在 Nuxt Content 等集成中,内容可以在运行时或从外部来源提供,我们在构建时并不知道这些内容。我们希望确保我们有能力很好地与这些情况集成。
  • 性能:我们希望确保图标被高效地捆绑,并且图标的加载针对最佳性能进行了优化。
  • 自定义图标:虽然 Iconify 提供了广泛的图标选择,但我们也意识到项目拥有自己的图标集或想要使用 Iconify 中不可用的付费图标是很常见的。支持自定义图标对我们的用户至关重要。

Nuxt Integration Challenges and Solutions

考虑到这些要求,让我们重新审视我们之前讨论的解决方案,看看它们是如何堆叠的。

对于动态图标,Iconify 运行时脱颖而出,成为一种可行的选择。它允许动态获取图标,使其适用于在构建时未知的内容。但是,它有其缺点。对运行时依赖项的依赖意味着它不能与 SSR 无缝集成,并且它不支持自定义图标,因为请求被定向到 Iconify 的服务器,而这些服务器无权访问我们的本地图标设置。

相反,纯 CSS 图标提供出色的性能和 SSR 兼容性。它们确保图标立即渲染而不会闪烁,并且被高效地捆绑。但是,当涉及到动态图标时,它们就显得不足了,因为它们需要在构建时捆绑,并且缺乏适应运行时内容更改的灵活性。

平衡这些权衡确实具有挑战性。那么,为什么不利用两种方法的优势呢?通过了解这些权衡,我们可以更好地理解 Nuxt Icon v1 提供的平衡解决方案。


Nuxt Icon v1 发布:两种世界的平衡

凭借 Nuxt 模块系统的灵活性,Nuxt Icon 结合了两个世界的优点:CSS 图标的即时渲染和 Iconify 图标的动态获取。这种双重方法提供了一种通用、现代且可定制的图标解决方案,可以无缝适应您的项目需求。

双渲染模式

为了解决渲染方法中的权衡,Nuxt Icon 引入了一个通用的 <Icon> 组件,该组件同时支持 CSS 和 SVG 模式,这两种模式都是 SSR 友好的。根据您的自定义需求,您可以在每种图标的这些模式之间切换。

在 CSS 模式下,图标在 SSR 期间包含在 CSS 中,确保它们立即渲染而没有任何运行时成本。在 SVG 模式下,图标在 SSR 期间内联为 HTML,提供相同的即时渲染优势。这两种方法都确保图标在初始屏幕上立即显示,而不会有任何延迟,从而提供无缝的用户体验。

Dual rendering mode


图标捆绑包

动态图标带来了独特的挑战,尤其是在高效加载它们方面。为了解决这个问题,我们利用了 Iconify 的 API,该 API 允许我们通过网络请求按需提供任何图标。但是,仅依赖此 API 可能会引入延迟,尤其是在服务器在地理位置上远离您的用户的情况下。

为了缓解这种情况,我们引入了图标捆绑包的概念。我们可以将常用图标直接捆绑到 客户端捆绑包 中。这确保了这些图标立即渲染,而无需额外的网络请求。但是,由于捆绑包大小可能会增加,因此捆绑所有可能的图标是不可行的。

鉴于 Nuxt 是一个全栈框架,我们可以通过引入 服务器捆绑包 来实现平衡。在服务器端,捆绑包大小不是问题,这使我们可以包含更广泛的图标集。在 SSR 期间,可以快速获取这些图标并根据需要发送到客户端。此设置确保常用图标的高性能,同时仍然提供从 Iconify 提供任何图标作为后备的灵活性。

通过结合客户端捆绑用于静态图标和服务器端捆绑用于动态图标,我们在性能和灵活性之间实现了最佳平衡。

Icon Bundles in Nuxt Icons


数据流

这是一个数据流图,说明了 Nuxt Icon 如何请求图标数据

  1. 您可以使用 <Icon> 组件并提供图标 name
  2. Nuxt Icon 将首先检查图标是否在 客户端捆绑包 或 SSR 有效负载中可用(SSR 中已知的图标将显示在有效负载中)。如果是,则图标将立即渲染。
  3. 如果客户端不可用该图标,则 Nuxt Icon 将从随您的 Nuxt 应用程序一起提供的服务器 API 中获取图标数据。在服务器端点内部,它将从 服务器捆绑包 查询以查看图标是否可用。
  4. 在此期间,涉及多个缓存系统。服务器端点缓存、HTTP 缓存和客户端缓存,以确保图标被高效且快速地获取。由于图标数据不会频繁更改,因此我们使用硬缓存策略来确保最佳性能。
  5. 当客户端和服务器都不知道图标时(动态图标),服务器端点将回退到 Iconify API 以获取图标数据。由于服务器端点被缓存,因此 Iconify API 将仅针对每个唯一图标调用一次,无论有多少客户端请求它,以节省双方的资源。

Nuxt Icon Requesting Data flow

这种分层方法确保了高效的图标交付,平衡了速度和灵活性,同时尽可能动态。并平衡了每种解决方案之间的权衡。


立即试用 Nuxt Icon

Nuxt Icon v1 代表了多年来图标渲染创新的顶峰。无论您是构建动态应用程序、静态网站还是介于两者之间的任何内容,Nuxt Icon 都可以适应您的需求。

通过运行以下命令,可以轻松地将 Nuxt Icon 添加到您的项目中

npx nuxi module add icon

然后,在您的 Vue 组件中导入 <Icon> 组件,并按照 Iconify 的约定 提供图标 name

<template>
  <Icon name="ph:arrow-down-duotone" />
</template>

通过 文档 了解更多信息,试用其功能,并告诉我们您的想法。我们很高兴看到 Nuxt Icon 如何改变您的项目!

祝您 Nuxting 愉快 ✨