Using gulp-svgstore with Angular
Update: ng2-inline-href has been renamed to ng-inline-href for compatibility with the release of Angular 4.
gulp-svgstore is a nice library for optimizing your SVG files when using Gulp. It lets you combine all of your SVGs into one file (same idea as a Spritesheet), and even inject that combined SVG into your HTML so that no extra network requests are required for your SVG files.
The problem, however, is that the <base href="/" />
tag causes some problems with Firefox. Let’s start from the beginning and see how to fix the issue.
Note: Already know how to use gulp-svgstore and just want the solution to the Angular issue? Skip down to “The Problem,” near the bottom of the page.
Adding gulp-svgstore to Your Gulp Pipeline
This code snippet, from the gulp-svgstore README, shows a basic example of inserting gulp-svgstore into your Gulp pipeline:
var gulp = require('gulp');
var svgstore = require('gulp-svgstore');
var svgmin = require('gulp-svgmin');
var path = require('path');
gulp.task('svgstore', function () {
return gulp
.src('test/src/*.svg')
.pipe(svgmin(function (file) {
var prefix = path.basename(file.relative, path.extname(file.relative));
return {
plugins: [{
cleanupIDs: {
prefix: prefix + '-',
minify: true
}
}]
}
}))
.pipe(svgstore())
.pipe(gulp.dest('test/dest'));
});
You probably noticed that the snippet also uses gulp-svgmin, which minifies the SVG files for you before concatenating them.
Injecting the Output Into the HTML Body
At this point, you already have a single master SVG file that is fully usable; however, we can take that a step further by injecting the output right into the HTML using gulp-inject.
In your index.html, at the top of the body, add a div that will contain the SVG:
<div class="svg-master">
<!-- inject:svg --><!-- endinject -->
</div>
This is where gulp-inject will put our SVG file. Make sure that you set display: none;
on the svg-master
class.
Now that the HTML is prepared, change your Gulp task to look like the following (also taken from the gulp-svgstore README):
var gulp = require('gulp');
var svgstore = require('gulp-svgstore');
var inject = require('gulp-inject');
gulp.task('svgstore', function () {
var svgs = gulp
.src('test/src/*.svg')
.pipe(svgstore({ inlineSvg: true }));
function fileContents (filePath, file) {
return file.contents.toString();
}
return gulp
.src('test/src/inline-svg.html')
.pipe(inject(svgs, { transform: fileContents }))
.pipe(gulp.dest('test/dest'));
});
gulp-inject will now place the generated SVG right into your HTML. The next step is to use them throughout your app.
The use Tag
The <svg>
element, in HTML, has a child element called <use>
, which allows you to import the original SVGs from the injected meta-SVG by referring to it’s generated ID.
The ID of each SVG element is equivalent to the original filename. For example, if you have a file called icon-back.svg, then you can use that SVG throughout your site with the following:
<svg>
<title>Go back</title>
<use xlink:href="#icon-back" />
</svg>
The Problem
At this point, all I have done is basically summarize some of the main points of the gulp-svgstore README, so what was the point of this article? Due to the <base href="/" />
tag, which Angular requires, Firefox will not handle these <use>
tags properly.
The reason for this is that Firefox is looking for the SVG in the root rather than the current file. For example, if you are at http://www.myawesomesite.xyz/somepage, you would expect the #icon-back
example above to resolve to http://www.myawesomesite.xyz/somepage#icon-back; however, Firefox is not doing that. Instead, it is resolving as http://www.myawesomesite.xyz/#icon-back, because of the base tag.
The Solution
Enter ng-inline-href, a small NPM package I wrote to handle this issue. This library will simply get the URL of the current page and concatenate it to the front of your ID reference, so that it becomes an absolute URL, instead of a relative one.
For example, <use inlineHref="#icon-back" />
acts the same as the above example, but works with Firefox. The resulting tag will look like this: <use xlink:href="http://www.myawesomesite.xyz/somepage#icon-back" />
.