@stephansama/vite-iconify-svgmap 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Stephan Randle
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,226 @@
1
+ <div align="center">
2
+
3
+ # [`@stephansama`](https://github.com/stephansama) / vite-iconify-svgmap
4
+
5
+ <!-- BADGE start -->
6
+
7
+ [![source code](https://img.shields.io/badge/Source-666666?style=flat&logo=github&label=Github&labelColor=211F1F)](https://github.com/stephansama/packages/tree/main/core/vite-iconify-svgmap)
8
+ [![documentation](https://img.shields.io/badge/Documentation-211F1F?style=flat&logo=Wikibooks&labelColor=211F1F)](https://packages.stephansama.info/api/@stephansama/vite-iconify-svgmap)
9
+ [![npm](https://img.shields.io/npm/v/%40stephansama%2Fvite-iconify-svgmap?logo=npm&logoColor=red&color=211F1F&labelColor=211F1F)](https://www.npmx.dev/package/@stephansama/vite-iconify-svgmap)
10
+ [![socket.dev](https://badge.socket.dev/npm/package/@stephansama/vite-iconify-svgmap)](https://socket.dev/npm/package/@stephansama/vite-iconify-svgmap/overview)
11
+ [![jsr](https://jsr.io/badges/@stephansama/vite-iconify-svgmap)](https://jsr.io/@stephansama/vite-iconify-svgmap)
12
+ [![npm downloads](https://img.shields.io/npm/dw/@stephansama/vite-iconify-svgmap?labelColor=211F1F)](https://www.npmx.dev/package/@stephansama/vite-iconify-svgmap)
13
+
14
+ [![@iconify/types](https://img.shields.io/badge/@iconify/types-2.0.0-026C9C.svg?logo=iconify&logoColor=ffffff&labelColor=026C9C)](https://npmx.dev/package/@iconify/types)
15
+ [![@tanstack/intent](https://img.shields.io/badge/@tanstack/intent-0.0.41-00a6f4.svg?logo=tanstack&logoColor=ffffff&labelColor=00a6f4)](https://npmx.dev/package/@tanstack/intent)
16
+ [![astro](https://img.shields.io/badge/astro-6.3.1-BC52EE.svg?logo=astro&logoColor=ffffff&labelColor=BC52EE)](https://npmx.dev/package/astro)
17
+ [![svelte](https://img.shields.io/badge/svelte-5.51.2-FF3E00.svg?logo=svelte&logoColor=ffffff&labelColor=FF3E00)](https://npmx.dev/package/svelte)
18
+ [![tsdown](https://img.shields.io/badge/tsdown-0.21.10-3178C6.svg?logo=rolldown&logoColor=ffffff&labelColor=3178C6)](https://npmx.dev/package/tsdown)
19
+ [![vite](https://img.shields.io/badge/vite-6.3.5-9135FF.svg?logo=vite&logoColor=ffffff&labelColor=9135FF)](https://npmx.dev/package/vite)
20
+
21
+ <!-- BADGE end -->
22
+
23
+ Vite plugin for generating iconify svg sprite maps in memory
24
+
25
+ </div>
26
+
27
+ ##### Table of contents
28
+
29
+ <details><summary>Open Table of contents</summary>
30
+
31
+ - [Installation](#installation)
32
+ - [Usage](#usage)
33
+ - [Astro](#astro)
34
+ - [SvelteKit](#sveltekit)
35
+ - [Vite](#vite)
36
+ - [Static imports](#static-imports)
37
+ - [Icons known while rendering](#icons-known-while-rendering)
38
+ - [Icon components](#icon-components)
39
+ - [Options](#options)
40
+ - [How it works](#how-it-works)
41
+
42
+ </details>
43
+
44
+ ## Installation
45
+
46
+ Install the plugin and at least one `@iconify-json/*` icon pack
47
+
48
+ ```sh
49
+ pnpm install -D @stephansama/vite-iconify-svgmap @iconify-json/logos
50
+ ```
51
+
52
+ Add the virtual module types to your `tsconfig.json`
53
+
54
+ ```json
55
+ {
56
+ "compilerOptions": {
57
+ "types": ["@stephansama/vite-iconify-svgmap/client"]
58
+ }
59
+ }
60
+ ```
61
+
62
+ ## Usage
63
+
64
+ ### Astro
65
+
66
+ The astro integration adds the vite plugin and writes sprites for icons
67
+ registered with `getIcon` once every page has rendered.
68
+
69
+ ```js
70
+ // astro.config.mjs
71
+ import iconifySvgmap from "@stephansama/vite-iconify-svgmap/astro/integration";
72
+ import { defineConfig } from "astro/config";
73
+
74
+ export default defineConfig({
75
+ integrations: [iconifySvgmap()],
76
+ });
77
+ ```
78
+
79
+ ### SvelteKit
80
+
81
+ Add the sveltekit plugins **after** `sveltekit()`:
82
+
83
+ ```js
84
+ // vite.config.js
85
+ import iconifySvgmap from "@stephansama/vite-iconify-svgmap/svelte/integration";
86
+ import { sveltekit } from "@sveltejs/kit/vite";
87
+ import { defineConfig } from "vite";
88
+
89
+ export default defineConfig({
90
+ plugins: [sveltekit(), iconifySvgmap()],
91
+ });
92
+ ```
93
+
94
+ SvelteKit prerenders in a worker thread and has no hook after prerendering,
95
+ so this plugin:
96
+
97
+ - receives `getIcon` calls made inside the prerender worker over an in
98
+ memory `BroadcastChannel`
99
+ - writes empty placeholder sprites for every installed icon pack when the
100
+ client build finishes, so the prerender crawler does not fail on
101
+ `<use href>` links to sprites that do not exist yet
102
+ - writes the real sprites (and removes unused placeholders) after
103
+ prerendering, before the adapter copies the client output
104
+
105
+ ### Vite
106
+
107
+ ```js
108
+ // vite.config.js
109
+ import iconifySvgmap from "@stephansama/vite-iconify-svgmap";
110
+ import { defineConfig } from "vite";
111
+
112
+ export default defineConfig({
113
+ plugins: [iconifySvgmap()],
114
+ });
115
+ ```
116
+
117
+ Static imports need nothing else. If you use `getIcon` in a server rendered
118
+ or prerendered app, call `writeSprites` with your client output directory
119
+ once rendering has finished:
120
+
121
+ ```js
122
+ import { writeSprites } from "@stephansama/vite-iconify-svgmap";
123
+
124
+ await writeSprites("dist");
125
+ ```
126
+
127
+ ### Static imports
128
+
129
+ Import an icon as `virtual:iconify-svgmap/<pack>/<icon>` to get its sprite
130
+ href. Unknown packs or icons fail the build.
131
+
132
+ ```astro
133
+ ---
134
+ import astro from "virtual:iconify-svgmap/logos/astro";
135
+ ---
136
+
137
+ <svg width="24" height="24"><use href={astro}></use></svg>
138
+ ```
139
+
140
+ Only the imported icons end up in a content hashed sprite per pack (for
141
+ example `/_astro/logos.BzUCTX55.svg`).
142
+
143
+ ### Icons known while rendering
144
+
145
+ When the icon name is only known while rendering (cms data, frontmatter,
146
+ loops), use `getIcon`:
147
+
148
+ ```astro
149
+ ---
150
+ import { getIcon } from "virtual:iconify-svgmap";
151
+
152
+ const href = getIcon(entry.data.iconPack, entry.data.icon);
153
+ ---
154
+
155
+ <svg width="24" height="24"><use href={href}></use></svg>
156
+ ```
157
+
158
+ `getIcon` records the icon in memory and returns
159
+ `/_iconify/<pack>.svg?v=<build>#<icon>`. The sprite is written after all pages
160
+ have rendered.
161
+
162
+ > \[!NOTE]
163
+ > `getIcon` icons must be rendered during the build, in the same process or
164
+ > one of its worker threads (static astro sites and prerendered sveltekit
165
+ > pages). Icons first requested at runtime by an on demand rendered route, or
166
+ > only by client side code, are not included in the written sprites. During
167
+ > development every icon works, including client rendered ones.
168
+
169
+ ### Icon components
170
+
171
+ Each framework subpath exports an `Icon` component that wraps `getIcon` in an
172
+ `<svg><use /></svg>`. They follow the same rules as `getIcon`: icons must be
173
+ rendered on the server during the build (for example astro pages or
174
+ server rendered svelte islands) and the sprites written afterwards (the astro
175
+ integration does this).
176
+
177
+ | Framework | Import |
178
+ | --------- | --------------------------------------------------------------------------- |
179
+ | astro | `import { Icon } from "@stephansama/vite-iconify-svgmap/astro/component";` |
180
+ | svelte 5 | `import { Icon } from "@stephansama/vite-iconify-svgmap/svelte/component";` |
181
+
182
+ ```astro
183
+ ---
184
+ import { Icon } from "@stephansama/vite-iconify-svgmap/astro/component";
185
+ ---
186
+
187
+ <Icon pack="logos" name="github-icon" size={24} title="GitHub" />
188
+ <Icon pack="heroicons" name="heart-solid" class="text-red-500" />
189
+ ```
190
+
191
+ ```svelte
192
+ <script>
193
+ import { Icon } from "@stephansama/vite-iconify-svgmap/svelte/component";
194
+ </script>
195
+
196
+ <Icon pack="logos" name="svelte-icon" size={24} title="Svelte" />
197
+ ```
198
+
199
+ | Prop | Default | Description |
200
+ | ------- | ------- | -------------------------------------------------------------------- |
201
+ | `pack` | | iconify pack, e.g. `logos` for `@iconify-json/logos` |
202
+ | `name` | | icon name inside the pack |
203
+ | `size` | `"1em"` | width and height |
204
+ | `title` | | accessible label; without it the icon gets `aria-hidden="true"` |
205
+ | ... | | any other svg attribute (`class`, `style`, ...) is passed to `<svg>` |
206
+
207
+ Icons that use `currentColor` follow the css `color` of the component.
208
+
209
+ ## Options
210
+
211
+ | Option | Default | Description |
212
+ | ------ | ------------- | -------------------------------------------------------------------------------------- |
213
+ | `dir` | `"_iconify"` | folder, relative to the output directory, for sprites of icons registered by `getIcon` |
214
+ | `root` | vite's `root` | directory used to resolve `@iconify-json/*` packages |
215
+
216
+ ## How it works
217
+
218
+ Nothing is written to the file system until the final output:
219
+
220
+ - icon packs are loaded lazily, only when an icon from the pack is requested
221
+ - during development sprites are generated in memory and served by the dev
222
+ server
223
+ - static imports are emitted as vite assets, so they are hashed and moved to
224
+ the output like any other asset
225
+ - `getIcon` usage is kept in an in memory registry and flushed once by
226
+ `writeSprites`
package/client.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ declare module "virtual:iconify-svgmap" {
2
+ /**
3
+ * Register an icon while rendering and return its sprite href, e.g.
4
+ * `/_iconify/<pack>.svg?v=<build>#<name>`
5
+ */
6
+ export function getIcon(pack: string, name: string): string;
7
+ }
8
+
9
+ declare module "virtual:iconify-svgmap/*" {
10
+ /**
11
+ * Sprite href for the imported icon, e.g.
12
+ * `/_astro/<pack>-<hash>.svg#<icon>`
13
+ */
14
+ const href: string;
15
+ export default href;
16
+ }
@@ -0,0 +1,11 @@
1
+ import { t as Options } from "../type-S4YO472i.mjs";
2
+ import { AstroIntegration } from "astro";
3
+
4
+ //#region src/astro.d.ts
5
+ /**
6
+ * Astro integration that adds the vite plugin and writes sprites for icons
7
+ * registered with `getIcon` once every page has been rendered
8
+ */
9
+ declare function iconifySvgmapIntegration(options?: Options): AstroIntegration;
10
+ //#endregion
11
+ export { iconifySvgmapIntegration as default };
@@ -0,0 +1,22 @@
1
+ import { n as iconifySvgmap, o as name, r as writeSprites } from "../src-CsllISxW.mjs";
2
+ //#region src/astro.ts
3
+ /**
4
+ * Astro integration that adds the vite plugin and writes sprites for icons
5
+ * registered with `getIcon` once every page has been rendered
6
+ */
7
+ function iconifySvgmapIntegration(options = {}) {
8
+ return {
9
+ name,
10
+ hooks: {
11
+ async "astro:build:done"({ dir, logger }) {
12
+ const written = await writeSprites(dir);
13
+ if (written.length > 0) logger.info(`wrote ${written.length} svg sprite(s)`);
14
+ },
15
+ "astro:config:setup"({ updateConfig }) {
16
+ updateConfig({ vite: { plugins: [iconifySvgmap(options)] } });
17
+ }
18
+ }
19
+ };
20
+ }
21
+ //#endregion
22
+ export { iconifySvgmapIntegration as default };
@@ -0,0 +1,24 @@
1
+ import { t as Options } from "./type-S4YO472i.mjs";
2
+ import { Plugin } from "vite";
3
+
4
+ //#region src/index.d.ts
5
+ declare const VIRTUAL_MODULE_ID = "virtual:iconify-svgmap";
6
+ /**
7
+ * Vite plugin that turns iconify icons into svg sprite maps
8
+ *
9
+ * - `import href from "virtual:iconify-svgmap/<pack>/<icon>"` resolves at build
10
+ * time and emits a content hashed `<pack>.svg` sprite through vite
11
+ * - `import { getIcon } from "virtual:iconify-svgmap"` registers icons while
12
+ * pages render; call {@link writeSprites} after rendering to write their
13
+ * sprites (the `/astro` integration does this for you)
14
+ */
15
+ declare function iconifySvgmap(options?: Options): Plugin;
16
+ /**
17
+ * Write sprites for every icon registered with `getIcon` into
18
+ * `<outDirectory>/<dir>/<pack>.svg`. call this after all pages have rendered.
19
+ *
20
+ * @returns The paths of the written sprites
21
+ */
22
+ declare function writeSprites(outDirectory: string | URL): Promise<string[]>;
23
+ //#endregion
24
+ export { type Options, VIRTUAL_MODULE_ID, iconifySvgmap as default, writeSprites };
package/dist/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ import { n as iconifySvgmap, r as writeSprites, t as VIRTUAL_MODULE_ID } from "./src-CsllISxW.mjs";
2
+ export { VIRTUAL_MODULE_ID, iconifySvgmap as default, writeSprites };