Skip to content

Instantly share code, notes, and snippets.

@syrxw
Last active December 7, 2020 09:31
Show Gist options
  • Save syrxw/5ef7c2fdcdd03694b7cbfe3451676a92 to your computer and use it in GitHub Desktop.
Save syrxw/5ef7c2fdcdd03694b7cbfe3451676a92 to your computer and use it in GitHub Desktop.
svg symbol合成脚本
Display the source blob
Display the rendered blob
Raw
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<metadata>
Created by syrxw
</metadata>
<defs></defs>
</svg>
#!/usr/bin/env node
const program = require("commander");
const fsp = require("fs").promises;
const path = require("path");
const chalk = require("chalk");
const globby = require("globby");
const cheerio = require("cheerio");
const css = require("css");
const chokidar = require("chokidar");
program
.version("0.0.2")
.description("svg图标雪碧图生成器 by syrxw")
.option("-g, --generate", "生成");
const svgFilePath = path.resolve("src/icons/icons.svg"); // svg最终生成文件
const dir = path.resolve("src/assets/image/svg_icons");// svg图标文件路径
const filePaths = globby.sync(["**/*.svg"], {
cwd: dir,
});
let svgFile = null;
function splitFileName(text) {
var pattern = /\.{1}[a-z]{1,}$/;
if (pattern.exec(text) !== null) {
return text.slice(0, pattern.exec(text).index);
} else {
return text;
}
}
// 生成css AST语法树
function parseCSS(content) {
const obj = css.parse(content);
const rules = obj.stylesheet.rules;
return rules.map((item) => {
return {
selector: item.selectors[0],
declarations: item.declarations.map((kitem) => {
return {
property: kitem.property,
value: kitem.value,
};
}),
};
});
}
// 读取svg文件
async function readSvgFile() {
try {
const data = await fsp.readFile(svgFilePath);
svgFile = cheerio.load(data, { xmlMode: true });
} catch (err) {
console.log(chalk.red("icons.svg文件不存在或文件损坏"));
return false;
}
}
async function readSvgIcons() {
try {
svgFile("defs").html(" ");
for (const file of filePaths) {
const data = await fsp.readFile(path.join(dir, file));
const $ = cheerio.load(data, { xmlMode: true });
const fileName = splitFileName(file);
if ($("path").length < 1) {
return false;
} else {
if ($("style").length > 0) {
const parsrCssRst = parseCSS($("style").html());
parsrCssRst.forEach((item) => {
item.declarations.forEach((declar) => {
$(item.selector).attr(declar.property, declar.value);
});
});
}
const svgWidth = $("svg").attr("width");
const svgHeight = $("svg").attr("width");
const element = `<symbol id="${fileName}" viewBox="0 0 ${
svgWidth ? svgWidth.replace("px", "") : 100
} ${svgHeight ? svgHeight.replace("px", "") : 100}">${$(
"path"
)}</symbol>`;
svgFile("defs").append(element);
}
}
} catch (err) {
console.log(chalk.red(err));
return false;
}
}
async function writeIconFile() {
try {
await fsp.writeFile(svgFilePath, svgFile.root().html());
} catch (err) {
console.log(chalk.red(err));
return false;
}
}
async function main() {
try {
await readSvgFile();
} catch (e) {
console.log(chalk.red(err));
}
try {
await readSvgIcons();
} catch (e) {
console.log(chalk.red(err));
}
try {
await writeIconFile();
} catch (e) {
console.log(chalk.red(err));
}
}
main()
<template>
<div class="hello">
<svg class="svg-icon" aria-hidden="true" v-for="n in 38" :key="n">
<use :xlink:href="`#icon_0${n}`"></use>
</svg>
</div>
</template>
<script>
import '@/icons/icons.svg';
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
// vue.config.js
const path = require('path')
module.exports = {
chainWebpack: config => {
const svgRule = config.module.rule('svg')
// 清除已有的所有 loader。
// 如果你不这样做,接下来的 loader 会附加在该规则现有的 loader 之后。
svgRule.uses.clear()
svgRule
.test(/\.svg$/)
.include.add(path.resolve(__dirname, './src/icons'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon'
})
const fileRule = config.module.rule('file')
fileRule.uses.clear()
fileRule
.test(/\.svg$/)
.exclude.add(path.resolve(__dirname, './src/icons'))
.end()
.use('file-loader')
.loader('file-loader')
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment