最近接到需求,要换肤,给系统增加主题的概念,让用户可以一键换肤。就想着参考element-ui中样式的管理方法,把所有样式都放到一起统一管理,而不是分散在vue文件中。然后就写了一个小工具来实现这个功能,基本可用
const path = require('path');
const fs = require('fs');
const compiler = require('vue-template-compiler');
const colors = [];
const reg = /(#[a-f0-9]{3.6})|(rgb[a]?\(.*\))/g; // 这个正则用来提取颜色值的,不完美,大体可用
let wd = process.argv[2] || '.';
wd = path.resolve(__dirname, wd);
if (process.argv[3] === 'color') {
traverseDirectory(wd, analyzeColor);
const cs = new Set(colors);
console.log('所有颜色:', cs);
return;
}
// 遍历目录,处理每一个vue文件
function handleDirectory(dirPath) {
traverseDirectory(dirPath, handleSingleVue);
}
handleDirectory(wd);
// 遍历目录
function traverseDirectory(dirPath, cb) {
const files = fs.readdirSync(dirPath);
log(dirPath, ':');
files.forEach(file => {
log(file);
const filePath = path.resolve(dirPath, file);
if (!shouldHandle(file)) {
log('不需要处理');
} else if (isVue(file)) {
log('vue文件');
cb && cb(filePath);
} else if (isDirectory(filePath)) {
log('目录');
traverseDirectory(filePath, cb);
} else {
log('不需要处理');
}
});
}
function handleSingleVue(filePath) {
const content = fs.readFileSync(filePath, 'utf-8');
const ret = compiler.parseComponent(content);
if (ret.styles && ret.styles.length) {
let str = `<template>${ret.template.content}</template>\r\n<script>${ret.script.content}</script>\r\n`;
const styles = ret.styles.map((style, index) => {
const stylePath = extractStyle(filePath, style, index);
return `<style${style.lang && style.lang !== 'css' ? ' lang="' + style.lang + '"' : ''}${style.scoped ? ' scoped' : ''}>\r\n@import "${replaceSrc(stylePath.replace(/\\/g, '/'))}";\r\n</style>`;
});
str += styles.join('\r\n') + '\r\n';
saveToFile(filePath, str);
}
}
function replaceSrc(filePath) {
const index = filePath.indexOf('/src');
return '@' + filePath.substr(index + 4);
}
function extractStyle(filePath, styleObj, fileIndex) {
const index = filePath.indexOf(path.sep + 'src');
const styleFilePath = filePath.substr(0, index) + ['', 'src', 'styles', 'default-theme'].join(path.sep) + filePath.substr(index + 4).replace('.vue', (fileIndex === 0 ? '' : fileIndex) + '.' + styleObj.lang);
saveToFile(styleFilePath, styleObj.content);
const c = getAllColors(styleObj.content);
if (c) {
colors.push(...c);
}
return styleFilePath;
}
function saveToFile(pathName, content) {
const dirs = pathName.split(path.sep);
let tmpStr = '';
for (let i = 0; i < dirs.length - 1; i++) {
tmpStr += dirs[i] + path.sep;
if (!fs.existsSync(tmpStr)) {
fs.mkdirSync(tmpStr);
}
}
fs.writeFileSync(pathName, content);
}
function log(str) {
console.log(str);
}
function isVue(filePath) {
return filePath && filePath.toLowerCase().endsWith('.vue');
}
function isDirectory(filePath) {
const stat = fs.statSync(filePath);
return stat.isDirectory();
}
function shouldHandle(filePath) {
const excludedDirs = ['node_modules', 'dist', '.git'];
if (filePath && (filePath[0] === '.' || excludedDirs.some(dir => filePath.indexOf(dir) !== -1))) {
return false;
}
return true;
}
function getAllColors(content) {
return content.match(reg);
}
function analyzeColor(filePath) {
const content = fs.readFileSync(filePath, 'utf-8');
const ret = compiler.parseComponent(content);
(ret.styles || []).forEach(style => {
const c = getAllColors(style.content);
if (c) {
colors.push(...c);
}
});
}
保存成extractStyle.js
公司电脑不能联网,又比着敲了一遍,注释实在是敲不动了!!
用法:
- 在vue项目根目录下执行node extractStyle.js ./src,就会遍历src下面的vue文件,然后在src/styles/default-theme中创建对应的样式文件,同时把原来的vue文件中的样式提取出去,只留下@import ‘@/xxxxx’
- 还提供了一个小工具,用来分析样式中使用的颜色值,有一点瑕疵,但是不影响使用, node extractStyle.js ./src color
由于项目代码审查不严格,我的项目中已经有200多个颜色值了,我都抓狂了
前面的路还很长啊!!!😦
如果有帮助,请点赞哦:)