A loader and plugin for webpack that converts all your SVGs into symbols and merges them into a SVG sprite.
Important: There is a breaking change when moving from v3 to v4. Check the release notes.
You will need NodeJS v6+, npm v3+ and webpack 4.
To make it work in older browsers, like Internet Explorer, you will also need SVG for Everybody or svgxuse.
npm i external-svg-sprite-loader
or
yarn add external-svg-sprite-loader
name
- relative path to the sprite file (default:img/sprite.svg
). The[contenthash]
placeholder is supported.iconName
- name for the icon symbol (default:icon-[name]-[hash:5]
).publicPath
- custom public path to be used instead of webpackoutput.publicPath
. This option might be useful when your webpackoutput.publicPath
is set to a different scheme/host/port (e.g.: when you use a CDN). This is because currently the SVG sprite cannot be served from another domain (read more).svgoOptions
- custom options to be passed to svgo. If you set this option then make sure you add{ removeViewBox: false }
to theplugins
otherwise this loader won't work.
emit
- determines if the sprite is supposed to be emitted (default: true). Useful when generating server rendering bundles where you just need the SVG sprite URLs but not the sprite itself.sprite
- SVG sprite options (default: {startX: 0, startY: 0, deltaX: 0, deltaY: 0, iconHeight: 50, rowWidth: 1000}). StartX and StartY - beginning sprite position, DeltaX and DeltaY - space between icons. IconHeight - Icon height in the sprite (just for the comfort).
If you have the following webpack configuration:
// webpack.config.js
import path from 'path';
import SvgStorePlugin from 'external-svg-sprite-loader';
module.exports = {
mode: 'development',
module: {
rules: [
{
loader: SvgStorePlugin.loader,
test: /\.svg$/,
},
],
},
output: {
path: path.join(__dirname, 'public'),
publicPath: '/',
},
plugins: [
new SvgStorePlugin({
sprite: {
startX: 10,
startY: 10,
deltaX: 20,
deltaY: 20,
iconHeight: 20,
},
}),
],
};
You will be able to import your SVG files in your JavaScript files as shown below.
The imported SVG will always correspond to a JavaScript object with keys symbol
, view
and viewBox
:
- The
symbol
url can be used on a<use>
tag to display the icon; - The
view
url is supposed to be used in CSS; - The
viewBox
value is required by some browsers on the<svg>
tag; - The
title
value can be used on the<svg>
tag for accessibility.
The URLs will have the following format:
symbol
:webpackConfig.output.publicPath
/loader.name
#loader.iconName
view
:webpackConfig.output.publicPath
/loader.name
#view-loader.iconName
/*
* {
* symbol: '/public/img/sprite.svg#icon-logo',
* view: '/public/img/sprite.svg#view-icon-logo',
* viewBox: '0 0 150 100',
* title: 'Logo'
* }
*/
import logo from './images/logo.svg';
const Logo = () => (
<svg viewBox={logo.viewBox} title={logo.title} role="img">
<use xlinkHref={logo.symbol} />
</svg>
);
In CSS files, you can import your SVG files as shown bellow (assuming you are using the MiniCssExtractPlugin).
The imported value will be converted into the view
url shown above.
.special-icon {
/* the url will be replaced with the url to the sprite */
background-image: url('./icons/special.svg') no-repeat 0;
}
When a SVG is added, removed or changed, the sprite will be re-generated and all files referencing it will be updated. When no [contenthash]
is used in the name
option, a cache-busting will be added to the URL so that the browser is forced to re-download the sprite.
You can find working examples in the examples
folder. To test the React example under the examples/react
folder run:
npm install
npm run start:dev
And then you can see the result in http://localhost:3000
.
There's some additional commands that you may try:
npm run start:dev:hot
to check if sprite updates work with Hot Module replacement.npm run start:dev:no-hash
to check if sprite updates work, even if the outputted file is the same.npm run start:dev:hot-no-hash
to check if sprite updates work with Hot Module replacement, even if the outputted file is the same.npm run build:prd && npm run start:prd
to test a production build.
First of all, thank you for contributing, you are awesome.
Here are a few rules to follow in order to ease code reviews, and discussions before maintainers accept and merge your work:
- Make sure your commit messages make sense (don't use
fix tests
,small improvement
,fix 2
, among others). - Before creating a pull request make sure of the following:
- your code is all documented properly;
- your code passes the ESLint rules;
- variable, function and class names are explanatory enough;
- code is written in ES2015.
- When creating a pull request give it a name and description that are explanatory enough. In the description detail everything you are adding, do not assume we will understand it from the code.
Thank you!