Atta ur Rehman
Atta ur Rehman

Reputation: 91

Inline SVG in vuejs component

I have created a Vuejs project using @vue/cli version 3.0.0-beta.16 and in my Home.vue single file component I want to import and add inline SVG in the template but I am having trouble doing so.

The problem is vue cli is already using .svg file extension for file-loader like so:

webpackConfig.module
  .rule('svg')
    .test(/\.(svg)(\?.*)?$/)
    .use('file-loader')
      .loader('file-loader')
      .options({
        name: getAssetPath(options, `img/[name].[hash:8].[ext]`)
      })

I have already tried using the html-loader plugin for including svg in the template and it works fine if I clear the svg default use in my vue.config.js and add my own loader like this:

// vue.config.js

chainWebpack: config => {
    const svgRule = config.module.rule('svg')

    // clear all existing loaders.
    // if you don't do this, the loader below will be appended to
    // existing loaders of the rule.
    svgRule.uses.clear()

    // add replacement loader(s)
    svgRule
    .test(/\.(svg)$/)
    .use('html-loader')
    .loader('html-loader')
    .options({
    })
}

and in my template:

// Home.vue

<div v-html="require('./../assets/inline.svg')"></div>

But the problem is it also replaces svg src in the <img /> tags with inline svg code. What I want is use file-loader for <img src="something.svg" /> and use html-loader for require('./inline.svg'). How do I use multiple loaders for same rule in webpack? Or is it the right approach? Any help would be appreciated.

Edit I think the problem is I'm adding the both loaders the wrong way. This is how I add them in my file:

// vue.config.js

svgRule
.test(/\.(svg)$/)
.use('file-loader')
.loader('file-loader')
.options({
  name: getAssetPath(options, `img/[name].[ext]`)
})

svgRule
.test(/\.(svg)$/)
.use('html-loader')
.loader('html-loader')
.options({
  attrs: ['div:v-html']
})

Upvotes: 9

Views: 18683

Answers (4)

Orlandster
Orlandster

Reputation: 4868

If you don't have html-loader installed simply execute

yarn add -D html-loader

Then add the following object to the rules array in your webpack config file:

{
  test: /\.svg$/,
  use: [{ loader: 'html-loader' }]
}

And finally, you will be able to import svg files to your scripts with the inline loader.

require('!html-loader!./../assets/inline.svg')

// or directly in your v-html directive
<div v-html="require('!html-loader!./../assets/inline.svg')"></div>

Upvotes: 5

Igonato
Igonato

Reputation: 10806

You can add a leading ! in the require expression to "override" existing loaders set up by the webpack config.

<div v-html="require('!html-loader!./../assets/inline.svg')"></div>

This will work without changes to the vue.config.js (as long as html-loader is installed)


Also, instead of using html-loader look into svg-inline-loader in can add hashes to classes and ids, so you don't need to worry about name collisions if you have multiple inline svgs on your page.

Upvotes: 6

hlobit
hlobit

Reputation: 166

You may want to use both webpack loaders, but also to tell your html loader to restrict to div elements with v-html with the following syntax in the loader options:

{
  attrs: ['div:v-html']
}

Docs for the html loader are found there.

Upvotes: 0

Lars Beck
Lars Beck

Reputation: 3584

You're almost there, just tell Webpack which loader to use:

<div v-html="require('html-loader!./../assets/inline.svg')"/>

Upvotes: 1

Related Questions