@zhangyx1998/svg-loader
v0.0.2
Published
Vite plugin that compiles imported .svg files into inline, style-scoped Vue components
Downloads
250
Maintainers
Readme
@zhangyx1998/svg-loader
A Vite plugin that compiles each imported .svg into an
inline, style-scoped Vue component.
import Logo from "./logo.svg";<template>
<!-- renders the SVG inline; inherits color via currentColor -->
<Logo class="w-8 text-blue-500" />
</template>Why inline?
- Vector stays vector. Unlike
<img src="logo.svg">, the markup is inlined, so you can target elements with CSS, animate them, and letcurrentColorinherit from surrounding text. - No class-name collisions. Each SVG gets a unique
data-v-<hash>scope and its<style>blocks are run through@vue/compiler-sfc'scompileStyle, so generic class names (.st0,.line, …) can't leak across figures. - Assets outside
public/. Relative raster references inside an SVG (e.g.<image xlink:href="photo.webp">) are rewritten into Vite?urlimports, so the bundler emits the assets and the inlined markup points at the resolved, content-hashed URLs.
Install
npm i -D @zhangyx1998/svg-loadervite and vue are peer dependencies.
Usage
1. Register the plugin
// vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import svgLoader from "@zhangyx1998/svg-loader";
export default defineConfig({
plugins: [vue(), svgLoader()],
});The plugin runs with
enforce: "pre", so it takes precedence over Vite's default asset handling for.svg.
2. Add the ambient types
So TypeScript knows that import Foo from "./foo.svg" is a component, register
the client types once. Pick whichever fits your project:
Option A — triple-slash reference (e.g. in env.d.ts):
/// <reference types="@zhangyx1998/svg-loader/client" />Additive and side-effect free — it doesn't touch any of your other global types. The downside is it lives in a source file rather than your config.
Option B — compilerOptions.types in tsconfig.json:
{
"compilerOptions": {
"types": ["@zhangyx1998/svg-loader/client"],
},
}Keeps everything in config, but types is all-or-nothing: setting it disables
TypeScript's automatic inclusion of every package in node_modules/@types, so
you must list the other globals you rely on too:
"types": ["node", "vite/client", "@zhangyx1998/svg-loader/client"]Option C — include a .d.ts from tsconfig.json:
Put the triple-slash line from Option A in a file (e.g. env.d.ts) and make
sure it's covered by include. This is additive like Option A while keeping
the wiring in config — at the cost of one extra file.
3. Import and render
<script setup lang="ts">
import Icon from "./icon.svg";
</script>
<template>
<Icon />
<!-- override the wrapper element if you need to -->
<Icon tagName="g" />
</template>Import types
By default an imported .svg is a Vue component. Explicit query suffixes let
you opt into the other forms per import:
import Icon from "./icon.svg"; // Vue component (default)
import Icon from "./icon.svg?component"; // Vue component (explicit)
import iconUrl from "./icon.svg?url"; // resolved URL string (Vite's asset handling)
import iconRaw from "./icon.svg?raw"; // raw SVG source string?url and ?raw are typed as string; the bare and ?component forms are
typed as the component (see Add the ambient types).
Options
svgLoader({
// Base URL prepended to root-absolute (`/...`) asset references found inside
// the SVG. Defaults to Vite's resolved `base`.
baseUrl: "/",
// Namespace element ids with the SVG's scope hash so ids like `clip-path-01`
// can't collide across multiple inlined SVGs. Defaults to true.
escapeIds: true,
// How a `.svg` import with no explicit query is resolved. Defaults to
// "component".
defaultImport: "component",
});| Option | Type | Default | Description |
| --------------- | ----------------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| baseUrl | string | Vite's base | Prefix applied to root-absolute (/...) href/src/url() references. |
| escapeIds | boolean | true | Suffix every element id with the scope hash and rewrite its url(#…) / href="#…" references to match, so ids (clip paths, gradients, patterns, filters, <use> symbols) can't collide when several SVGs are inlined on one page. |
| defaultImport | "component" | "url" | "raw" | "component" | Import form for a .svg with no ?component / ?url / ?raw query. An explicit query always overrides this. |
Component props
The generated component accepts a single prop:
| Prop | Type | Default | Description |
| --------- | -------- | ------- | ------------------------------------------ |
| tagName | string | "svg" | The root element tag the SVG renders into. |
All other attributes (class, style, event handlers, …) are forwarded to the
root element.
License
MIT © Yuxuan Zhang
