Skip to content

Instantly share code, notes, and snippets.

@daviddarnes
Last active August 7, 2021 09:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save daviddarnes/2d6f2db8c304024db67e0e2be6231916 to your computer and use it in GitHub Desktop.
Save daviddarnes/2d6f2db8c304024db67e0e2be6231916 to your computer and use it in GitHub Desktop.
Create SVG sprites in Eleventy using a directory SVG files as a reference, credit to @patrickxchong and @maxboeck for the performance technique and original implementation respectively
module.exports = (eleventyConfig) => {
// ...
// Icon Sprite
eleventyConfig.addWatchTarget("src/assets/svgs/");
eleventyConfig.on("beforeBuild", svgsprite);
eleventyConfig.addNunjucksAsyncShortcode("svgsprite", svgsprite);
eleventyConfig.addShortcode("icon", (name) => {
return `<svg class="icon icon--${name}" role="img" aria-hidden="true" width="24" height="24"><use xlink:href="#icon-${name}" fill="currentColor"></use></svg>`;
});
// ...
};
const fs = require("fs-extra");
const path = require("path");
const util = require("util");
const glob = require("glob");
const File = require("vinyl");
const svgSprite = require("svg-sprite");
let spriteContent = null; // Placeholder sprite variable
let cacheKey = ""; // Placeholder cached key
const svgPath = "src/assets/svgs"; // Path for all svgs
const cwd = path.resolve(svgPath);
// SVG sprite configuration
const spriteConfig = {
mode: {
inline: true,
symbol: true,
},
shape: {
transform: ["svgo"],
id: {
generator: "icon-%s",
},
},
svg: {
xmlDeclaration: false,
doctypeDeclaration: false,
},
};
module.exports = async () => {
// Get all SVG files in working directory
const getFiles = util.promisify(glob);
const files = await getFiles("**/*.svg", { cwd: cwd });
// Use all the SVG file timestamps as a cache key string
const newCacheKey = files
.map((file) => `${file}:${fs.statSync(`${svgPath}/${file}`).mtimeMs}`)
.join("|");
// Return existing sprite in spriteContent if the cache key hasn't changed
// otherwise skip return and set a new cache key
if (spriteContent && newCacheKey === cacheKey) {
return spriteContent;
} else {
cacheKey = newCacheKey;
}
// Make a new svgSprite instance with configuration
const spriter = new svgSprite(spriteConfig);
// Wrap spriter compile function in a Promise
const compileSprite = async (args) => {
return new Promise((resolve, reject) => {
spriter.compile(args, (error, result) => {
if (error) {
return reject(error);
}
resolve(result.symbol.sprite);
});
});
};
// Add all files to the spriter
files.forEach(function (file) {
spriter.add(
new File({
path: path.join(cwd, file),
base: cwd,
contents: fs.readFileSync(path.join(cwd, file)),
})
);
});
// Store contents of the sprite in the spriteContent variable
// Return the new sprite
const sprite = await compileSprite(spriteConfig.mode);
spriteContent = sprite.contents.toString("utf8");
return spriteContent;
};
---
---
<div hidden>{% svgsprite %}</div>
{% icon "filename" %}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment