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 configYou 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',
          },
          { 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
?componentquery string if you use the suggested type definition below. The reason is that Vite ships a type definition for*.svgwhich states thatimport Comp from './file.svgreturns a string.So providing a default type definition for
*.svgis 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?componentwith 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
}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.d.ts'NOTE! If you have
module/moduleResolutionset toNodeNextin your Typescript config, you MUST include.d.tsin the import of the SVG type definition.
I don't know if this still applies, but it's kept here for good measure
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 />.