Two Ways Use SVG Icons In vue-cli3 Based Project

June 06, 2019

Icon Font

  1. Install Dependencies
npm install --save-dev iconfont-webpack-plugin
  1. Update Config of Vue
// vue.config.js
// Add IconfontWebpackPlugin instance to plugins of postcss-loader options
const IconfontWebpackPlugin = require("iconfont-webpack-plugin");

function tapPostcssLoaderOptions(config, moduleRule, rule) {
  config.module
    .rule(moduleRule)
    .oneOf(rule)
    .use("postcss-loader")
    .loader("postcss-loader")
    .tap(options => {
      const iconFontOptions = {
        plugins: loader => {
          return [new IconfontWebpackPlugin(loader)];
        },
      };
      Object.assign(options, iconFontOptions);
      return options;
    });
}

function configIconFont(config) {
  // Sass is the pre-processor of my project
  // Replace with yours
  //
  // Tips
  // Use `vue inspect --rules` view rules used in project
  // Use `vue inspect --rule scss` view special rule
  const moduleRules = ["scss", "css"];
  const rules = ["normal", "normal-modules", "vue", "vue-modules"];
  for (let i = 0; i < moduleRules.length; i++) {
    const moduleRule = moduleRules[i];
    for (let i = 0; i < rules.length; i++) {
      const rule = rules[i];
      tapPostcssLoaderOptions(config, moduleRule, rule);
    }
  }
}

module.exports = {
  chainWebpack: config => {
    configIconFont(config);
  },
};
  1. Usage in Component
<template>
  <div>
    <span class="class-name-use-svg-icon"></span>
  </div>
</template>

<style lang="scss">
.class-name-use-svg-icon {
  &:before {
    font-icon: url("../../src/svg-icons/spanner.svg");
  }
}
</style>

SVG sprite

  1. Install Dependencies
npm install --save-dev svg-sprite-loader svgo-loader
  1. Update Config of Vue
// vue.config.js

function configSVGIcon(config) {
  // Exclude SVG sprite directory from default svg rule
  config.module
    .rule("svg")
    .exclude.add(path.resolve(__dirname, "./src/svg-icons"))
    .end();

  // Options used by svgo-loader to optimize SVG files
  // https://github.com/svg/svgo#what-it-can-do
  const options = {
    plugins: [
      { cleanupAttrs: true },
      { cleanupEnableBackground: true },
      { cleanupIDs: true },
      { cleanupListOfValues: true },
      { cleanupNumericValues: true },
      { collapseGroups: true },
      { convertColors: true },
      { convertPathData: true },
      { convertShapeToPath: true },
      { convertStyleToAttrs: true },
      { convertTransform: true },
      { mergePaths: true },
      { removeComments: true },
      { removeDesc: true },
      { removeDimensions: true },
      { removeDoctype: true },
      { removeEditorsNSData: true },
      { removeEmptyAttrs: true },
      { removeEmptyContainers: true },
      { removeEmptyText: true },
      { removeHiddenElems: true },
      { removeMetadata: true },
      { removeNonInheritableGroupAttrs: true },
      { removeRasterImages: true },
      { removeTitle: true },
      { removeUnknownsAndDefaults: true },
      { removeUselessDefs: true },
      { removeUnusedNS: true },
      { removeUselessStrokeAndFill: true },
      {
        removeAttrs: { attrs: "fill" }, //移除fill属性
      },
      { removeXMLProcInst: true },
      { removeStyleElement: true },
      { removeUnknownsAndDefaults: true },
      { sortAttrs: true },
    ],
  };

  // Include only SVG sprite directory for new svg-icon rule
  // Use svg-sprite-loader to build SVG sprite
  // Use svgo-loader to optimize SVG files
  config.module
    .rule("svg-icon")
    .test(/\.svg$/)
    .include.add(path.resolve(__dirname, "./src/svg-icons"))
    .end()
    .use("svg-sprite-loader")
    .loader("svg-sprite-loader")
    .options({
      symbolId: "icon-[name]",
    })
    .end()
    .use("svgo-loader")
    .loader("svgo-loader")
    .options(options)
    .end();
}

module.exports = {
  chainWebpack: config => {
    configSVGIcon(config);
  },
};
  1. Create A Component
// src/components/SvgIcon.vue
<template>
  <svg :class="svgClass" aria-hidden="true">
    <use :xlink:href="name"></use>
  </svg>
</template>

<script>
// https://webpack.js.org/guides/dependency-management/#context-module-api
const requireAll = requireContext => requireContext.keys().map(requireContext);
const req = require.context("../svg-icons", false, /\.svg$/);
requireAll(req);

export default {
  name: "SvgIcon",
  props: {
    iconName: {
      // icon filename
      type: String,
      required: true,
    },
    className: {
      // css class name
      type: String,
      default: "",
    },
  },
  computed: {
    name() {
      let icon = this.iconName;
      return icon ? `#icon-${icon}` : "";
    },
    svgClass() {
      let className = this.className;
      return className ? `svg-icon ${className}` : "svg-icon";
    },
  },
};
</script>

<style>
.svg-icon {
  width: 1em;
  height: 1em;
  fill: currentColor; /* important */
  overflow: hidden;
}
</style>
  1. Usage
// Remember to copy svg files to svg-icons directory under src
<template>
  <div>
    <svg-icon icon-name="settings"></svg-icon>
  </div>
</template>

<script>
import SvgIcon from "@/components/SvgIcon";

export default {
  components: {
    SvgIcon,
  },
};
</script>

Useful Resources


Profile picture

Written by Priestch who lives and works in Xi'an building useful things. You can follow him on Github