storybook: Load svg using vue-svg-loader not working

.storybook/webpack.config.js

const path = require('path');
const fs = require('fs');

// Export a function. Accept the base config as the only param.
module.exports = async ({ config, mode }) => {
  // `mode` has a value of 'DEVELOPMENT' or 'PRODUCTION'
  // You can change the configuration based on that.
  // 'PRODUCTION' is used when building the static version of storybook.
  // Make whatever fine-grained changes you need
  config.module.rules.push({
    test: /\.scss$/,
    use: [
      "style-loader", // creates style nodes from JS strings
      "css-loader", // translates CSS into CommonJS
      "sass-loader" // compiles Sass to CSS, using Node Sass by default
    ]
  });
  config.module.rules.push({
    test: /\.(png|jpg|gif)$/,
    use: [
      {
        loader: 'file-loader',
        options: {name: 'assets/[name].[hash:8].[ext]'},
      },
    ],
  });
  config.module.rules.push({
    test: /\.vue$/,
    use: [
      {
        loader: "vue-svg-inline-loader",
        options: { /* ... */ }
      }
    ]
  });
  config.module.rules.push({
    test: /\.svg$/,
    loader: 'vue-svg-loader',
    options: {name: 'assets/[name].[hash:8].[ext]'},
  });
  config.resolve.alias['@'] = path.resolve('src')

  // Return the altered config
  return { ...config, node: { fs: 'empty' } };
};

index.vue

<template>
  <div>
     <IconTest/>
  </div>
</template>
<script>
   import IconTest from "@/assets/svg/test-icon.svg"
   export default {
      components:{
         IconTest
      }
   }
</script>

error: [Vue warn]: Invalid Component definition: static/media/test-icon.d9ed9e17.svg

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 2
  • Comments: 19 (5 by maintainers)

Most upvoted comments

@devtoni’s workaround worked for me too, with one additional change.

As of Storybook v6.9.0, I had to add pdf to the test regex that was being replaced. The updated code that worked for me is:

  config.module.rules = config.module.rules.map(rule => {
    if (String(rule.test) === String(/\.(svg|ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/)) {
      return {
        ...rule,
        test: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/,
      };
    }
    return rule;
  });

https://github.com/storybookjs/vue-cli-plugin-storybook/issues/69#issuecomment-668171815

This config solved the issue for me:

module.exports = ({ config }) => {

    let rule = config.module.rules.find(r =>
        // it can be another rule with file loader 
        // we should get only svg related
        r.test && r.test.toString().includes('svg') &&
        // file-loader might be resolved to js file path so "endsWith" is not reliable enough
        r.loader && r.loader.includes('file-loader')
    );
    rule.test = /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani)(\?.*)?$/;

    config.module.rules.push(
        {
            test: /\.svg$/,
            use: ['vue-svg-loader']
        }
    )

    // ...

    return config;
}

Original post: https://stackoverflow.com/questions/56971513/storybook-does-not-load-svgs-in-components-of-vue-project

This config solved the issue for me: Using vite 3.0.0, vite-svg-loader 3.4.0 and storybook 6.5.9

const svgLoader = require('vite-svg-loader');

module.exports = {
    async viteFinal(config) {
        config.plugins = [
            ...config.plugins,
            svgLoader(),
        ];

        return config;
    },
    
    // ...

};

@ecarrera solution isn’t working for me - I get an error when doing that saying “You may need an additional loader to handle the result of these loaders.”

It however looks like the svg’s are correctly loaded as vue components, but storybook still fails…

image

I have also tried this approach from the documentation:

image

But since I’m using vue-cli this isn’t working either because webpack is configured in vue.config.js which doesnt have a ‘rules’ object exposed

Thanks @devtoni ! I was running into this trying to use svg-inline-loader.

I had a similar problem, the reason as shilman commented is because storybook by default in its webpack configuration is using file-loader for the svgs. So it founds a conflict with the vue-svg-loader.

What I did in my case and it works is to remove from the regex the svg extension and then as you did push the new rule of svg with the vue-svg-loader.

config.module.rules = config.module.rules.map(rule => {
        {
            if (String(rule.test) === String(/\.(svg|ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani)(\?.*)?$/)) {
                return {
                    ...rule,
                    test: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani)(\?.*)?$/,
                };
            }

            return rule;
        }
    });

friends i need your help here about Vue Storybook import SVGs components https://stackoverflow.com/questions/75432897/load-svgs-components-in-storybook-vue-not-working

Thanks @ecarrera that worked for me as well. Been struggling with this all day!

Thank you @devtoni ! Works!