Coder Social home page Coder Social logo

vite-svg-loader's Introduction

Vite SVG loader

Vite plugin to load SVG files as Vue components, using SVGO for optimization.

Version Downloads Tests License

<template>
  <MyIcon />
</template>

<script setup>
import MyIcon from './my-icon.svg'
</script>

Install

npm install vite-svg-loader --save-dev

Setup

vite.config.js

import svgLoader from 'vite-svg-loader'

export default defineConfig({
  plugins: [vue(), svgLoader()]
})

Import params

URL

SVGs can be imported as URLs using the ?url suffix:

import iconUrl from './my-icon.svg?url'
// 'data:image/svg+xml...'

Raw

SVGs can be imported as strings using the ?raw suffix:

import iconRaw from './my-icon.svg?raw'
// '<?xml version="1.0"?>...'

Component

SVGs can be explicitly imported as Vue components using the ?component suffix:

import IconComponent from './my-icon.svg?component'
// <IconComponent />

Default import config

When no explicit params are provided SVGs will be imported as Vue components by default. This can be changed using the defaultImport config setting, such that SVGs without params will be imported as URLs (or raw strings) instead.

vite.config.js

svgLoader({
  defaultImport: 'url' // or 'raw'
})

SVGO Configuration

vite.config.js

svgLoader({
  svgoConfig: {
    multipass: true
  }
})

Disable SVGO

vite.config.js

svgLoader({
  svgo: false
})

Skip SVGO for a single file

SVGO can be explicitly disabled for one file by adding the ?skipsvgo suffix:

import IconWithoutOptimizer from './my-icon.svg?skipsvgo'
// <IconWithoutOptimizer />

Use with TypeScript

If you use the loader in a Typescript project, you'll need to reference the type definitions inside vite-env.d.ts:

/// <reference types="vite/client" />
/// <reference types="vite-svg-loader" />

Sponsors

Nexxtmove Logo

Thanks to Nexxtmove for sponsoring the development of this project.
Your logo or name here? Sponsor this project.

vite-svg-loader's People

Contributors

abdul-alhasany avatar antti avatar bobmulder avatar callmesoul avatar falstack avatar felixluciano avatar floorish avatar gkatsanos avatar ifrvn avatar jpkleemans avatar kaeki avatar kingyue737 avatar mdunisch avatar nxmad avatar sergiocarracedo avatar thy3634 avatar yooouuri 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  avatar  avatar  avatar

vite-svg-loader's Issues

import not found: createElementVNode

I'm using typescript and I've followed the guide as set out in the README but I get the error import not found: createElementVNode in the console.

vite.config.js

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import svgLoader from "vite-svg-loader";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    svgLoader({
      svgoConfig: {
        multipass: true,
      },
    }),
  ],
});

I'm importing like this:

<script lang="ts" setup>
import Test from "../test.svg?component";
</script>

import.meta.globEager not working

// vite.config.ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import svgLoader from 'vite-svg-loader';
import legacy from '@vitejs/plugin-legacy';
import hmrFollow from 'vite-plugin-hmr-follow';
import path from 'path';
export default defineConfig({
  plugins: [
    vue(),
    svgLoader(),
    legacy({
      targets: ['defaults', 'not IE 11'],
    }),
    hmrFollow(),
  ],
  server: {
    host: '127.0.0.1',
    port: 8001,
  },
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src'),
    },
  },
  build: {
    sourcemap: false,
  },
});

// --------------------------------------
// any_file.ts

const modules = import.meta.globEager('@/assets/svg/*.svg', { as: 'url' });
  for (const path in modules) {
    const mod = modules[path];
    console.log(path, mod);
    // got <string>, <object>, instead of <string>, <string>
  }

style tag are gone

If svg file contains style tag.
There will only render defs tag without style tag.

This plugin should have more options such as prefixIds.

How to configure plugins

Hi!

I am trying to configure some plugins such as cleanupIDs and prefixIds.
This is my configuration but the loader returns an error
[plugin:svg-loader] Plugin name should be specified

I am using the same SVGs multiple times in the same page but they won't be displayed correctly because of conflicting IDs.

# vite.config.ts
....
       svgLoader({
           svgoConfig: {
               multipass: true,
               plugins: [
                   {
                       prefixIds: {
                           prefix: ({ path }: { path: string }) => basename(path, '.svg'),
                           delim: '-',
                       },
                   },
                   { removeDoctype: true },
                   { removeComments: true },
                   { cleanupIDs: true },
                   { collapseGroups: true },
                   { removeEmptyContainers: true },
                   { removeUnknownsAndDefaults: { keepDataAttrs: false } },
               ],
           },
       }),

Could I get some advice on how to configure plugins? Many thanks!

Vulnerable dependencies

Hello,

running npm audit on this package gives me 4 critical vulnerabilities (for which dependabot nags me). I recommend to upgrade these packages, and if you would like to know more about the vulnerabilities, just run the npm audit command.
The lint script still passes after running npm audit fix.

Cannot load svg with ?url

Hi,

Great job it works great but sometimes I need to load the SVGs from their URL and this library disables the possibility, could you allow such imports ?

Thank you

Adding attributes to the <svg> element, besides `class`

I was wondering, if there is a way that we can somehow get other attributes to appear on the <svg> element? I when using inline SVG for icons or purely decorative elements, it'd be important to tell screenreaders to ignore this element via aria-hidden="true".

Is it possible to import icons from an S3 in production ?

Hello !

At work, we have a workflow where SVGs are automatically optimized and put on an S3 service to be directly distributed and avoid a HIT on our servers.

I was wondering if it was possible (or conceivable) that during the production build, it loads the icons from an S3 server.
For example, we have a manifest.json file that contains all the imports and their chunked matches, we could on the fly point to S3 directly.

I mean, I know it's a bit peculiar but it would be cool if there was a way to do that
Kind regards

Usage with SVGO (Imagemin)

Hi. Any docs how to use this plugin together with SVGO?
Plugin alone on fresh Vue 3 + Vite works well. Unfortunately after adding vite-plugin-imagemin with SVGO build-in I have two issues (after build):

  1. SVG via import is not compressed at all.
  2. SVG as normal asset <img src="" /> looks like this:
    <img src="function c(n,s){return e(),t(&quot;svg&quot;,r,[l])}" alt="">
    Thing is - after removing "vite-svg-loader" everything works, I can get my optimized .svg file. This plugin should work only with .svg files imported as component, but somehow it messes with my .svg assets and imagemin. Why?

vite.config.ts

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import viteSvgLoader from 'vite-svg-loader'
import viteImagemin from 'vite-plugin-imagemin'
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    viteImagemin(),
    viteSvgLoader(),
  ]
})

Component

<template>
  <img src="/src/assets/images/header/news.svg" alt="Test as asset">
  <NewsIcon />
</template>

<script lang="ts">
  import { defineComponent } from 'vue'
  import NewsIcon from '/src/assets/images/header/news.svg'

  export default defineComponent({
    name: 'App',
    components: {
      NewsIcon
    }
  })
</script>

Result

<img src="function m(a,n){return e(),t(&quot;svg&quot;,i,[c])}" alt="Test as asset">
<svg xmlns="http://www.w3.org/2000/svg" width="21" height="20" viewBox="0 0 21 20">UNCOMPRESSED SVG SOURCE</svg>

doesn't work with alias

import ErrorSvg from "../../src/assets/icons/error.svg?component";
console.log("ErrorSvg", ErrorSvg);

works.

import ErrorSvg from "@/assets/icons/error.svg?component";
console.log("ErrorSvg", ErrorSvg);

always logs a base64-encoded url.

relevant vite config:

  plugins: [
    vue(),
    svgLoader({
      defaultImport: "component", // or 'raw' or 'url'
    }),
  ],
  resolve: {
    alias: [{ find: "@", replacement: "./src" }],
  },

dynamically import not working when build

@jpkleemans Hi, I used this but failed when build for production.
It's working in dev mode

<script lang="ts">
  import { computed, defineComponent, defineAsyncComponent } from 'vue'
  export default defineComponent({
    props: {
      name: {
        type: String,
        default: undefined,
      },
    },
    setup(props) {
      const currentIcon = computed(() => defineAsyncComponent(() => import(`../../icons/${props.name}.svg?component`))).value
      return {
        currentIcon
      }
    }
  })
</script>

SVG <style> definitions removed when loaded as component

Hi,
When I include style definitions in a <style> tag, the tag including the styles are being removed when loaded as inline svg using the svg loader. Is this an intended behaviour? I would like to include style definitions and deliver them with the svg within the <svg> tag. Is there a way to preserve the style definitions within the svg?

Sample markup:

logo.svg file:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 234.86 58.25">
  <style>
    .dash-grey { fill: #706f6f; }
    .dash-rose { fill: #ea719a; }
    .dash-teal { fill: #1c9fb2; }
    .dash-teal-light { fill: #7ecbd8; }
    .dash-yellow { fill: #f7bc03; }
  </style>
  <g class="icon">
      [...]
   </g>
</svg>

What is rendered:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 234.86 58.25" class="logo" height="20" data-v-81440b78=""><g class="icon">[...]</g></svg>

Desired rendering:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 234.86 58.25" class="logo" height="20" data-v-81440b78=""><style> 
  .dash-grey { fill: #706f6f; } 
  .dash-rose { fill: #ea719a; } 
  .dash-teal { fill: #1c9fb2; } 
  .dash-teal-light { fill: #7ecbd8; } 
  .dash-yellow { fill: #f7bc03; }
  </style><g class="icon">[...]</g></svg>

The loaded SVG should include the style defintions from the SVG file.

Thanks for your help.

Changing the default import option when no query params are given

Currently an svg without a query param is imported as a Component. Is it possible to change that to the ?url behavior instead?

Generally, I'm importing svgs as <img/> in Vue templates/CSS, and occasionally use the ?component query param to get a component instead. But all those <img/> need a ?url query param, otherwise they're not loaded when using Vite build.

It's a bit weird to add these ?url params everywhere, e.g.:

.some-class {
    background: url('/src/assets/arrow.svg?url');
}
<img src="/src/assets/arrow.svg?url">

Particularly because the default for other assets is without query params:

.some-class {
    background: url('/src/assets/arrow.png');
}
<img src="/src/assets/arrow.png">

And if you accidentally forget the ?url param you'll only notice missing assets when using vite build. When using vite dev the assets are still shown correctly, so they're hard to spot when developing.

Changing the default would be a breaking change, so instead a plugin config option that sets the default would be nice to have.

Uncaught DOMException: Failed to execute 'createElement' on 'Document' when loading from public

I get this error when im trying to load a svg file as component from public/:
Uncaught DOMException: Failed to execute 'createElement' on 'Document': The tag name provided ('/icons/moon.svg?component') is not a valid name.

image

My structure:
image

My env.d.ts:

/// <reference types="vite/client" />
/// <reference types="vite-svg-loader" />

My vite.config.ts:

import { fileURLToPath, URL } from 'url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

import svgLoader from 'vite-svg-loader'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue(), svgLoader()],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})

Repo:
https://github.com/Backifyco/backify-font-logo-finder

Vite dev build works perfectly; production build does not load raw SVGs

I have a Vue 2 + Vite project utilizing this plugin.

import svgLoader from 'vite-svg-loader'
...
svgLoader({
  defaultImport: 'raw'
})

When I run vite (or yarn dev) everything works fine and all svg assets are properly rendered.

When I build for production, the assets are instead loaded as a url (I think?) and just the asset path is outputted into the DOM
image

I can't seem to put together a decent reproduction, but I'm happy to provide more info or pair as needed.

Click to expand more info

I also control the repository these icons are sourced from. That repository utilizes webpack and Vue 2, and includes a svg rule in the chainWebpack config like this:

svgRule.uses.clear()
svgRule
  .oneOf('external')
  .resourceQuery(/external/)
  .use('url')
  .loader('url-loader')
  .options({
    limit: 10000,
    name: 'img/[name].[hash:7].[ext]'
  }).end().end()
  .oneOf('normal')
  .use('raw')
  .loader('raw-loader')
  .end().end()

If you look above, this is where the asset URLs (with the hash) are being generated from; however, I can't figure out how to get around this.

index.d.ts 不是模块

文件“d:/project/djcars-newpc-web/node_modules/vite-svg-loader/index.d.ts”不是模块。

"types": ["vite-svg-loader", "vite/client"],

[vite] Internal server error: Failed to resolve import "./banner.svg?component"

"vite": "^2.9.2",
"vite-svg-loader": "^3.2.0",

tsconfig.json
{ "compilerOptions": { "target": "esnext", "useDefineForClassFields": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "strict": true, "jsx": "preserve", "sourceMap": true, "isolatedModules": false, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "typeRoots": [ "./@types" ], "lib": [ "esnext", "dom" ] }, "include": [ "@types/*.d.ts", "src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue" ], "references": [ { "path": "./tsconfig.node.json" } ] }

then,show the error:

下午11:07:21 [vite] Internal server error: Failed to resolve import "./banner.svg?component" from "src/pages/test/index.vue". Does the file exist?
Plugin: vite:import-analysis
File: /Users/glodon/workspace/glodon/mls-web/src/pages/test/index.vue
4 | import { ref } from "vue";
5 | import { UploadFilled } from "@element-plus/icons-vue";
6 | import IconComponent from "./banner.svg?component";
| ^
7 | const _sfc_main = /* @PURE */ _defineComponent({
8 | emits: ["onChange"],

the file 'banner.svg' had exists!

Support ?raw parameter to get the string instead of a component

Hi !

99% of the time we want a component but it happens that we need to have the raw value of an svg.
Currently in those cases it's not possible to have the raw value of the file as it is without the plugin.
It'd be awesome if this parameter was added.

SVG is loading is not loading as a component

Hi
The plugin does not seem to load the svg file as a component.

I imported svg file like this:

import ThankYou from '/images/illustrations/placeholders/thankyou.svg?component';

I also setup vite.config.ts like so:

svgLoader({
   defaultImport: 'component',
})

Despite all that I get this error:

Uncaught (in promise) DOMException: Failed to execute 'createElement' on 'Document': The tag name provided ('/images/illustrations/placeholders/thankyou.svg?component') is not a valid name

I am using version 3.4.0, which supposed to solve this issue as stated here: #51

?component loader doesn't work with vitest

Hey,

Thanks for the library, it allows us to style svgs using currentColor.
I have an issue during testing however. I created a vue project using the getting started guide: https://vitejs.dev/guide/#scaffolding-your-first-vite-project

This configures vitest which uses the same vite.config.ts as the app during development.
However during tests I get the following errors:

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Failed Tests 2 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯

 FAIL  src/screens/IssueDetails.test.ts > IssueDetails > renders properly
Error: Failed to fully serialize error: 'get name' called on an object that is not a valid instance of DOMException.
Inner error message: "/src/assets/icons/arrow-left.svg?&component" did not match the Name production
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/2]⎯

 FAIL  src/screens/IssueDetails.test.ts > IssueDetails > can access methods from the imported component
Error: Failed to fully serialize error: 'get name' called on an object that is not a valid instance of DOMException.
Inner error message: "/src/assets/icons/arrow-left.svg?&component" did not match the Name production
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/2]⎯

Test Files  1 failed (1)
     Tests  2 failed (2)
      Time  1.57s (in thread 41ms, 3819.19%)

It seems that this svg-loader is doing something different when being run through vitest, but I don't know why.

svg file still in build dist

this plugin set enforce: pre, but svg file still handled by vite assets plugin
if transform program move to load, seem to fix it

Transforming Vue 3 components for unit testing with Jest

If you need to transform Vue 3 components created using Vite SVG Loader for the purpose of Jest unit testing:

  1. Create a mock component. I saved mine to the tests directory.
<template>
  <svg />
</template>

You could alternatively use jest-transform-stub, but it may log warnings to the console. Plus this way the rendered HTML includes an <svg> tag.

  1. Update your jest.config.js to transform SVG components into the mock component:
// jest.config.js
module.exports = {
  transform: {
    "^.+\\.[t|j]sx?$": "babel-jest",
    "^[^.]+.vue$": "@vue/vue3-jest",
  },
  testMatch: ["**/tests/**/*.spec.js"],
  moduleFileExtensions: ["js", "vue"],
  moduleNameMapper: {
    ".+\\.(svg)(\\?component)?$": "<rootDir>/tests/svgMock.vue",
    "^@/(.*)$": "<rootDir>/src/$1",
  },
  testEnvironment: "jsdom",
  collectCoverage: true,
}

I've included my entire jest.config.js file for reference, but the key part is here:

module.exports = {
  ...
  moduleNameMapper: {
    ".+\\.(svg)(\\?component)?$": "<rootDir>/tests/svgMock.vue",
    ...
  },
  ...
}

Now all components created using Vite SVG Loader will be automatically transformed to the mock component.

Public path not matched when build

Hello, when I try to use a svg from public path it works in the dev server, but breaks in build.
image

If I v-bind the image src in the template with the same path, it surprisingly works, even in build
image

Any thoughts on why i get an error trying to build a simple svg? I'm not even trying to import as a component...

adding a class to the svg tag?

If I wanted to add a class to the svg tag - is there a way to do it?
currently -

...

would like it to be more like

...

svg property changes

Is it possible with this lib to change svg properties like fill color, border color, etc?

`?url` causes tests to fail

First of all, thank you for your work! It really helped a lot while reworking a whole project with vue3 and vite.
While testing with only importing without any prefix I could get it running.
But I stumbled across a problem while unit testing my components.
I imported a svg in order to use it as a background-image:

import CloudsSvg from '~client/assets/svg/registration_animation_clouds.svg?url'

<div :style="{ backgroundImage: `url(${CloudsSvg})` }" >

In dev and prod build everything runs fine, but the test keeps failing.
I tried the approach from here: #35
My jest.config.js looks like this:

const esModules = ['lodash'].join('|')

module.exports = {
  rootDir: process.cwd(),
  displayName: {
    name: 'nodejs',
    color: 'blueBright',
  },
  moduleFileExtensions: ['js', 'json', 'ts', 'tsx'],
  moduleNameMapper: {
    '.+\\.(svg?url)$': '<rootDir>/configs/tests/__mocks__/svgUrlMock.ts',
    '^.*\\.svg$': '<rootDir>/configs/tests/__mocks__/svgMock.vue',
    '^.*\\.scss$': '<rootDir>/configs/tests/__mocks__/scssMock.vue',
    '^~configs(.*)$': '<rootDir>/configs/$1',
    '^~engine(.*)$': '<rootDir>/src/engine/$1',
    '^~client(.*)$': '<rootDir>/src/client/$1',
  },
  setupFiles: ['<rootDir>/configs/tests/utils/setEnvVars.js'],
  setupFilesAfterEnv: [
    '<rootDir>/configs/tests/utils/preload.js',
    '<rootDir>/configs/tests/utils/ignoreWarn.js',
    '<rootDir>/configs/tests/utils/ignoreError.js',
  ],
  testEnvironment: 'node',
  testEnvironmentOptions: {
    customExportConditions: ['node', 'node-addons'],
  },
  testRegex: ['__tests__\\/[A-Za-z_.]*\\.(service|node|redirect)\\.(spec|test)\\.ts?$'],
  transform: {
    '\\.[jt]sx?$': 'babel-jest',
  },
  transformIgnorePatterns: [`<rootDir>/node_modules/(?!(${esModules})/)`],
  verbose: false,
}

I know the problem is '.+\\.(svg?url)$': '<rootDir>/configs/tests/__mocks__/svgUrlMock.ts',, but I can't find a working solution.
Is there a clever way to do this, or is it possible to add native jest support?
Thanks in advance!

New release

Hey there,

Would you be able to release a new version of vite-svg-loader? There's a fix that was made in ce3e75e that I could really use that wasn't part of 3.5.1.

Type error

Hi,

Thanks for this loader! I'm using it in Vue 3 with TypeScript, and I'm getting the following Vetur warning in VS Code for each SVG in the line that says something like components: { MyLogo }:

No overload matches this call.
  The last overload gave the following error.
    Type 'string' is not assignable to type 'Component<any, any, any, Record<string, ComputedGetter<any> | WritableComputedOptions<any>>, MethodOptions>'

Is there a way to inform TypeScript that the result of that import { MyLogo } from "mylogo.svg" will, in fact, be a Component, not a string?

Everything still works fine, it's just a red-squiggly issue.

Vue 2 support

Any plans to support vue 2?

I have this error in a vite project with vue 2:

Uncaught SyntaxError: The requested module '/node_modules/.vite/vue.js' does not provide an export named 'Fragment

Thanks

Storybook build - Unknown variable dynamic import: ./{filename}.svg?component

I have a library built using Vite (in library mode) + Vue3 + Storybook + TypeScript and I am facing problems building the project and/or building Storybook when Vite-SVG-Loader is used.

The component that uses a SVG:

<script setup lang="ts">
import { computed, defineAsyncComponent } from "vue";

const props = withDefaults(defineProps<{ name: string }>(), {
  name: 'add'
});

const iconComponent = computed(() => {
  return defineAsyncComponent(
    () => import(`./assets/${props.name}.svg?component`)
  );
});
</script>

<template>
  <component :is="iconComponent" />
</template>

Scenario 1
By keeping the ?component on the URL for the defineAsyncComponent function, vite build and start-storybook works perfectly fine but although build-storybook runs fine, when you try to access a component on storybook that uses the async loaded SVG you get the following error:

Unknown variable dynamic import: ./assets/add.svg?component
Error: Unknown variable dynamic import: ./assets/add.svg?component
at http://127.0.0.1:8080/assets/iframe.d31911ec.js:930:5989
at new Promise ()
at variableDynamicImportRuntime0 (http://127.0.0.1:8080/assets/iframe.d31911ec.js:930:5886)
at http://127.0.0.1:8080/assets/iframe.d31911ec.js:930:6317
at pe (http://127.0.0.1:8080/assets/iframe.d31911ec.js:119:21340)
at setup (http://127.0.0.1:8080/assets/iframe.d31911ec.js:119:22194)
at callWithErrorHandling (http://127.0.0.1:8080/assets/iframe.d31911ec.js:119:848)
at setupStatefulComponent (http://127.0.0.1:8080/assets/iframe.d31911ec.js:119:68463)
at setupComponent (http://127.0.0.1:8080/assets/iframe.d31911ec.js:119:68106)
at Ht (http://127.0.0.1:8080/assets/iframe.d31911ec.js:119:47236)

Scenario 2
On the other hand, by removing the ?component, everything Storybook related works but the vite build throws the following error:

Invalid value "umd" for option "output.format" - UMD and IIFE output formats are not supported for code-splitting builds.
error during build:
Error: Invalid value "umd" for option "output.format" - UMD and IIFE output formats are not supported for code-splitting builds.
at error (./node_modules/rollup/dist/shared/rollup.js:198:30)
at validateOptionsForMultiChunkOutput (./node_modules/rollup/dist/shared/rollup.js:16207:16)
at Bundle.generate (./node_modules/rollup/dist/shared/rollup.js:16041:17)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async ./node_modules/rollup/dist/shared/rollup.js:23679:27
at async catchUnfinishedHookActions (./node_modules/rollup/dist/shared/rollup.js:23121:20)
at async doBuild (./node_modules/vite/dist/node/chunks/dep-27bc1ab8.js:39180:26)
at async build (./node_modules/vite/dist/node/chunks/dep-27bc1ab8.js:39011:16)
at async CAC. (./node_modules/vite/dist/node/cli.js:738:9)

My project configuration

Packages used:

  • storybook-builder-vite: ^0.1.23
  • @storybook/vue3: ^6.5.0-alpha.55
  • typescript: ~4.5.5
  • vite: ^2.9.5
  • vite-plugin-vue-type-imports: ^0.1.3
  • vite-svg-loader: ^3.2.0

Vite setup

import { fileURLToPath, URL } from "url";
import { defineConfig } from "vite";
import path from "path";
import vue from "@vitejs/plugin-vue";
import ViteSvgLoader from "vite-svg-loader";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue(), ViteSvgLoader()],
  resolve: {
    alias: {
      "@": fileURLToPath(new URL("./src", import.meta.url)),
    },
  },
  build: {
    lib: {
      entry: path.resolve(__dirname, "src/main.ts"),
      name: "DesignSystem",
      fileName: (format) => `index.${format}.js`,
    },
    rollupOptions: {
      external: ["vue"],
      output: {
        globals: {
          vue: "Vue",
        },
      },
    },
  },
});

Storybook main.js

const ViteSvgLoader = require('vite-svg-loader')

module.exports = {
  ...
  "framework": "@storybook/vue3",
  "core": {
    "builder": "storybook-builder-vite"
  },
  async viteFinal(config, { configType }) {
    config.plugins.push(ViteSvgLoader());
    return config;
  },
}

Any ideas?

vite svg loader with typescript gives error when running jest test

    Configuration error:
    
    Could not locate module @assets/images/icon-calendar.svg?component mapped as:
    /Users/ahmedyagoub/plankk/phoenix/src/assets/$1.
    
    Please check your configuration for these entries:
    {
      "moduleNameMapper": {
        "/@assets\/(.*)/": "/Users/ahmedyagoub/plankk/phoenix/src/assets/$1"
      },
      "resolver": undefined
    }
    ```

[Vue warn]: Failed to resolve component:

enviroment

"vite-svg-loader": "^3.1.2",
"vite": "^2.8.0"

Error

[Vue warn]: Failed to resolve component: temperature
If this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement.
at <TemAndHumi>
at <Board onVnodeUnmounted=fn ref=Ref< undefined > >
at <RouterView>
at <App>

detail

I import a temperature.svg as a component in my TemAndHumi.vue component,and use it by <temperature></temperature>
.but it produced a warn in console.I don't why it appeard in.

color disappear

when i was using the order'?component', my illustration missed partial color.
test

Non-prop attributes are not being inherited

When transforming an svg to a component and trying to add an attribute, like `data-testid, and it's not being rendered

Example:

<template>
  <div id="app">
    <Icon style="flex: 1" class="icon" data-testid="asfg"/>
  </div>
</template>

<script setup>
import Icon from './icons/icon.svg';
</script>

Render as:

<div id="app">
  <svg class="icon" viewBox="0 0 360 264" fill="none" xmlns="http://www.w3.org/2000/svg" style="flex: 1 1 0%;">
    ...
  </svg>
</div>

Typescript errors in 3.5.0

importing @something/filename.svg?component gives typescript error TS2307: Cannot find module in version 3.5.0. It works fine in 3.4.0.

Guessing it has something to do with the removed imports within the *.svg?component module.

image

How can we dynamically import svg files?

I am not sure if this loader supports this:

  computed: {
    currentIcon() {
        return () => import('path/to/svg/file.svg');
    }
  }

and then we can use as

<template>
  <compoment
    :is="currentIcon"
    :aria-hidden="hidden"
  />
</template>

Currently console output as

runtime-core.esm-bundler.js:38 [Vue warn]: Invalid VNode type: undefined (undefined) 
  at <Anonymous is=fn aria-hidden=true > 
  at <UiIcon name="notification" > 

Set tag attributes to svg

Current behaviour:
If we write this code

<script lang="ts" setup>
  import User from '@/assets/icons/user.svg';
</script>

<template>
  <User style="color: red" data-test="some-string" />
</template>

we will see this html output

<svg style="color: red">...</svg>

There are no data-test or any other attibutes

Expected behaviour:
All attributes that we pass to icon should appear

Way to dynamic import a huge set of icons as component?

I'm new to Vite 2.0 project, and I used to use Vuetify in Vue 2.0, and it has a easy-to-use component v-icon allows me just to find the icons name and use it in other components/views. Now I want to try different icon sets, for example fluentui-system-icon. Is there a way to do this? I have no idea about this.

Vite Error: Unrestricted file system access ...

Hey there, thanks for creating this plugin. Exactly what I needed.
There is just an error on every dev-server startup that notifies me that this package will break in future vite versions because of file system access. The error message:

Unrestricted file system access to "/notes/function render(_ctx, _cache) {  return (_openBlock(), _createElementBlock("svg", _hoisted_1, _hoisted_3))}"
For security concerns, accessing files outside of serving allow list will be restricted by default in the future version of Vite. Refer to https://vitejs.dev/config/#server-fs-allow for more details.

Now everything works. But I guess this is not something to ignore.

How to have a dynamic import SVG component

Hello,

I have an issue when building the Vue (2.7) app:

[plugin:vite:dynamic-import-vars] invalid import "/icons/${this.name}.svg?raw". Variable absolute imports are not supported, imports must start with ./ in the static part of the import. For example: import(./foo/${bar}.js).

We're using this component everywhere in our application.
SwIcon.vue :

<template lang="pug">
  div
    span.block(
      :class="[styleClass, sizeClass]"
      :style="{strokeLinecap: 'round', strokeLinejoin: 'round'}"
      @click="$emit('click')"
      v-html="svgRawContent"
    )
</template>

<script>
export default {
  name: 'SwIcon',
  props: {
    name: {
      type: String,
      default: '',
    },
    unstyled: {
      type: Boolean,
      default: false,
    },
    size: {
      type: String,
      default: 'w-6 h-6',
    },
  },
  data () {
    return {
      svgRawContent: '',
    };
  },
  computed: {
    sizeClass () {
      return this.size;
    },
    styleClass () {
      return this.unstyled ? '' : 'fill-none stroke-current stroke-2';
    },
  },
  // Todo: Replace by Suspense or something else when upgrading to Vue 3 to avoid async lifecycle method
  async mounted () {
    const svgObject = await import(`/icons/${this.name}.svg?raw`);
    this.svgRawContent = svgObject.default;
  },
};
</script>

Like you can see, we have this import await import(`/icons/${this.name}.svg?raw`); which is working good in development.

I guess the problem comes from the fact that during the build phase, since it is dynamic, it is not able to bundle the svg since it does not know them.

But then, how can I keep a similar component and make it work? Even if it has to bundle the whole icon's folder, it's not a big deal if it's lazy loaded.

Thanks in advance, I appreciate it ❤️

PS: I have already check #24, but I don't understand well for my case :/

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.