Workflow for creating SVG sprites with NPM scripts
In this blog post, I would like to demonstrate a simplified workflow for creating SVG sprites in front-end projects. This task will be done by writing a couple of NPM scripts and Node.js scripts.
NPM scripts reside within
package.json file in the
script section. You can run them with
npm run myscript where
myscript is a name of the script. For instance, if you have
you can run
npm run buildcss to compile SASS files to CSS. There are some reserved script names which don’t require
run. One of such name is
start. In the example above, simple execute the command
npm start to delete the folder
dist and compile SASS to CSS after that.
Let’s create our SVG sprite from various single SVG icons and place it inline in the HTML. Inline SVG sprites are working cross-browser and don’t require any polyfills. An inline SVG sprite looks like as follows:
Read here why
symbol is a better choice for icons. As you can also see, an inline sprite should be placed within a hidden container element. Now, when we want to use the icons from the sprite somewhere in the HTML, we can reference them by identifiers as follows:
Let’s automate our tasks. For that, we need to install the following dependencies:
They can be installed as usual with NPM, e.g.
npm install ejs --save-dev. A short description of the most important packages is not to be missed:
imagemin— this is an image minifier which will minify our SVGs (https://github.com/imagemin/imagemin).
imagemin-svgo— this is an imagemin plugin for SVGO (https://github.com/imagemin/imagemin-svgo). SVGO is an optimizer for SVG files which remove a lot of redundant and useless information (https://github.com/svg/svgo).
svgstore-cli— this is a command line tool of
svgstorewhich combines multiple SVG files into one using
We want to achieve the following sequence of goals with automated tasks:
- Optimize all SVG icons with SVGO by using
- Minify all SVG icons with
- Combine all SVG icons into one sprite which can be used inline.
- Embed created sprite into the HTML file automatically.
- Create a demo page with all available SVG icons (handy for developers).
In one of my current project, I’ve grouped and placed all SVG icons below the path
The presented tasks and the project structure lead to the following NPM scripts:
The execution order of scripts is ensured by using the
post hooks. Script names started with such prefixes are running automatically by
npm before and after their corresponding script. For instance, the command for the script
prebuildsprite is running before the command behind the script
First of all, we delete the
dist folder. This is a temporary folder the optimized and minified icons will be copied into. The optimization and minification can be achieved by the following Node.js script:
This script gets executed by
node imagemin-svgo.js — a quite common execution of any script in the Node.js environment. The
imagemin-svgo has a lot of plugins doing various optimization. We remove style and title elements in the SVG definitions, round numeric values to the fixed precision, etc. The next step is the sprite creation. This step is done by the
svgstore tool. We say it: “take all optimized icons below the
dist/svg folder and build a sprite named
casa-svgsprite.svg to be used inline”.
In the last step, we have to put the content of the created sprite into the HTML (s. the markup above). In the HTML (say index.html), we have to use the simple syntax of the templating language EJS. With the scriptlet tag
<%- … %> you can output any unescaped value into the template. In our case, the sprite’s content acts as value. The template itself could be written as follows:
For the sake of simplicity, we will write the template as ES6 string directly in the Node.js script
embed-sprite.js. This Node.js script gets executed by the NPM script
<% … %> scriptlet tag. We could e.g. iterate over an array of filenames (files with SVG icons) by
forEach and output icons having filename as identifier. This is shown in the template
Here, we have three values passed in from outside:
- theme — content of the CSS theme file which is put inline.
- svgsprite — content of the SVG sprite which is put inline.
- files — array of filenames of files containing SVG icons.
Finally, the remaining part of the
embed-sprite.js looks like as follows:
That’s all. Now, when we run
npm start, we will see something like in the output:
$ npm start
> npm run rimraf && nnpm run buildsprite && npm run embedsprite
> firstname.lastname@example.org rimraf D:\devsbb\vermittler-pos\web-theme
> rimraf dist
> email@example.com prebuildsprite D:\devsbb\vermittler-pos\web-theme
> npm run imageminsvgo
> firstname.lastname@example.org imageminsvgo D:\devsbb\vermittler-pos\web-theme
> node imagemin-svgo.js
SVG-Icons were successfully optimized
> email@example.com buildsprite D:\devsbb\vermittler-pos\web-theme
> svgstore -o src/main/resources/svg/casa-svgsprite.svg dist/svg/**/*.svg --inline
> firstname.lastname@example.org embedsprite D:\devsbb\vermittler-pos\web-theme
> node embed-sprite.js
An optimized sprite has been created and embedded into the
index.html. The demo page
svgsprite-demo.html with all SVG icons has been created as well (see the screenshot at the top of this post — just a piece of the whole page).