This plugin makes it possible to import SVG files as Svelte components, inline SVG code or urls.
NOTE! This plugin isn't just for SvelteKit, but works for any Svelte project using Vite
yarn add --dev @poppanator/sveltekit-svg
npm install -D @poppanator/sveltekit-svg
In your vite.config.js
import { sveltekit } from '@sveltejs/kit/vite'
import svg from '@poppanator/sveltekit-svg'
/** @type {import('vite').UserConfig} */
const config = {
plugins: [
sveltekit(),
svg(options), // Options are optional
],
}
export default config
You can also pass multiple svg
transformers based on paths if you want to
apply different SVGO options for different SVGs
const config = {
plugins: [
sveltekit(),
svg({
includePaths: ['./src/lib/icons/', './src/assets/icons/'],
svgoOptions: {
multipass: true,
plugins: [
{
name: 'preset-default',
// by default svgo removes the viewBox which prevents svg icons from scaling
// not a good idea! https://github.com/svg/svgo/pull/1461
params: { overrides: { removeViewBox: false } },
},
{ name: 'removeAttrs', params: { attrs: '(fill|stroke)' } },
],
},
}),
svg({
includePaths: ['./src/lib/graphics/'],
svgoOptions: {
multipass: true,
plugins: ['preset-default'],
},
}),
],
}
Import as a Svelte component:
NOTE! It's recommended that you use the
?component
query string if you use the suggested type definition below. The reason is that Vite ships a type definition for*.svg
which states thatimport Comp from './file.svg
returns a string.So providing a default type definition for
*.svg
is in most cases causing a conflict which will lead to TSC errors when treating such an import as a Svelte component.So the best way to avoid errors, current and future, is to always use
import Comp from './file.svg?component
with the suggested type definition at the end of this file.
<script>
import Logo from "./logo.svg?component";
</script>
<Logo />
When used as a component you can also pass attributes to the SVG
<Logo width="200" />
Import as file path:
<script>
import logoUrl from "./logo.svg?url";
</script>
<img src={logoUrl} />
Import as data URL:
<script>
import logoDataUrl from "./logo.svg?dataurl";
</script>
<img src={logoDataUrl} />
In contrast to ?url
this will apply SVGO optimization/transform before the
the SVG is turned into a data URL
You can also pass the SVGO config option datauri
as value to ?dataurl
.
This will, for instance, generate an URI encoded string
<script>
import logoDataUrl from "./logo.svg?dataurl=enc";
</script>
<img src={logoDataUrl} />
Import as code:
<script>
import logo from "./logo.svg?src";
</script>
{@html logo}
interface Options {
/**
* Output type
*
* `dataurl` can also take the following options, which are verbatim SVGO
* `datauri` options:
*
* - `?dataurl=base64` (default, same as `?dataurl`)
* - `?dataurl=enc` URL encoded string
* - `?dataurl=unenc` Plain SVG
*
* @default "component"
*/
type?: 'src' | 'url' | 'component' | 'dataurl'
/**
* Verbatim [SVGO](https://github.com/svg/svgo) options
*
* If no options are given, the SVG will be optimized with the default SVGO
* options.
* If `false` SVGO will be bypassed altogether
*/
svgoOptions?: Config | false
/**
* Paths to apply the SVG plugin on. This can be useful if you want to apply
* different SVGO options/plugins on different SVGs.
*
* The paths are path prefixes and should be relative to your
* `svelte.config.js` file.
*
* @example
* ```
* {
* includePaths: ['src/assets/icons/', 'src/images/icons/']
* }
* ```
*/
includePaths?: string[]
/**
* Hook that lets you transform the svg to a raw Svelte component yourself,
* before being passed to the Svelte compiler.
*
* @param rawSvg The raw SVG data as read from disk
* @param splitSvg The SVG split into parts, e.g its attributes and
* its content
* @returns This should return a complete Svelte component that can be passed
* to the Svelte compiler
*/
preCompileHook?(rawSvg: string, splitSvg: SplitSvg): string
}
According to a report Jest will have trouble
transforming .svg
files when such is imported as a Svelte component.
The solution seems to be to add a module name mapper entry in the the
jest.config.cjs
file, like so:
module.exports = {
// ... other config
moduleNameMapper: {
// ... other mappers
'^.+\\.svg$': '<rootDir>/src/lib/EmptyIcon.svelte',
},
}
where src/lib/EmptyIcon.svelte
can contain just <svg />
.
For Typescript not to complain about file.svg?component
et.al, add the
following import statement to src/app.d.ts
(or any .d.ts
file somewhere in the path of your
project where tsc
can find it).
import '@poppanator/sveltekit-svg/dist/svg'