Coder Social home page Coder Social logo

poppa / sveltekit-svg Goto Github PK

View Code? Open in Web Editor NEW
212.0 5.0 18.0 932 KB

SvelteKit plugin that makes it possible to import SVG files as Svelte components, inline SVG code or urls

License: MIT License

JavaScript 33.16% TypeScript 52.29% HTML 1.53% Svelte 13.02%
sveltekit vite-plugin sveltekit-plugin svelte svelte3 svelte4 vite vitejs svelte5

sveltekit-svg's Introduction

SvelteKit SVG Plugin

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

Install

  • yarn add --dev @poppanator/sveltekit-svg
  • npm install -D @poppanator/sveltekit-svg

Usage

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'],
      },
    }),
  ],
}

Svelte usage

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 that import 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}

Options

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
}

Notes on using with Jest

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 />.

See the reported issue and solution

Typescript

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'

sveltekit-svg's People

Contributors

aradalvand avatar bummzack avatar james-camilleri avatar joakimnordling avatar ljani avatar oetiker avatar paoloricciuti avatar poppa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

sveltekit-svg's Issues

How to use SVG component in Jest?

I am trying to setup Jest unit test but Jest cannot transform .svg file. I don't know how to do it when it is imported as a Svelte component.

import Exclamation from '$lib/icons/exclamation.svg'

<Exclamation />

This svg does not work when imported as component or src, but does when used used directly

<svg width="916" height="1001" viewBox="0 0 916 1001" fill="none" xmlns="http://www.w3.org/2000/svg">
   <g filter="url(#filter0_f_549_57)">
      <rect x="300" y="300" width="316" height="401" fill="url(#paint0_linear_549_57)" />
   </g>
   <defs>
      <filter id="filter0_f_549_57" x="0" y="0" width="916" height="1001" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
         <feFlood flood-opacity="0" result="BackgroundImageFix" />
         <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
         <feGaussianBlur stdDeviation="150" result="effect1_foregroundBlur_549_57" />
      </filter>
      <linearGradient id="paint0_linear_549_57" x1="431" y1="1328" x2="458.523" y2="300" gradientUnits="userSpaceOnUse">
         <stop stop-color="#4F46E5" />
         <stop offset="1" stop-color="#472187" />
      </linearGradient>
   </defs>
</svg>
import BlurComponent from '$lib/assets/blur.svg?component';
import BlurSrc from '$lib/assets/blur.svg?src';
	
<BlurComponent />
{@html BlurSrc}
<svg width="916" height="1001" viewBox="0 0 916 1001" fill="none" xmlns="http://www.w3.org/2000/svg">
	<g filter="url(#filter0_f_549_57)">
		<rect x="300" y="300" width="316" height="401" fill="url(#paint0_linear_549_57)" />
	</g>
	<defs>
		<filter id="filter0_f_549_57" x="0" y="0" width="916" height="1001" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
		        <feFlood flood-opacity="0" result="BackgroundImageFix" />
		       <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
		        <feGaussianBlur stdDeviation="150" result="effect1_foregroundBlur_549_57" />
		</filter>
		<linearGradient id="paint0_linear_549_57" x1="431" y1="1328" x2="458.523" y2="300" gradientUnits="userSpaceOnUse">
			<stop stop-color="#4F46E5" />
			<stop offset="1" stop-color="#472187" />
		</linearGradient>
	</defs>
</svg>

Screenshot 2024-04-08 at 16 09 32

Svelte 5 Support

I realise this is probably still rather early to be looking at this, but I am so I figure I'll put a ticket with my findings. I have patched it locally so there's no urgency on my part to get it fixed ;)

When using sveltekit-svg with Svelte 5.0.0-next.26, compilation fails with the following error:

Failed reading SVG ".../svelte-site/src/resources/title.svg?component": Invalid compiler option: css: "none" is no longer a valid option. If this was crucial for you, please open an issue on GitHub with your use case. sr [CompileError]: Invalid compiler option: css: "none" is no longer a valid option. If this was crucial for you, please open an issue on GitHub with your use case.
    at ar (.../svelte-site/node_modules/.pnpm/[email protected]/node_modules/svelte/compiler.cjs:1:228490)
    at gS (.../svelte-site/node_modules/.pnpm/[email protected]/node_modules/svelte/compiler.cjs:1:627312)
    at .../svelte-site/node_modules/.pnpm/[email protected]/node_modules/svelte/compiler.cjs:1:624179
    at .../svelte-site/node_modules/.pnpm/[email protected]/node_modules/svelte/compiler.cjs:1:627031
    at .../svelte-site/node_modules/.pnpm/[email protected]/node_modules/svelte/compiler.cjs:1:626951
    at e.compile (.../svelte-site/node_modules/.pnpm/[email protected]/node_modules/svelte/compiler.cjs:1:642916)
    at TransformContext.transform (.../svelte-site/node_modules/.pnpm/@[email protected][email protected][email protected][email protected]/node_modules/@poppanator/sveltekit-svg/dist/index.js:112:55)
    at async Object.transform (file://.../svelte-site/node_modules/.pnpm/[email protected]/node_modules/vite/dist/node/chunks/dep-R0I0XnyH.js:63705:30)
    at async loadAndTransform (file://.../svelte-site/node_modules/.pnpm/[email protected]/node_modules/vite/dist/node/chunks/dep-R0I0XnyH.js:49386:29)
    at async Object.warmupRequest (file://.../svelte-site/node_modules/.pnpm/[email protected]/node_modules/vite/dist/node/chunks/dep-R0I0XnyH.js:60017:13) {
  filename: '.../svelte-site/src/resources/title.svg?component',
  position: undefined,
  start: undefined,
  end: undefined,
  code: 'invalid-compiler-option'
}

Changing css: 'none', to css: 'external', fixes the compile issue and generally seems to work (the SVG is rendered now), although it now has a couple of warnings:

`generate: "dom"` and `generate: "ssr"` options have been renamed to "client" and "server" respectively
The hydratable option has been removed. Svelte components are always hydratable now.
Sourcemap for ".../svelte-site/src/resources/title.svg" points to missing source files

(the last one is for the specific SVG I am importing, but applies more generally)

Property X does not exist on type 'IntrinsicAttributes'

Thanks for this plugin, it's working great.

However when passing any attributes e.g color ,height etc, I get a TS error:

Property `x` does not exist on type 'IntrinsicAttributes'

image

currently using:

"@sveltejs/kit": "1.0.0-next.1",
"svelte": "^3.44.0",
"typescript": "^4.4.3"

`Error: Cannot find module 'svgo'`

I did yarn add --dev @poppanator/sveltekit-svg
I added import svg from '@poppanator/sveltekit-svg' and used as plugin:
plugins: [sveltekit(), svg()]

After that, I'm trying to run yarn dev and this error happens.

yarn dev
yarn run v1.22.4
$ vite dev
failed to load config from C:\Users\Jerry\projects\jerrygreen.github.io-src2\vite.config.ts
error when starting dev server:
Error: Cannot find module 'svgo'

Is this a dependency I should manually add, or?

Error: Cannot find module '@rollup/pluginutils'

Hi.
Very nice plugin.

However, I've encountered an issue. When I configure the settings and start the application, I get the following error:

> [email protected] dev
> vite dev

failed to load config from /app/vite.config.ts
error when starting dev server:
Error: Cannot find module '@rollup/pluginutils'
Require stack:
- /app/node_modules/@poppanator/sveltekit-svg/dist/index.js
    at Module._resolveFilename (node:internal/modules/cjs/loader:1144:15)
    at Module._load (node:internal/modules/cjs/loader:985:27)
    at Module.require (node:internal/modules/cjs/loader:1235:19)
    at require (node:internal/modules/helpers:176:18)
    at Object.<anonymous> (/app/node_modules/@poppanator/sveltekit-svg/dist/index.js:5:23)
    at Module._compile (node:internal/modules/cjs/loader:1376:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1435:10)
    at Module.load (node:internal/modules/cjs/loader:1207:32)
    at Module._load (node:internal/modules/cjs/loader:1023:12)
    at cjsLoader (node:internal/modules/esm/translators:345:17)

Here are the relevant devDependencies from my package.json:

	"devDependencies": {
		"@poppanator/sveltekit-svg": "^4.2.0",
		"@sveltejs/adapter-auto": "^3.0.0",
		"@sveltejs/adapter-cloudflare": "^3.0.1",
		"@sveltejs/kit": "^2.0.0",
		"@sveltejs/vite-plugin-svelte": "^3.0.0",
		"@types/eslint": "8.56.0",
		"@typescript-eslint/eslint-plugin": "^6.0.0",
		"@typescript-eslint/parser": "^6.0.0",
		"eslint": "^8.56.0",
		"eslint-config-prettier": "^9.1.0",
		"eslint-plugin-svelte": "^2.35.1",
		"prettier": "^3.1.1",
		"prettier-plugin-svelte": "^3.1.2",
		"svelte": "^4.2.7",
		"svelte-check": "^3.6.0",
		"sveltekit-superforms": "^1.13.1",
		"svgo": "^3.2.0",
		"tslib": "^2.4.1",
		"typescript": "^5.0.0",
		"vite": "^5.0.3",
		"wrangler": "^3.22.2",
		"zod": "^3.22.4"
	},

Do you have any suggestions on how to resolve this issue? I would greatly appreciate your help.

Thanks!

Inlining as data url?

Hi,
I found this plugin hoping that it would allow me to import small svg icons as data url strings which I could directly use as the source of img tags, but was disappointed when I found that it does not allow that (or am I missing something? maybe there is an svgo option for this?)
So I guess this is a feature request, would this be possible?
Before sveltekit I was using this rollup plugin to achieve the same: https://www.npmjs.com/package/@rollup/plugin-image

Fails to compile in Svelte 5: "Invalid compiler option: css: "none" is no longer a valid option"

Howdy!

I recently tried updating my project to Svelte 5 (w/ SvelteKit v2), and it's throwing the following error when starting up the dev server:

Failed reading SVG "/Users/.../dev/web-app/src/icons/Flowbite-ComputerSpeaker.svg?component": Invalid compiler option: css: "none" is no longer a valid option. If this was crucial for you, please open an issue on GitHub with your use case. sr [CompileError]: Invalid compiler option: css: "none" is no longer a valid option. If this was crucial for you, please open an issue on GitHub with your use case.

It's not really a big deal atm since Svelte 5 is still beta, so I'll just downgrade for now so I can continue using your library.

Error: <Btn_Next> is not a valid SSR component.

I have this line in one of my svelte components:

<script type="ts">
import Btn_NEXT from '$lib/assets/btn_NEXT.svg?component';
</script>
...
<Btn_NEXT fill="{fill}" class="{imgClass}" />

So I plan to use this SVG as a component and change some properties dynamically.

As soon as I have a non-empty svgoOptions (see below later) in my vite.config I first get this warning:

[WARNING]: Type ".../src/lib/assets/btn_NEXT.svg?component" can not be imported as a Svelte component since "datauri" is set in vite.config

Then, it throws this error:

Error: <Btn_NEXT> is not a valid SSR component. You may need to review your build config to ensure that dependencies are compiled, rather than imported as pre-compiled modules. Otherwise you may need to fix a <Btn_NEXT>.

I searched through your code and logged svgo:

            let svgo = options.svgoOptions;
            let isSvgoDataUri = false;
            console.log(svgo)
            if (svgo && typeof svgo === 'object') {
                if (svgo.datauri) {
                    isSvgoDataUri = true;
                }
            }
            if (isSvgoDataUri && type === 'component') {
                console.warn(`[WARNING]: Type "${id}" can not be imported as a Svelte component ` +
                    `since "datauri" is set in vite.config`);
            }

Output:

{
  plugins: [ { name: 'preset-default', params: [Object] } ],
  datauri: 'base64'
}

But I fail to see if I can do anything about it. svgo will write base64 in any case and it can't be empty. I havn't been setting datauri, just defaults. Here's what my vite.config looks like:

import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vitest/config';
import svg from '@poppanator/sveltekit-svg';


export default defineConfig({
	plugins: [
		sveltekit(),
		svg({
			svgoOptions: {
				datauri: false,
				plugins: [
					{ name: 'preset-default', params: { overrides: { removeViewBox: false } } },
					'removeDimensions'
				]
			}
		})
	],
	test: {
		include: ['src/**/*.{test,spec}.{js,ts}']
	}
});

Again: If svgoOptions is empty, vite runs just fine, but without those options sveltekit-svg looses its value for me.

Full stacktrace:
https://pastebin.mozilla.org/oBB5Ezmn

package.json excerpt

		"@poppanator/sveltekit-svg": "^3.0.0",
		"svelte": "^3.54.0",
		"@sveltejs/kit": "^1.5.0",
		"tailwindcss": "^3.2.7",
		"typescript": "^4.9.3",
		"vite": "^4.0.0",

What am I missing here? This seems to be the standard use case, right?!

PSA: css selectors that target an imported `.svg` are considered `unused` and are pruned

Hi,

Thank you for this great plugin. It's nice to be able to import the raw svg xml and seamlessly pass attributes into it at the same time.

This video provided a nice overview and use case:
LIVE Coding & Chill: ๐Ÿ–ผ importing SVGs in SvelteKit ๐ŸŒ 


Here's what I ran into:

When using import for an .svg, css selectors, that target only that svg, are pruned because Svelte (or Vite or one of the css minifiers) thinks they're unused.

Example:

<script>
    import Logo from '$lib/logo.svg?component';
</script>

<Logo id="logo"/>

<style>
#logo {
    opacity: 0.5;
}
</style>

Result:

  • Console output: Unused CSS selector "#logo"
  • That #logo selector is removed from the css output.
  • Therefore the SVG does not receive opacity: 0.5

The same happens if you explicitly set the id= inside of the original .svg file, as opposed to setting it via an attribute on the sveltekit-svg created <Logo id="logo"/> tag.

I originally found this with a <style lang="sass"> block. I thought maybe this had something to do with using sass as a pre-processor. But it doesn't. At least not in this case.

But if you copy/paste the .svg code directly into the .svelte file, it works as expected:

<svg id="logo"/>

<style>
#logo {
    opacity: 0.5;
}
</style>

Result:

  • No warning in the console.
  • The #logo selector remains.
  • opacity: 0.5 is applied.

Workarounds:

  • The main workaround seems to be using: :global(#logo)

    This forces Svelte to keep the #logo selector, regardless of its use/non-use. See: sveltejs/svelte#1594 (comment)

  • Someone else suggested using the svelte-preprocess plugin and set <style global>. But that seems less than ideal.

  • Another way of approaching it, would be to wrap the <Logo/> in an element with the ID and adjust your CSS accordingly:

<div id="logo">
    <Logo>
</div>

<style>
#logo svg {
    opacity: 0.5;
}
</style>

Here's some commentary about this exact issues:
sveltejs/svelte#5804

This seems to bite a lot of people. It's the second or third issue I've run into related to import (which seems to be the frequently preferred method of using assets) and then later having issues because some other plugin or generic code doesn't recognizing that dynamic import at compile-time.

I'm posted this not because it's a bug with sveltekit-svg, but more for:

  • General information/PSA.
  • Cross-referencing to others who have reported similar SvelteKit issues.
  • Maybe because it would be good to put something in the sveltekit-svg docs about this issue. I figure, because of the nature of this plugin, a disproportionate number of people might run into this. (But I could be wrong)

I have no grand suggestion or request, since this seems to have basically everything to do with how SvelteKit is setup and not your plugin :-)

I hope this helps.

Thanks.

Svelte and TS errors when importing svgs

If I use ?component I get this:
Screenshot 2022-11-06 at 14 58 12

If I remove ?component I get this:
Screenshot 2022-11-06 at 14 58 51

Also had to import the vite Plugin type to make this plugin work. Everything works now despite these errors, but how can I fix them? Thanks for you help!

Conflict with Vite 4.0

Hello,

I seem to be getting a conflict when I try to install sveltekit-svg with vite 4.0

this is the error I get

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: [email protected]
npm ERR! Found: [email protected]
npm ERR! node_modules/vite
npm ERR!   vite@"^4.0.0" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer vite@"3.x" from @poppanator/[email protected]
npm ERR! node_modules/@poppanator/sveltekit-svg
npm ERR!   dev @poppanator/sveltekit-svg@"*" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR! See /Users/myname/.npm/eresolve-report.txt for a full report.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/myname/.npm/_logs/2022-12-11T18_18_10_409Z-debug-0.log

SSR true

image

It seems that in SSR mode generated component if we use `?component` syntax fails

Add a hook to allow plugin users to modify the resulting component

We are currently using this in out application but we've runned into the issue of not being able to dynamically set the title of the svg for accessibility reasons.

Given that the resulting import is a svelte component this would be very easy to do if we could modify the string returned from the vite plugin before the transform.

I can make a PR for this, and i'll probably start to work on this tomorrow so is you have any concern regarding this feel free to hit me up.

Use events on components

Hello. Thank you for making this, it works like a charm.

I would really like however if we could also use regular Svelte events on imported components, as it does not seem like this is currently possible.

<script lang="ts">
    import Logo from '$components/icon/logo.svg?component';
</script>

<Logo on:mouseover={() => console.log('hovered')} /> // doesn't work

<svg on:mouseover={() => console.log('hovered')}>...</svg> // works

Or am I missing something?

Also as a side note, I think you should update your Typescript example by using something like the newly added svelte/elements types instead of ConstructorOfATypedSvelteComponent (which isn't recommended) :

declare module '*svg?component' {
  import type { ComponentType, SvelteComponentTyped } from 'svelte';
  import type { SVGAttributes } from 'svelte/elements';

  const content: ComponentType<SvelteComponentTyped<SVGAttributes<SVGSVGElement>>>;

  export default content;
}

This way you get full intellisense support like a normal svg tag.

`?url` + SVGO?

Hey there!
I have a scenario where I need to import an SVG file as a URL (rather than as a Svelte component), but I still want it to go through SVGO.
Unfortunately, using the ?url option seems to cause SVGO to be bypassed. Is there a way around this? And wouldn't it make more sense in general to have all SVGs go through SVGO regardless of how they're imported? That's certainly what I was expecting.

Simplify library usage for common usage

Instead of this:

<script>
import Logo from "./logo.svg?component";
</script>

<Logo />

I personally expect a more traditional look:

<script>
import Logo from "./logo.svg";
</script>

<Logo />

In addition to better aesthetics, it won't require these hacks with import "@poppanator/sveltekit-svg/dist/svg" in app.d.ts

Is usage with a packaged library supported?

I'm trying to use svelte-svg in components of a library output with svelte-kit package. Locally (and with Storybook) i can get everything working fine; but when I try to import my packaged components into an external project I hit the following error:
<MyIcon> is not a valid SSR component
My svg source path is inside the library src/

I was hoping I could configure svelte-svg in the external project and use the path to the icons in node_modules in the includePaths; but unfortunately that doesn't work. I did manage to get [unplugin-icons|https://github.com/antfu/unplugin-icons] working with this approach (that uses some form of alias in the SVG path); but I can't get that working with Storybook; and TBH svelte-svg seems somewhat simpler to work with.

Is it possible to use svelte-svg in a packaged library; and if so is there any documentation/example available? Thanks!

Failed reading SVG, config should be an object

Problem

Plugin options are specified as optional in the README, however not providing any svgoOptions causes following error when running svelte-kit build and importing SVG as a Svelte component:

Failed reading SVG "C:/Users/[redacted]/static/[redacted].svg": Config should be an object

Then when running svelte-kit dev, a subsequent error is produced as expected:

Error: <Icon> is not a valid SSR component. You may need to review your build config to ensure that dependencies are compiled, rather than imported as pre-compiled modules

Workaround

Providing empty object for svgoOptions solves mentioned errors:

svelte.config.js

const svg = require('@poppanator/sveltekit-svg')

module.exports = {
  ...,
  kit: {
    ...,
    vite: {
      plugins: [svg({svgoOptions: {}})]
    }
  }
}

Reproduction details

Dependencies

Files

svelte.config.js

const svg = require('@poppanator/sveltekit-svg')

module.exports = {
  ...,
  kit: {
    ...,
    vite: {
      plugins: [svg()],
      resolve: {
        alias: {
          $assets: resolve('./static/assets'),
        },
      }
    }
  }
}

src/routes/index.svelte

<script>
  import Icon from '$assets/icon.svg';
</script>

<Icon />

static/assets/icon.svg

-

Not a valid SSR component

Hi!

I would like to use the Component style rendering import, but I get this error in my project.

Error: <BackgroundSvg> is not a valid SSR component. You may need to review your build config to ensure that dependencies are compiled, rather than imported as pre-compiled modules. Otherwise you may need to fix a <BackgroundSvg>. at Module.validate_component

i am on

   "svelte": "^4.2.0",
    "svelte-check": "^3.4.6",
"@sveltejs/adapter-auto": "^2.1.0",
    "@sveltejs/adapter-vercel": "^3.0.3",
    "@sveltejs/kit": "^1.5.0",

Get SVGSVGElement from generated component

When getting a component using *.svg?component is there a way to get an instance of SVGSVGElement from the component? Like what bind:this does on the <svg> tag (and all the other DOM element tags). Alternatively, is there a way to add use:action to the element or any other way to access lifetime hooks?

Pass attributes to Svelte components

Hi,

I was wondering if it would be possible to pass attributes to the SVG when loaded as Svelte components.
For example:

<script>
import FacebookLogo from 'line-awesome/svg/facebook-f.svg';
</script>

<FacebookLogo class="my-class" />

Sourcemap issues

Hi thanks for creating this great little package.

I noticed this warning in our builds when using with a typical svelte + kit + vite build.

(sveltekit-svg plugin) Sourcemap is likely to be incorrect: a plugin (sveltekit-svg) was used to transform files, but didn't generate a sourcemap for the transformation. Consult the plugin documentation for help

Are we missing something in our config or is this possibly an issue with the plugin?

Happy to provide any other details if useful.
Thanks!

Import SVG component dynamically based on input that the component is getting

Hi.
I would like to add svg icon dynamically based on parameters that the component is getting by its inputs.

Input example:
socials: [
{ link: 'XXX', url: '../images/icons/instagram-brands.svg' },
{ link: 'XXX', url: '../images/icons/tiktok-brands.svg' },
{ link: 'XXX', url: '../images/icons/whatsapp-brands.svg' },
{ link: 'https://t.me/InstBlast', url: '../images/icons/telegram-plane-brands.svg' }
]

I tried dynamic import like the example above but the icons is not displayed

  {#each data.socials as social }
    <a
      href={social.link}
      target="_blank"
      rel="noopener noreferrer"
      class="text-gray-400 hover:text-gray-900 hover:text-primary"
    >
      {#await import(`${social.url}?component`) then Icon}
        <Icon.default width="200" />
      {/await}
    </a>
  {/each}

Any suggestions How can I make it work?

Thanks.

Example for using svgOptions?

I cannot figure out how to use the svgoOptions argument. Tried this:

// svelte.config.js
const config = {
  preprocess: preprocess(),
  kit: {
    adapter: adapter(),
    vite: {
      plugins: [
        svg({
          plugins: [
            {
              name: 'preset-default',
              params: {
                overrides: {
                  removeEditorsNSData: false,
                  removeMetadata: false,
                  removeViewBox: false,
                  removeDimensions: true
                }
              }
            }
          ]
        })
      ]
    },
    // hydrate the <div id="svelte"> element in src/app.html
    target: '#svelte'
  }
};

but it did not have any effect on the rendered svg. I then also tried to put this into a separate svgo.config.js file, but that did also not have any effect.

Support alternative datauri encodings

svgo has a datauri option to set the encoding: base64, enc (URI encoded), unenc. See svg/svgo#105.
Though, before v3 datauri field sometimes seems to be ignored: svg/svgo#1679

This plugin currently only support base64. Could you honour the "datauri" field in optimization config?

Unexpected behavior passing classes to component svg

The expected behavior is that these two behave the same, but the latter does not work.

<!-- Inline the svg -->
<svg class="my-class" viewbox="0 0 128 128">
    <!-- ... -->
</svg>

<style>
    .my-class {
        width: 16px;
        height: 16px;
    }
</style>

However this does not work:

<!-- Import as component -->
<script>
    import Svg from 'test.svg';
</script>

<Svg class="my-class" />

<style>
    .my-class {
        width: 16px;
        height: 16px;
    }
</style>

With a real svg when I inspect the generated elements in chrome, the inlined svg generates:

<svg class="my-class s-Uap-jPRb-uiE" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" style="isolation: isolate;">

While the component svg generates:

<svg class="my-class" xmlns="http://www.w3.org/2000/svg" style="isolation:isolate" viewBox="0 0 128 128">

Notice the missing svelte class.

Incorrect configuration in documentation example

As of the most recent versions of SvelteKit, any VIte plugins must be passed to a vite object in the Svelte config, e.g.

kit: {
  ...
  vite: {
    plugins: [svg()]
  }
}

This is not currently reflected on the plugin documentation - you may want to update it.

Thanks for the super-useful plugin ๐Ÿ˜ƒ

Import from static folder

When import SVGs from static folder, either with relative path or using an alias, this error occurs:
files in the public directory are served at the root path. Instead of /static/icons/file.svg?import, use /icons/file.svg?import

The problem is that if I ommit the static folder, it says the SVG is not a valid SSR Component.

Svelte 4 support

Since svelte 4 was released as a stable module, it would be lovely to update this project to svelte 4. Due to this being a relatively small upgrade, there shouldn't be too many complications. I think this package would probably just require a version bump in the package.json

Related migration guide

Thank you for the kind work!

Render the contents of the `<svg>` tag using `{@html}` in the component mode

Importing an SVG file as a Svelte component with this plugin currently causes it to generate a Svelte component on the fly which will have the entire SVG directly as its content โ€” it just adds {...$$props} on the <svg> tag:

function addComponentProps(data: string): string {
const parts = svgRegex.exec(data)
if (!parts) {
throw new Error('Invalid SVG')
}
const [, head, body] = parts
return `${head} {...$$props}${body}`
}

However, the problem with this is that when the Svelte compiler then looks at the generated component, it will parse all the elements inside the root <svg> tag, and will yield lots of compiler output with lots of function calls to create each element in the DOM. This is totally unnecessary. A better approach would be to render the contents of the <svg> tag using {@html}.

See this REPL, which demonstrates exactly this; take a look at AtHtmlSvg.svelte and RegularSvg.svelte and the JS output tab of each, and notice the difference.

Even some plugins have been created to address this, like svelte-preprocess-svg, for cases where you have inlined SVG elements in your Svelte components. But sveltekit-svg can make this improvement very easily.

Let me know if you're on board, and I will make a pull request.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.