@stephansama/vite-iconify-svgmap
Version:
Vite plugin for generating iconify svg sprite maps in memory
227 lines (167 loc) • 8.58 kB
Markdown
<div align="center">
# [`@stephansama`](https://github.com/stephansama) / vite-iconify-svgmap
<!-- BADGE start -->
[](https://github.com/stephansama/packages/tree/main/core/vite-iconify-svgmap)
[](https://packages.stephansama.info/api/@stephansama/vite-iconify-svgmap)
[](https://www.npmx.dev/package/@stephansama/vite-iconify-svgmap)
[](https://socket.dev/npm/package/@stephansama/vite-iconify-svgmap/overview)
[](https://jsr.io/@stephansama/vite-iconify-svgmap)
[](https://www.npmx.dev/package/@stephansama/vite-iconify-svgmap)
[](https://npmx.dev/package/@iconify/types)
[](https://npmx.dev/package/@tanstack/intent)
[](https://npmx.dev/package/astro)
[](https://npmx.dev/package/svelte)
[](https://npmx.dev/package/tsdown)
[](https://npmx.dev/package/vite)
<!-- BADGE end -->
Vite plugin for generating iconify svg sprite maps in memory
</div>
##### Table of contents
<details><summary>Open Table of contents</summary>
- [Installation](#installation)
- [Usage](#usage)
- [Astro](#astro)
- [SvelteKit](#sveltekit)
- [Vite](#vite)
- [Static imports](#static-imports)
- [Icons known while rendering](#icons-known-while-rendering)
- [Icon components](#icon-components)
- [Options](#options)
- [How it works](#how-it-works)
</details>
## Installation
Install the plugin and at least one `@iconify-json/*` icon pack
```sh
pnpm install -D @stephansama/vite-iconify-svgmap @iconify-json/logos
```
Add the virtual module types to your `tsconfig.json`
```json
{
"compilerOptions": {
"types": ["@stephansama/vite-iconify-svgmap/client"]
}
}
```
## Usage
### Astro
The astro integration adds the vite plugin and writes sprites for icons
registered with `getIcon` once every page has rendered.
```js
// astro.config.mjs
import iconifySvgmap from "@stephansama/vite-iconify-svgmap/astro/integration";
import { defineConfig } from "astro/config";
export default defineConfig({
integrations: [iconifySvgmap()],
});
```
### SvelteKit
Add the sveltekit plugins **after** `sveltekit()`:
```js
// vite.config.js
import iconifySvgmap from "@stephansama/vite-iconify-svgmap/svelte/integration";
import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [sveltekit(), iconifySvgmap()],
});
```
SvelteKit prerenders in a worker thread and has no hook after prerendering,
so this plugin:
- receives `getIcon` calls made inside the prerender worker over an in
memory `BroadcastChannel`
- writes empty placeholder sprites for every installed icon pack when the
client build finishes, so the prerender crawler does not fail on
`<use href>` links to sprites that do not exist yet
- writes the real sprites (and removes unused placeholders) after
prerendering, before the adapter copies the client output
### Vite
```js
// vite.config.js
import iconifySvgmap from "@stephansama/vite-iconify-svgmap";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [iconifySvgmap()],
});
```
Static imports need nothing else. If you use `getIcon` in a server rendered
or prerendered app, call `writeSprites` with your client output directory
once rendering has finished:
```js
import { writeSprites } from "@stephansama/vite-iconify-svgmap";
await writeSprites("dist");
```
### Static imports
Import an icon as `virtual:iconify-svgmap/<pack>/<icon>` to get its sprite
href. Unknown packs or icons fail the build.
```astro
---
import astro from "virtual:iconify-svgmap/logos/astro";
---
<svg width="24" height="24"><use href={astro}></use></svg>
```
Only the imported icons end up in a content hashed sprite per pack (for
example `/_astro/logos.BzUCTX55.svg`).
### Icons known while rendering
When the icon name is only known while rendering (cms data, frontmatter,
loops), use `getIcon`:
```astro
---
import { getIcon } from "virtual:iconify-svgmap";
const href = getIcon(entry.data.iconPack, entry.data.icon);
---
<svg width="24" height="24"><use href={href}></use></svg>
```
`getIcon` records the icon in memory and returns
`/_iconify/<pack>.svg?v=<build>#<icon>`. The sprite is written after all pages
have rendered.
> \[!NOTE]
> `getIcon` icons must be rendered during the build, in the same process or
> one of its worker threads (static astro sites and prerendered sveltekit
> pages). Icons first requested at runtime by an on demand rendered route, or
> only by client side code, are not included in the written sprites. During
> development every icon works, including client rendered ones.
### Icon components
Each framework subpath exports an `Icon` component that wraps `getIcon` in an
`<svg><use /></svg>`. They follow the same rules as `getIcon`: icons must be
rendered on the server during the build (for example astro pages or
server rendered svelte islands) and the sprites written afterwards (the astro
integration does this).
| Framework | Import |
| --------- | --------------------------------------------------------------------------- |
| astro | `import { Icon } from "@stephansama/vite-iconify-svgmap/astro/component";` |
| svelte 5 | `import { Icon } from "@stephansama/vite-iconify-svgmap/svelte/component";` |
```astro
---
import { Icon } from "@stephansama/vite-iconify-svgmap/astro/component";
---
<Icon pack="logos" name="github-icon" size={24} title="GitHub" />
<Icon pack="heroicons" name="heart-solid" class="text-red-500" />
```
```svelte
<script>
import { Icon } from "@stephansama/vite-iconify-svgmap/svelte/component";
</script>
<Icon pack="logos" name="svelte-icon" size={24} title="Svelte" />
```
| Prop | Default | Description |
| ------- | ------- | -------------------------------------------------------------------- |
| `pack` | | iconify pack, e.g. `logos` for `@iconify-json/logos` |
| `name` | | icon name inside the pack |
| `size` | `"1em"` | width and height |
| `title` | | accessible label; without it the icon gets `aria-hidden="true"` |
| ... | | any other svg attribute (`class`, `style`, ...) is passed to `<svg>` |
Icons that use `currentColor` follow the css `color` of the component.
## Options
| Option | Default | Description |
| ------ | ------------- | -------------------------------------------------------------------------------------- |
| `dir` | `"_iconify"` | folder, relative to the output directory, for sprites of icons registered by `getIcon` |
| `root` | vite's `root` | directory used to resolve `@iconify-json/*` packages |
## How it works
Nothing is written to the file system until the final output:
- icon packs are loaded lazily, only when an icon from the pack is requested
- during development sprites are generated in memory and served by the dev
server
- static imports are emitted as vite assets, so they are hashed and moved to
the output like any other asset
- `getIcon` usage is kept in an in memory registry and flushed once by
`writeSprites`