基于公司需求,会搭建一个常规的组件 ui 库,简单的组件库还是非常好搭建的,我也搭建了很多次了,美滋滋的去搭建了,局部组件、公共组件,巴拉巴拉一顿输出。
在于 antdesign
经常会自己设置主题,我们的组件库需要支持 antdesign
中的变量继承,看到 antdesign
在 main.js
中可以 直接 import '*****.less'
, 我是比较好奇的,但是还是真没在组件库做过。开始想到的是用 webpack
或者 gulp
进行 打包成 less
,在于本人技术实在尴尬,网上也搜不到对应的东西。 后面想想,干脆自己用 fs
的方式进行操作文件抽离出来,时间又紧迫,只好想了后就开始行动,经过几个小时的奋战,把文件的样式 class 都设置成了比较语义化,以及成功在其他项目引用修改变量能顺利修改。
我们需要分离 vue
文件中的 style
中的样式,那么vue-template-compiler
必不可少!
vue-template-compiler
是编译 vue 模板的包,传入模板返回AST 抽象语法树。
例子
下面是一个简单的 tooltip
小组件。
<template>
<tooltip placement="top">
<template slot="title" v-if="isAllShow || content.length > len">
{{ tipContent || content }}
template>
{{ content.length > len ? content.slice(0, len) + "..." : content }}
tooltip>
template>
<script>
import { Tooltip } from "ant-design-vue";
export default {
name: "CTooltip",
components: { Tooltip },
props: {
tipContent: {
type: String,
default: "",
},
content: {
type: String,
default: "",
},
len: {
type: Number,
default: 12,
},
isAllShow: {
type: Boolean,
default: false,
},
},
};
script>
我们现在来获取它的结构
// 引入 vue-template-compiler
const compiler = require("vue-template-compiler");
// 处理文件与目录路径
const path = require("path");
// 处理文件的读写、复制、s删除、重命名等操作
const fs = require("fs");
// 拼接路径
const resolve = (dir) => path.join(__dirname, dir);
// 读取文件
const content = fs.readFileSync(
resolve("./packages/components/CTooltip/index.vue"),
"utf-8"
);
// 编译模板字符串并返回已编译的JavaScript代码及其AST树。
const ret = compiler.parseComponent(content);
console.log(ret);
运行
node demo.js
可以看到常规分为了 3 部分, template
、 script
、 styles
。
我们只需要 styles
数组的东西。
合并成 less
文件,需要遍历 packages
文件夹中所有的文件,抽取出 vue
文件、less
文件 、 css
文件。
function ergodicDirectory(dirPath) {
// 读取文件
const files = fs.readdirSync(dirPath);
files.forEach((file) => {
// 当前遍历的 文件
const filePath = path.resolve(dirPath, file);
if (isVue(file)) {
// 是vue文件的处理方式
copyVue && copyVue(filePath);
} else if (isLessOrCss(file)) {
// 是否是 less 或 css 文件
copyFile && copyFile(filePath);
} else if (isDirectory(filePath)) {
// 是否是 目录 文件夹
ergodicDirectory(filePath);
}
});
}
function isVue(filePath) {
return filePath && filePath.toLowerCase().endsWith(".vue");
}
function isLessOrCss(filePath) {
return (
filePath &&
(filePath.toLowerCase().endsWith(".less") ||
filePath.toLowerCase().endsWith(".css"))
);
}
function isDirectory(filePath) {
const stat = fs.statSync(filePath);
return stat.isDirectory();
}
function copyVue(filePath) {
const content = fs.readFileSync(filePath, "utf-8");
const ret = compiler.parseComponent(content);
// 循环styles
ret.styles &&
ret.styles.forEach((style) => {
// 追加内容到 规定文本
pushStyle(style.content);
});
}
function copyFile(filePath) {
const content = fs.readFileSync(filePath, "utf-8");
const ret = compiler.parseComponent(content);
pushStyle(ret.source);
}
arr 是存文本的全局变量
function pushStyle(data) {
// 去掉 deep
data = data.replace("/deep/", "");
// 去掉 @import 引入的 文本
const last = data.lastIndexOf('";');
const last2 = data.lastIndexOf('");');
if (last !== -1) arr += data.substring(last + 2);
else if (last2 !== -1) arr += data.substring(last2 + 3);
else arr += data;
}
function save () {
// 写入 的 路径地方以及名称
fs.writeFileSync(resolve('./lib/demo.less'), arr)
}
ergodicDirectory(resolve("./packages"));
save();
"build": "vue-cli-service build --target lib --name custom-ant-base-ui --dest lib packages/index.js && node demo.js"
npm run build
// 引入 vue-template-compiler
const compiler = require("vue-template-compiler");
// 处理文件与目录路径
const path = require("path");
// 处理文件的读写、复制、s删除、重命名等操作
const fs = require("fs");
// 拼接路径
const resolve = (dir) => path.join(__dirname, dir);
let arr = "";
// 遍历目录
function ergodicDirectory(dirPath) {
// 读取文件
const files = fs.readdirSync(dirPath);
files.forEach((file) => {
// 当前遍历的 文件
const filePath = path.resolve(dirPath, file);
if (isVue(file)) {
// 是vue文件的处理方式
copyVue && copyVue(filePath);
} else if (isLessOrCss(file)) {
// 是否是 less 或 css 文件
copyFile && copyFile(filePath);
} else if (isDirectory(filePath)) {
// 是否是 目录 文件夹
ergodicDirectory(filePath);
}
});
}
// 是否是VUE文件
function isVue(filePath) {
return filePath && filePath.toLowerCase().endsWith(".vue");
}
// 是否是Less或者Css文件
function isLessOrCss(filePath) {
return (
filePath &&
(filePath.toLowerCase().endsWith(".less") ||
filePath.toLowerCase().endsWith(".css"))
);
}
// 是否是目录
function isDirectory(filePath) {
const stat = fs.statSync(filePath);
return stat.isDirectory();
}
function copyVue(filePath) {
const content = fs.readFileSync(filePath, "utf-8");
const ret = compiler.parseComponent(content);
// 循环styles
ret.styles &&
ret.styles.forEach((style) => {
// 追加内容到 规定文本
pushStyle(style.content);
});
}
function copyFile(filePath) {
const content = fs.readFileSync(filePath, "utf-8");
const ret = compiler.parseComponent(content);
pushStyle(ret.source);
}
function pushStyle(data) {
// 去掉 deep
data = data.replace("/deep/", "");
// 去掉 @import 引入的 文本
const last = data.lastIndexOf('";');
const last2 = data.lastIndexOf('");');
if (last !== -1) arr += data.substring(last + 2);
else if (last2 !== -1) arr += data.substring(last2 + 3);
else arr += data;
}
function save() {
// 写入 的 路径地方以及名称
fs.writeFileSync(resolve("./lib/demo.less"), arr);
}
ergodicDirectory(resolve("./packages"));
save();
对于项目紧急的情况,现在是最好的处理方式了,欢迎各位小伙伴们告诉我其他方式,后面再优化,修改。