Create generate-sprite.ts
Install packages like svg-sprite
fs
and path
Create generate-sprite.ts
file the root
import Sprite from 'svg-sprite';
import { readdirSync, readFileSync } from 'fs';
import { join, basename, extname, relative, resolve } from 'path'
import { writeFileSync } from 'fs';
const ICONS_DIR = resolve('assets/icons') // absolute path
// npx tsx generate-sprite.ts
const sprite = new Sprite({
mode: {
symbol: {
sprite: 'sprite.svg',
example: false
},
},
shape: {
transform: [
{
svgo: {
plugins: [
{
name: 'removeDimensions',
active: false // ❗ Don't remove width/height
},
{
name: 'removeViewBox',
active: false // ❗ Don't remove viewBox
}
]
}
}
],
id: {
generator: (filepath: string) => {
console.log('filepath',filepath)
const relPath = relative(ICONS_DIR, resolve(filepath)).replace(/\\/g, '/')
const parts = relPath.split('/');
const folder = parts.length > 1 ? parts.slice(0, -1).join('-') : '';
const file = basename(filepath, extname(filepath));
return folder ? `${folder}:${file}` : file;
},
},
},
});
function walk(dir: string): string[] {
const entries = readdirSync(dir, { withFileTypes: true });
return entries.flatMap((entry) => {
const fullPath = join(dir, entry.name);
if (entry.isDirectory()) {
return walk(fullPath);
} else if (entry.isFile() && entry.name.endsWith('.svg')) {
return [fullPath];
}
return [];
});
}
async function buildSprite() {
const files = walk('assets/icons');
for (const file of files) {
console.log('file',file)
const content = readFileSync(file, 'utf-8');
sprite.add(file, file, content);
console.log('file2')
}
sprite.compile(async (err, result) => {
if (err) {
console.error('Compile error:', err);
return;
}
const compiled = result.symbol.sprite.contents;
writeFileSync('public/icons/sprite.svg', compiled);
console.log('✅ Generated: public/icons/sprite.svg');
});
}
buildSprite();
Update ICONS_DIR
path.
Generate Sprite
Run npx tsx generate-sprite.ts
How to use?
<svg class="icon" >
<use xlink:href="'/icons/sprite.svg#user" crossorigin="anonymous"></use>
</svg>