@svelte-put/preprocess-inline-svg GitHub

svelte preprocessor to inline static svg at build time

@svelte-put/preprocess-inline-svg @svelte-put/preprocess-inline-svg @svelte-put/preprocess-inline-svg changelog

Introduction

Current solutions (that I know of) for inlining SVGs in Svelte land require either runtime logics or a component-oriented strategy. These solutions are acceptable in most cases but have been proven to be problematic when additional styling / attributes are needed for the inlined svg element.

This package tries to achieve zero runtime footprint with no additional component. The idea is to enable this:

minimal usage api

<svg inline-src="google/info"></svg>

which will automatically read from the source svg and inline it at build time. Additional styling and attributes can now be added idiomatically as with any other html element.

Prior Art

Runtime Solution

This processor is best for static svgs like icons and pictograms. For dynamic svgs (i.e loaded from network), use @svelte-put/inline-svg - an action-based strategy with a similar api.

runtime alternative

<svg use:inlineSrc={'https://example.com/icon.svg'}></svg>

Installation

terminal

npm install --save-dev @svelte-put/preprocess-inline-svg

Quick Start

preprocess-inline-svg provides both a vite plugin and a svelte preprocessor with the same core functionality.
Use svelte preprocessor if you are not using vite. Otherwise, vite plugin is recommended.

Given the following (vite.config.ts,js or svelte.config.js)

quick start - config

import { inlineSvg } from '@svelte-put/preprocess-inline-svg/vite';
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [
    // make sure inlineSvg comes before `svelte` or `sveltekit` plugin
    inlineSvg(
      [
        {
          directories: 'src/assets/icons',
          attributes: {
            class: 'icon',
            width: '20',
            height: '20',
          },
        },
        {
          directories: 'src/assets/pictograms',
        },
      ],
      {
        inlineSrcAttributeName: 'inline-src',
      },
    ),
    sveltekit(),
  ],
});

and the asset files as follow

quick start - assets

src/assets
    |
    |-- icons
         |-- svelte.svg
         |
         |-- google
               |-- arrow-right.svg
         |-- simpleicons
               |-- github.svg
    |
    |-- pictograms
         |-- diagram.svg

we can now do

quick start - usage

<!-- this will have width="20" height="20" as specified in the config -->
<svg inline-src="svelte" />

<!-- nested -->
<svg inline-src="google/arrow-right.svg" />
<!-- .svg can be omitted -->
<svg inline-src="simpleicons/github" />

<!-- with custom attributes -->
<svg inline-src="diagram" width="100" height="100" />

<!-- alternatively, you can provide a per-case path that is relative to the current source file -->
<svg inline-src="./local-icon.svg" />

<!-- if the source svg is not found for any of the above, an error will be thrown -->

The .svg extension may be omitted from the path provided to inline-src.

Attributes & Inner HTML

Attributes provided to the source svg element will be kept after build and override the existed ones in the inlined SVG.

merging attributes

<svg inline-src="path/icon" width="100" height="100" class="c-icon"></svg>

InnerHTML of the source svg element will be replaced with the that from the inlined SVG.

merging attributes

<svg inline-src="path/icon">anything in here will be replaced</svg>

If you have a use case where it is useful to append/prepend the innerHTML of inlined SVGs rather than replace it, please raise an issue over at github . For now, let's keep things simple.

Typing the `inline-src` Attribute

This feature is only available when the vite plugin is used, see Quick Start for more information about vite plugin vs svelte preprocessor config.

preprocess-inline-svg vite plugin provides automatic typing generation (enabled by default) for the inline-src attribute when multiple svg sources are configured. There are a couple of steps needed to get this working.

1. Set the inlineSrcAttributeName option to a non data attribute (this is because currently data attributes do not get intellisense with svelte-check, for some strange reason).

setting inlineSrcAttributeName

import { inlineSvg } from '@svelte-put/preprocess-inline-svg/vite';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [
    inlineSvg(
      [
        // ... sources as in Quick Start section
      ],
      {
        inlineSrcAttributeName: 'inline-src',
      },
    ),
    // ...
  ],
});

2. Set typing in a additional-svelte-typing.d.ts file, following instruction here from the svelte language-tools team

src/additional-svelte-typing.d.ts

declare namespace svelteHTML {
  interface SVGAttributes {
    'inline-src'?: import('@svelte-put/inline-svg/preprocess').Source;
  }
}

The inline-src attribute should be strongly typed now. For example, with the assets as shown in the Quick Start section, the typing should be the following:

Source

// import('@svelte-put/inline-svg/preprocess').Source
export type Source =
  | `./${string}`
  | `../${string}`
  | 'svelte'
  | 'google/arrow-right'
  | 'simpleicons/github'
  | 'diagram';

To disable this typing generation, set sourceTypingGeneration option to false.

Limitations

preprocess-inline-svg only works in svelte markup, i.e in the template part of svelte source files. The following will not work

only support svelte markup

<script>
  let html = `<svg inline-src="path/icon"></svg>`;
</script>

<!-- eslint-disable-next-line svelte/no-at-html-tags -->
{@html html}

preprocess-inline-svg does not support inline-src as a variable. I.e, the following will not work

dynamic attribute is not support

<script lang="ts">
  export let icon: string;
</script>

<svg inline-src={icon} />

This is because it is difficult for the preprocessor to analyze a variable to determine its immutability at build time, i.e a variable is meant to be changed. In these case, some workarounds are

  • use if-else statements to switch between different inline-src as literal strings, or
  • use @svelte-put/inline-svg as a runtime action-based strategy instead.

If you have an idea for improvements, please raise an issue over at github . Thanks!

Customization

All options are optional. By default inline-svg can be used with no config at all, in which case svg source paths are resolved relative to the svelte source file it is specified in.

Note that path alias is not supported in inline-src! For example, "$lib/src/assets/..." will not work.

Alternatively, the directories option can be specified (as seen in the "Quick Start" section) to conveniently omit the need for verbose pathnames.


Input to inline-svg can be provided as a single object, or an array of such (as seen in the "Quick Start" section), helpful for organization purposes or when different configurations are needed for different directories.

When input is an array of configs, the following applies:

There can only be one config object without the directories option (default config).
If multiple are found, an error will be thrown at build. If none is provided, the internal default config is used.

Each svg source will then be searched top down in the config until a match is found, or else an error will be thrown.

Local svg (local to svelte source file) always has the highest priority and will use default config as described above.


Option

Description

directories

directories relative to which the svg source paths will be resolved.
type: string[] | string
default: []

attributes

default attributes to add to the svg element, will override the attributes from the svg source, but be overridden by the attributes from the element itself (in svelte source)
type: Record<string, string>
default: {}

serializeOptions

options for hast-util-to-html during serialization
type: Object
default: { space: 'svg', allowDangerousCharacters: true }

inlineSrcAttributeName

the attribute to get the svg source from
type: string
default: 'inline-src'

keepInlineSrcAttribute

whether to keep the inline src attribute after build (for reference, for example)
type: boolean
default: false

Further Work

This package is kept minimal as it has served its purpose for all of my need. If you find this package to lack certain features that are essential to your use cases, please file an issue at github and let me know. Thank you!

Some possibilities:

  • Support for svgo?
  • Support for fetching remote svg in inline-src at build time?

Edit this page on GitHub