storybookjs/vue-cli-plugin-storybook

Load svg using vue-svg-loader not working

gsaada opened this issue · 2 comments

.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

@gsaada There are existing rules that test for /\.vue$/ or /\.svg$/ files like you do and my guess is that they are conflicting. You should leverage Webpack include/exclude rule parameters to avoid conflicts.

Here’s an example on how to modify an existing rule in Storybook Webpack config to add an exclude option:

// .storybook/main.js
const path = require('path');

module.exports = {
  // ...
  webpackFinal: (config) => {
    // Prevent Storybook generic SVG loader from taking care of SVG icons going in the sprite
    const fileLoader = config.module.rules.find((rule, i) => {
      return rule.loader && rule.loader.match(/file-loader/);
    });
    fileLoader.exclude = path.resolve('./src/assets/icons');

    // Custom loader with an `include` to limit the loader to only icons
    config.module.rules.push({
      test: /\.svg$/,
      include: path.resolve('./src/assets/icons'),
      use: [
        {
          loader: 'svg-sprite-loader',
        },
      ],
    });
  }
  // ...
};

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