I’m looking into the new Build Plugins API, and it seems like it would be perfect to take individual SVG files and compile them into a sprite in order to be able to lower the number of HTTP calls and style them with CSS.
I can see two ways to do it:
Take all the SVGs and compile them into a single SVG, which gets injected at the top of the document (the process described in that blog post)
Take each SVG file and inject its code into a new, individual template. So you’d be able to use logo.svg simply by calling {{> logo}}.
I looked at the documentation and while both seem like they should be possible, I’m not sure how to proceed exactly.
It seems like addHtml is what I need, but it’s not clear what type of arguments you need to pass to it, and so far it doesn’t seem to do anything for me. So anyway, I would love a few pointers on the best way to achieve this! (@sashko maybe?)
This looks interesting, but my question was more about the parsing/compiling files aspect, which that package doesn’t really deal with. So it’s more a complement I think?
Disclaimer, I haven’t used the build plugins api just yet, but perhaps something along these lines would work? (freehand, so will probably contain errors)
Plugin.registerCompiler({
extensions: ["svg"],
filenames: []
}, function () {
var compiler = new SVGCompiler();
return compiler;
});
function SVGCompiler() {};
SVGCompiler.prototype.processFilesForTarget = function (files) {
var outputPath = "/somepath/";
//Spriter config
var spriter = new SVGSpriter({
dest: outputPath,
mode: {
css: {
render: {
css: true
}
}
}
});
//Iterate over files and add them to spriter
files.forEach(function (file) {
var path = file.getDirname(); //Get path of file
spriter.add(
path, //Path to file
file, //Filename
fs.readFileSync(path+file, {encoding: 'utf-8'}) //file data
);
});
//Compile sprite to destination
spriter.compile({
//Optional config
}, function(err, res, data){
//Add the resulting data
files.addStylesheet({
data: res.css,
path: outputpath+"svgSprite.css"
});
files.addAsset({
data: res.sprite,
path: outputpath+"svgSprite.svg"
});
});
};
Thanks! This looks like it could work, but the addStylesheet method belongs to file, not files. I’m not sure what’s the best way to access it outside of that forEach loop though, since we only want to call it once?
Package.describe({
name: "utilities:compile-svg",
summary: "Get SVG images and make them available as templates",
version: "0.1.0"
});
Package.registerBuildPlugin({
name: "compileSVG",
use: [
'caching-html-compiler',
'ecmascript',
'templating-tools',
'underscore'
],
sources: ['lib/compile-svg.js'],
npmDependencies: {
"svg-sprite": "1.2.10"
}
});
Package.onUse(function (api) {
api.use('isobuild:compiler-plugin@1.0.0');
});
var SVGSpriter = Npm.require("svg-sprite");
var fs = Plugin.fs;
Plugin.registerCompiler({
extensions: ["svg"],
archMatching: 'web',
filenames: []
}, function () {
var compiler = new SVGCompiler();
return compiler;
});
function SVGCompiler() {};
SVGCompiler.prototype.processFilesForTarget = function (files) {
var outputPath = "/somepath/";
var mode = {
"css": true,
"symbol": true
};
//Spriter config
var spriter = new SVGSpriter({
dest: outputPath,
mode: mode
});
//Iterate over files and add them to spriter
files.forEach(function (file) {
var fullPath = file._resourceSlot.inputResource.path;
var fileName = fullPath.replace(/^.*[\\\/]/, '');
var data = fs.readFileSync(fullPath, {encoding: 'utf-8'});
spriter.add(
fullPath, //Path to file
fileName, //Filename
data //file data
);
});
//Compile sprite to destination
spriter.compile(function(err, res, data){
//Add the resulting data
files[0].addHtml({section: "body", data: "???"});
files[0].addStylesheet({
data: "???",
path: outputPath+"svgSprite.css"
});
files[0].addAsset({
data: "???",
path: outputPath+"svgSprite.svg"
});
});
};
The issue is that I’m not sure what to pass to addHtml, addStylesheet, or addAsset. If I just pass the output of the spriter it throws errors, and I can’t yet figure out how to convert that output to a string to pass it properly…
Oh and also, while this works for SVGs contained in my main app directories, it doesn’t trigger for SVGs contained in packages.
The only remaining hurdle (apart from the fact that it doesn’t parse SVGs contained in packages yet) is that the generated <symbol> tag IDs are blank for some reason…
I’d love to try and debug this, but I realized I don’t actually know how to tell a Meteor package (in this case running locally using the PACKAGE_DIRS technique) to use a local NPM package’s code instead of the one downloaded from the online repository…
sadly I found the thread this late. last week I worked on exactly the same build plugin and I experiensed some difficulties as well. I wrote the same callback version as @sacha, but it didnt work (race condition during the build IMHO). the next one I wrote was a future powered version (since the build process uses fibers to parallelize its tasks) - I didnt notice an inconsistency so fare. But this is not the way its supposed to be done - some thoughts about it
since @sacha s repo is offline (or in a place were I couldnt find it) maybe some of this could be helpful to someone.