react-icons-sprite 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/icon.js CHANGED
@@ -2,8 +2,7 @@ import { jsx } from "react/jsx-runtime";
2
2
 
3
3
  //#region src/icon.tsx
4
4
  const ReactIconsSpriteIcon = ({ iconId,...rest }) => {
5
- const spriteHref = "__SPRITE_URL_PLACEHOLDER__";
6
- const iconHref = `${spriteHref}#${iconId}`;
5
+ const iconHref = `__SPRITE_URL_PLACEHOLDER__#${iconId}`;
7
6
  return /* @__PURE__ */ jsx("svg", {
8
7
  height: "1em",
9
8
  width: "1em",
@@ -2,11 +2,6 @@ import { Plugin } from "vite";
2
2
 
3
3
  //#region src/vite/plugin.d.ts
4
4
  type ReactIconsSpriteVitePluginOptions = {
5
- /**
6
- * Append a cache-busting query parameter to the emitted sprite URL.
7
- * Example: { spriteUrlVersion: "1.2.3" } -> "/assets/react-icons-sprite.svg?v=1.2.3"
8
- */
9
- spriteUrlVersion?: string;
10
5
  /**
11
6
  * If passed, this exact string will be used for the emitted file name.
12
7
  * If fileName is omitted, name will be generated as `react-icons-sprite-[hash].svg.
@@ -1,3 +1,4 @@
1
+ import { createHash } from "node:crypto";
1
2
  import { createElement } from "react";
2
3
  import { renderToStaticMarkup } from "react-dom/server";
3
4
  import * as t from "@babel/types";
@@ -64,8 +65,7 @@ const replaceJsxWithSprite = (ast, localNameToImport, iconLocalName, register) =
64
65
  if (!meta) return;
65
66
  if (isAlreadyIcon(name)) return;
66
67
  path.node.name = t.jSXIdentifier(iconLocalName);
67
- const hasIconId = path.node.attributes.some((a) => t.isJSXAttribute(a) && t.isJSXIdentifier(a.name, { name: "iconId" }));
68
- if (!hasIconId) path.node.attributes.unshift(t.jSXAttribute(t.jSXIdentifier("iconId"), t.stringLiteral(`ri-${meta.exportName}`)));
68
+ if (!path.node.attributes.some((a) => t.isJSXAttribute(a) && t.isJSXIdentifier(a.name, { name: "iconId" }))) path.node.attributes.unshift(t.jSXAttribute(t.jSXIdentifier("iconId"), t.stringLiteral(`ri-${meta.exportName}`)));
69
69
  usedLocalNames.add(local);
70
70
  anyReplacements = true;
71
71
  register(meta.pack, meta.exportName);
@@ -147,11 +147,10 @@ const PRESENTATION_ATTRS = new Set([
147
147
  ]);
148
148
  const ATTR_RE = /([a-zA-Z_:.-]+)\s*=\s*"([^"]*)"/g;
149
149
  const renderOneIcon = async (pack, exportName) => {
150
- const mod = await import(
150
+ const Comp = (await import(
151
151
  /* @vite-ignore */
152
152
  pack
153
- );
154
- const Comp = mod[exportName];
153
+ ))[exportName];
155
154
  if (!Comp) throw new Error(`Icon export not found: ${pack} -> ${exportName}`);
156
155
  const id = `ri-${exportName}`;
157
156
  const html = renderToStaticMarkup(createElement(Comp));
@@ -163,17 +162,13 @@ const renderOneIcon = async (pack, exportName) => {
163
162
  if (PRESENTATION_ATTRS.has(key)) attrs.push(`${key}="${v}"`);
164
163
  }
165
164
  const inner = html.replace(/^<svg[^>]*>/i, "").replace(/<\/svg>\s*$/i, "");
166
- const stylePart = attrs.length ? ` ${attrs.join(" ")}` : "";
167
- const symbol = `<symbol id="${id}" viewBox="${viewBox}"${stylePart}>${inner}</symbol>`;
168
165
  return {
169
166
  id,
170
- symbol
167
+ symbol: `<symbol id="${id}" viewBox="${viewBox}"${attrs.length ? ` ${attrs.join(" ")}` : ""}>${inner}</symbol>`
171
168
  };
172
169
  };
173
170
  const buildSprite = async (icons) => {
174
- const rendered = await Promise.all(Array.from(icons).map(({ pack, exportName }) => renderOneIcon(pack, exportName)));
175
- const symbols = rendered.map((r) => r.symbol).join("");
176
- return `<svg xmlns="http://www.w3.org/2000/svg"><defs>${symbols}</defs></svg>`;
171
+ return `<svg xmlns="http://www.w3.org/2000/svg"><defs>${(await Promise.all(Array.from(icons).map(({ pack, exportName }) => renderOneIcon(pack, exportName)))).map((r) => r.symbol).join("")}</defs></svg>`;
177
172
  };
178
173
  const createCollector = () => {
179
174
  const set = /* @__PURE__ */ new Map();
@@ -196,7 +191,7 @@ const createCollector = () => {
196
191
  //#endregion
197
192
  //#region src/vite/plugin.ts
198
193
  const reactIconsSprite = (options = {}) => {
199
- const { spriteUrlVersion, fileName } = options;
194
+ const { fileName } = options;
200
195
  const collector = createCollector();
201
196
  return {
202
197
  name: "vite-plugin-react-icons-sprite",
@@ -225,6 +220,7 @@ const reactIconsSprite = (options = {}) => {
225
220
  },
226
221
  async generateBundle(_options, bundle) {
227
222
  const spriteXml = await buildSprite(collector.toList());
223
+ const generatedHash = createHash("sha256").update(spriteXml).digest("hex").slice(0, 8);
228
224
  const emitFileOptions = {
229
225
  type: "asset",
230
226
  source: spriteXml
@@ -232,8 +228,7 @@ const reactIconsSprite = (options = {}) => {
232
228
  if (fileName) emitFileOptions.fileName = fileName;
233
229
  else emitFileOptions.name = "react-icons-sprite.svg";
234
230
  const assetId = this.emitFile(emitFileOptions);
235
- const name = this.getFileName(assetId);
236
- const finalUrl = spriteUrlVersion && spriteUrlVersion.length > 0 ? `/${name}?v=${encodeURIComponent(spriteUrlVersion)}` : `/${name}`;
231
+ const finalUrl = `/${this.getFileName(assetId)}?v=${encodeURIComponent(generatedHash)}`;
237
232
  for (const [, item] of Object.entries(bundle)) if (item.type === "chunk" && typeof item.code === "string") {
238
233
  if (item.code.includes(PLACEHOLDER)) item.code = item.code.replaceAll(PLACEHOLDER, finalUrl);
239
234
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-icons-sprite",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "",
@@ -49,20 +49,21 @@
49
49
  "react-icons": ">= 5"
50
50
  },
51
51
  "devDependencies": {
52
- "@babel/generator": "7.28.3",
53
- "@babel/parser": "7.28.3",
54
- "@babel/traverse": "7.28.3",
55
- "@babel/types": "7.28.2",
56
- "@biomejs/biome": "2.2.2",
52
+ "@babel/generator": "7.28.5",
53
+ "@babel/parser": "7.28.5",
54
+ "@babel/traverse": "7.28.5",
55
+ "@babel/types": "7.28.5",
56
+ "@biomejs/biome": "2.3.0",
57
57
  "@types/babel__generator": "7.27.0",
58
58
  "@types/babel__traverse": "7.28.0",
59
- "@types/react-dom": "19.1.9",
60
- "react": "19.1.1",
61
- "react-dom": "19.1.1",
59
+ "@types/node": "^24.9.1",
60
+ "@types/react-dom": "19.2.2",
61
+ "react": "19.2.0",
62
+ "react-dom": "19.2.0",
62
63
  "react-icons": "5.5.0",
63
- "tsdown": "0.14.2",
64
- "typescript": "5.9.2",
65
- "vite": "7.1.3"
64
+ "tsdown": "0.15.10",
65
+ "typescript": "5.9.3",
66
+ "vite": "7.1.12"
66
67
  },
67
68
  "keywords": [
68
69
  "vite",