npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

vue-svg-icon-set

v0.2.0

Published

Create an optimized Vue SVG icon set

Downloads

44

Readme

vue-svg-icon-set

vue-svg-icon-set offers the tools necessary to create an optimized SVG icon set for Vue

:raising_hand: Why?

  • ⚡️ Optimized SVG usage Prevent SVGs from being inlined multiple times from your icon-set
  • 🔥 Webpack integration Seamlessly integrate with your Webpack build
  • 🦋 Light 1.27 kB minzipped for the IconLayer and 743 B for IconRegister

:rocket: Install

npm i -D vue-svg-icon-set

🚦 Quick setup

  1. Update Webpack config

    Add the following changes to your Webpack configuration so that vue-svg-icon-set can transform your SVGs and so that you can output an IconLayer.

    module.exports = {
         ...,
    
         entry: {
    +        'lib/icon-layer': 'vue-svg-icon-set/icon-layer.vue',
    
             ...iconPaths,
         },
    
         module: {
             rules: [
                 ...,
    
    +            {
    +                test: /\.svg$/,
    +                use: [
    +                    'vue-loader',
    +                    'vue-svg-icon-set/loader',
    +                ],
    +            },
             ],
         }
    };
  2. Use IconLayer

    Add the outputted icon-layer file to your application as a top-level wrapper.

    <template>
    +    <icon-layer>
             <app />
    +    </icon-layer>
    </template>
    <script>
    + import IconLayer from 'icon-library/lib/icon-layer';
    
    export default {
         components: {
    +        IconLayer
         }
    }
    </script>
  3. Use Icons

    That's it! You should be ready to start using the icons from your library. 👍

    <template>
        <thumbsup-icon style="fill:orange" />
    </template>
    
    <script>
    import ThumbsupIcon from 'icon-library/icons/thumbsup-icon';
    
    export default {
        components: {
            ThumbsupIcon
        }
    };
    </script>

⚙️ Options

  • svgComponentPath <String> The path to a custom component to use as the root of the icon component. This custom component should return a <svg> root element and can be used to add advanced behavior to the icon. For example, this custom component makes all icons appear clickable:

    <template>
        <svg
            class="icon"
            v-on="$listeners"
            v-bind="$attrs"
        >
            <slot />
        </svg>
    </template>
    
    <style scoped>
    .icon {
        cursor: pointer;
    }
    </style>
  • generateId(resourcePath) <Function> Method to generate each icon id. By default, it uses the kebab-case of the basename of the file path. You can access this method via this.kebabBaseName() in the generateId function.

    Since SVGs use ids for referencing, this method can be used to namespace the ids to minimize the possibility of collision.

    {
         test: /\.svg$/,
         use: [
             'vue-loader',
    -        'vue-svg-icon-set/loader',
    +        {
    +            loader: 'vue-svg-icon-set/loader',
    +            options: {
    +                generateId(resourcePath) {
    +                    const id = this.kebabBaseName(resourcePath);
    +                    return `namespace-${id}`;
    +                }
    +            }
    +        }
         ],
    }

🏎 Optimizations

Externalizing icon register

The icon-register.js component is used by every icon and can be abstracted out to reduce the size of each icon.

module.exports = {
     ...,

     entry: {
         'lib/icon-layer': 'vue-svg-icon-set/icon-layer.vue',
+        'lib/icon-register': 'vue-svg-icon-set/icon-register',

         ...iconPaths,
     },
     
+    externals: [
+        (from, req, cb) => {
+            if (req.endsWith('icon-register.js')) {
+                return cb(null, '../lib/icon-register.js');
+            }
+            cb();
+        },
+    ],

};

SVGO

I recommend using SVGO to optimize your SVGs. Use svgo-loader to pipe optimized SVGs to vue-svg-icon-set.

{
     test: /\.svg$/,
     use: [
         'vue-loader',
         'vue-svg-icon-set/loader',
+        'svgo-loader',
     ],
}

💁‍♂️ FAQ

How is this optimized?

SVGs can be referenced and reused like variables with the <use> element. This icon-set leverages this feature to define referencable SVGs so that repeated usage of an icon isn't duplicated in the DOM.

Demo on JSFiddle

<!-- Defined SVGs aka IconLayer -->
<svg style="display: none">
  <defs>
    <svg id="plus">
      <path d="M8 2V14M2 8H14" stroke="black" stroke-width="2" />
    </svg>

    <svg id="circle">
      <circle cx="8" cy="8" r="8" fill="black" />
    </svg>
  </defs>
</svg>


<!-- Use "plus" icon -->
<svg class="icon" width="16" height="16">
  <use href="#plus" />
</svg>

<!-- Use "circle" icon -->
<svg class="icon" width="16" height="16">
  <use href="#circle" />
</svg>

What's the IconLayer for?

The IconLayer is a component that declares the SVG definitions so they're referenceable across the document. It injects an API so that all icons can communicate with it and register an icon to be defined.

Does this work with SSR?

Yes! However, the SVG will not be inlined in the server-rendered document. It's actually a technical limitation because each icon usages hoists up the SVG rendering to happen in the parent IconLayer, and SSR only renders once. This could work to an advantage as it keeps the server-rendered doc from including SVGs that may be large or repeated. Here's a working demo.

Is it possible to opt-out of the optimization and inline the SVG?

Yes! Pass in the inline boolean prop on the icon component and it will render the SVG inline.

When rendering a lot of icons, it could be noticeably faster to render the icons inline. Try it when you see a performance bottleneck in icon rendering.

👪 Related