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

@wisdomgarden/torque-icons

v0.1.6

Published

Torque Design icons — the Wisdom Garden icon set — one lazily loaded ES module per icon, plus a React <Icon> that resolves them by name.

Readme

@wisdomgarden/torque-icons

Torque Design 的图标集 —— Wisdom Garden 设计系统的一部分(另两个是 @wisdomgarden/torque 组件库与 @wisdomgarden/torque-styles 设计 token)。每个图标是一个独立的、按需加载的 ES 模块,外加一个按名字解析图标的 React <Icon>。

为什么是「一图标一模块」

图标名是运行时字符串(<Icon name={someVariable} />),打包器没法静态分析,所以 tree-shaking 帮不上忙。这个包换一条路:把 598 个图标各自编译成独立模块,再由包内的 loader 用一个前缀固定、只有名字是变量的动态 import 去取:

import(`./generated/${name}.js`);

消费方的打包器见到这个形状,会对 dist/generated/ 建一个 context module,把 598 个模块各自切成一个 chunk。页面渲染哪几个图标,就只下载哪几个。

实测(Next 16 + Turbopack):598 个图标 → 598 个 chunk;一个渲染 4 个图标的页面只下载 4 个,单个图标 gzip 中位数约 0.6 KB。

对比之下,把全部图标合成一个 sprite 或一份 CSS 都是约 380 KB,不管用几个都得下完。这个形态还让"往包里加图标"对已有消费方的运行时成本是 0。

安装

pnpm add @wisdomgarden/torque-icons

用法

零配置 —— 装完直接用:

import { Icon } from '@wisdomgarden/torque-icons';

<Icon name="search" />
<Icon name={`file/${upload.type}`} />        {/* 运行时名字照常工作 */}
<Icon name="common-entry/my-notes" useOriginalColor width={44} height={44} />

<Icon> 内部用 React.lazy + Suspense 解析图标:组件在渲染期就拿到、实际模块按需加载。 所以图标参与服务端渲染 —— React 会在流式阶段把图标补进 HTML,不用等 hydration, 而且这条路是框架无关的(next/dynamic 本质就是这个加上 Next 特有的预加载)。

只有当图标要来自别的地方(自建 CDN、宿主自己的图标体系)时才需要注册:

import { setIconLoader } from '@wisdomgarden/torque-icons';

setIconLoader(name => fetchMyIcon(name));

必须在第一个 <Icon> 渲染前调用 —— 解析结果按名字缓存。

useOriginalColor

默认会把图标里所有非 none 的 fill / stroke 改写成 currentColor,于是图标跟随父级文字颜色(暗色主题、hover、a11y 主题全部自动跟上)。

自带配色的图标必须传 useOriginalColor —— 比如「色块底 + 白色图形」这类(common-entry/*)、品牌 logo(activity/fill/google-meeting)、带渐变的图标。不传的话所有形状会被统一成一个颜色,糊成色块。

这个改写发生在渲染期而不是构建期,因为 useOriginalColor 是调用点的 prop,不是图标的固有属性 —— 这套图标里有 17 个既按原色用、又按 currentColor 用。构建期出两套变体的话模块数会翻倍,只为把一个布尔值挪出渲染路径,不划算。

改写逻辑由全部 598 个模块共享一份(color-override.tsx),所以每个图标自己的 chunk 里只有它的图形。

新增图标

  1. 把 svg 放进 src/svgs/(子目录即名字前缀,src/svgs/file/document.svg → "file/document")
  2. pnpm build

构建会重新生成组件模块,并把 IconName 联合类型写进 src/icon-names.ts。

API

| 导出 | 说明 | | ---------------------------- | ----------------------------------------------- | | Icon | 图标组件 | | setIconLoader(loader) | 启动时注册一次 | | getIconLoader() | 读取当前 loader | | loadIcon(/loader 子入口) | 包内置的按需加载器 | | iconNames | 全部图标名数组 | | IconName | 图标名联合类型(仅用于补全,运行时接受任意字符串) |

setIconLoader 是模块级状态,所以本包必须单实例 —— 被 @wisdomgarden/torque 声明为 peerDependency 正是为此。

构建产物

| 路径 | 内容 | | ------------------------ | ------------------------------- | | dist/generated/**.js | 598 个图标模块,一图标一文件 | | dist/color-override.js | 共享的颜色改写逻辑 | | dist/loader.js | 那行动态 import | | dist/index.js | Icon / setIconLoader / 类型 |

生成产物不带 sourcemap:598 个图标模块与 icon-names 是从 src/generated/ 编译来的, 而那个目录本身就是构建产物(gitignore),map 指向任何检出都不存在的文件 —— 连本地调试 都没价值。去掉后 tarball 从 856 KB 降到 414 KB;5 个手写模块的 map 保留,合计约 8 KB。

dist/loader.js 里的动态 import 带 @vite-ignore:本包自己的 Vite 构建不能碰它。Vite 默认会交给 @rollup/plugin-dynamic-import-vars,那个插件在构建期就把变量 import 展开成静态 map —— 在这里会得到空 map(图标是各自独立的 entry),运行时必然抛 Unknown variable dynamic import;而且它只支持一层路径,file/document 这种两级名字本来也过不去。这行必须原样送到消费方,由消费方的打包器处理。