vite-svg-loader
vite-svg-loader copied to clipboard
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.
Hi, Vue doesn't support
- Use the
inlineStyles
plugin from svgo. See https://github.com/svg/svgo#built-in-plugins - Change the
style
tag tosvg:style
(VueJS parser doesn't recognize that so it will just ignore it and move on. But it's still valid HTML.), eg:
<svg>
<svg:style>
.dash-grey { fill: #706f6f; }
</svg:style>
</svg>
Thx for your fast reply and the suggested solutions. I tried the second option. However, I get the following error:
Cannot read properties of undefined (reading 'type')
[vite] Internal server error: Cannot read properties of undefined (reading 'type')
The compiler doesn't seem to accept the svg namespace markup <svg:style>
as valid svg markup.
That's strange. For me it works out of the box. Could you please share (part of) your project so I can try to find out whats going wrong?
@distor-sil3nt are you using Nuxt?
Thx for your fast reply and the suggested solutions. I tried the second option. However, I get the following error:
Cannot read properties of undefined (reading 'type') [vite] Internal server error: Cannot read properties of undefined (reading 'type')
The compiler doesn't seem to accept the svg namespace markup
<svg:style>
as valid svg markup.
Did you add the duplicate namespace in the <svg>
tag?
VVV
<svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" ...
- https://github.com/vuejs/vue/issues/4144#issuecomment-258818137
By default, SVGO does not strip classes which are used more than once, as it increases the output size.
But it's needed to be able to apply the styles, because Vue strips the style tag away. Thats why I needed to set the onlyMatchedOnce
option to false
.
svgLoader({
svgo: true,
svgoConfig: {
plugins: [
{
name: 'preset-default',
params: {
overrides: {
inlineStyles: {
onlyMatchedOnce: false,
},
},
},
},
],
},
})
Maybe it would be worth to include this snippet in the project README.md?
@distor-sil3nt are you using Nuxt?
I'm using plain Vue 3, not Nuxt in this case
Thx for your fast reply and the suggested solutions. I tried the second option. However, I get the following error:
Cannot read properties of undefined (reading 'type') [vite] Internal server error: Cannot read properties of undefined (reading 'type')
The compiler doesn't seem to accept the svg namespace markup
<svg:style>
as valid svg markup.Did you add the duplicate namespace in the
<svg>
tag?VVV <svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" ...
This actually solved the probem. With the extra namespace attribute it works without throwing errors now. Thanks a lot for your help @DrJume and also @jpkleemans
You're welcome! ☺️
I cheered to soon unfortunately. Instead of errors, I now get a warning in the console:
[Vue warn]: Failed to resolve component: svg:style
If this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement
When I try to match the svg:style
tag in compilerOptions.isCustomElement
it doesn't work since neither svg:style
nor svg
is listed in this option (handled as isNativeTag
):
vite.config.ts
:
import svgLoader from 'vite-svg-loader'
import vue from '@vitejs/plugin-vue'
export default defineConfig(async () => {
return {
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('svg:style'),
},
},
}),
svgLoader(),
[...]
],
[...]
}
})
In the docs it's saying:
Native HTML and SVG tags don't need to be matched in this function - Vue's parser recognizes them automatically.
https://vuejs.org/api/application.html#app-config-compileroptions
Do you have any idea on how to get rid of this warning?
By default, SVGO does not strip classes which are used more than once, as it increases the output size. But it's needed to be able to apply the styles, because Vue strips the style tag away. Thats why I needed to set the
onlyMatchedOnce
option tofalse
.svgLoader({ svgo: true, svgoConfig: { plugins: [ { name: 'preset-default', params: { overrides: { inlineStyles: { onlyMatchedOnce: false, }, }, }, }, ], }, })
Maybe it would be worth to include this snippet in the project README.md?
I had the same issue of svg styles disappearing. Updating the svgoConfig
(as mentioned above by @DrJume) did the trick for me 👍
Also had an issue similar to this where the viewbox attribute gets stripped off from some svgs. Fixed it with the properties below:
...
overrides: {
removeViewBox: false,
},
...