最近在优化前端⼯程的时候,想把element改成按需引⼊,但是由于项⽬组件⾮常庞⼤复杂,不确定哪些组件有被使⽤到。受到最近在看的element-theme库的影响,想试着⽤脚本去帮我们处理,最好能⾃动⽣成element.js⽂件。
实现步骤:
- 1. 先通过 fs 和 path 中间件递归查询 src 所有 vue 和 js ⽂件,解析⽂本中的element 组件信息;
- 2. 只提取 el-组件名 形式的⽂本,并做去重;
- 3. 根据官⽅提供的完整组件列表匹配提取出来的组件;
- 4. 使⽤ fs.writeFile ⽣成element.js⽂件;
- 5. 脚本如下:
⾃动⽣成element依赖⽂件:
// 该脚本用来查找目录下所有使用过element的组件并创建js文件
const fs = require('fs'); // 引入文件系统模块
const path = require('path'); // 引入路径模块
const elementComponentsSet = new Set(); // 创建一个集合用于存储element组件
// 递归读取目录下的文件
function readDirSync(dir, callback) {
const files = fs.readdirSync(dir); // 读取目录下的文件
files.forEach(file => {
const filePath = path.join(dir, file); // 获取文件路径
if (fs.statSync(filePath).isDirectory()) { // 判断是否为目录
readDirSync(filePath, callback); // 递归读取子目录
} else {
if (path.extname(file) === '.vue') { // 判断文件扩展名是否为.vue
const content = fs.readFileSync(filePath, 'utf8'); // 读取文件内容
const elementComponents = content.match(/el-([a-zA-Z]+)/g); // 使用正则表达式匹配element组件
if (elementComponents) {
elementComponents.forEach(component => {
if (component.split('-')[1]) {
callback(component.split('-')[1]); // 调用回调函数处理组件名
}
});
}
}
}
});
}
// 读取目录下的文件,将使用过的element组件添加到集合中
readDirSync('./src', component => {
elementComponentsSet.add(component);
});
const elementComponentArr = Array.from(elementComponentsSet); // 将集合转换为数组
console.log(elementComponentArr); // 打印element组件数组
// 创建文件,生成element注册文件
// 不区分大小写的匹配
const all_el_components = [
'Pagination',
'Dialog',
'Autocomplete',
'Dropdown',
'DropdownMenu',
'DropdownItem',
'Menu',
'Submenu',
'MenuItem',
'MenuItemGroup',
'Input',
'InputNumber',
'Radio',
'RadioGroup',
'RadioButton',
'Checkbox',
'CheckboxButton',
'CheckboxGroup',
'Switch',
'Select',
'Option',
'OptionGroup',
'Button',
'ButtonGroup',
'Table',
'TableColumn',
'DatePicker',
'TimeSelect',
'TimePicker',
'Popover',
'Tooltip',
'Breadcrumb',
'BreadcrumbItem',
'Form',
'FormItem',
'Tabs',
'TabPane',
'Tag',
'Tree',
'Alert',
'Slider',
'Icon',
'Row',
'Col',
'Upload',
'Progress',
'Spinner',
'Badge',
'Card',
'Rate',
'Steps',
'Step',
'Carousel',
'CarouselItem',
'Collapse',
'CollapseItem',
'Cascader',
'ColorPicker',
'Transfer',
'Container',
'Header',
'Aside',
'Main',
'Footer',
'Timeline',
'TimelineItem',
'Link',
'Divider',
'Image',
'Calendar',
'Backtop',
'PageHeader',
'CascaderPanel',
'Loading',
'MessageBox',
'Message',
];
let indexPath = `./src/plugins/element.js`; // 定义文件路径
fs.writeFile(indexPath, indexPage(elementComponentArr), function (err) { // 写入文件
if (err) {
return console.log('创建element文件失败', err);
}
console.log(`创建element.js文件成功`);
});
// 定义文件模板
function indexPage(list) {
let string = `import Vue from 'vue';\n`; // 引入Vue
const match_components_set = new Set(); // 创建一个集合用于存储匹配的组件
list.forEach(item => {
all_el_components.forEach(value => {
if (value.toLowerCase().indexOf(item.toLowerCase()) > -1) { // 不区分大小写的匹配
match_components_set.add(value); // 将匹配的组件添加到集合中
}
});
});
const match_components = Array.from(match_components_set); // 将集合转换为数组
console.log(match_components); // 打印匹配的组件数组
// 处理一些特殊的引入
string += `import { Loading, MessageBox, Message, Notification} from 'element-ui' // 一般都会引入的文件 \n`;
// 处理引入
string += `import {\n${match_components.join(',\n')} \n} from 'element-ui';\n`;
// 处理VueUse
match_components.forEach(value => {
string += `Vue.use(${value});\n`; // 使用Vue.use注册组件
});
// 添加其他依赖
string += `Vue.use(Loading.directive);
Vue.prototype.$loading = Loading.service;
Vue.prototype.$msgbox = MessageBox;
Vue.prototype.$alert = MessageBox.alert;
Vue.prototype.$confirm = MessageBox.confirm;
Vue.prototype.$prompt = MessageBox.prompt;
Vue.prototype.$notify = Notification;
Vue.prototype.$message = Message;`;
return string; // 返回文件模板字符串
}
生成后的文件
import Vue from 'vue';
import { Loading, MessageBox, Message, Notification } from 'element-ui'; // 一般都会引入的文件
import {
Icon,
Select,
TimeSelect,
Option,
OptionGroup,
Dropdown,
DropdownMenu,
DropdownItem,
Form,
FormItem,
Input,
InputNumber,
Tooltip,
Menu,
Submenu,
MenuItem,
MenuItemGroup,
Container,
Header,
PageHeader,
Breadcrumb,
BreadcrumbItem,
Main,
TableColumn,
Col,
Collapse,
CollapseItem,
ColorPicker,
RadioButton,
CheckboxButton,
Button,
ButtonGroup,
Row,
Upload,
Badge,
Table,
Dialog,
Image,
Carousel,
CarouselItem,
DatePicker,
Radio,
RadioGroup,
Checkbox,
CheckboxGroup,
Pagination,
Tree,
Backtop,
Transfer,
Divider,
Cascader,
CascaderPanel,
Card,
Tabs,
TabPane,
Tag,
Steps,
Step,
Autocomplete,
Progress,
Timeline,
TimelineItem,
} from 'element-ui';
Vue.use(Icon);
Vue.use(Select);
Vue.use(TimeSelect);
Vue.use(Option);
Vue.use(OptionGroup);
Vue.use(Dropdown);
Vue.use(DropdownMenu);
Vue.use(DropdownItem);
Vue.use(Form);
Vue.use(FormItem);
Vue.use(Input);
Vue.use(InputNumber);
Vue.use(Tooltip);
Vue.use(Menu);
Vue.use(Submenu);
Vue.use(MenuItem);
Vue.use(MenuItemGroup);
Vue.use(Container);
Vue.use(Header);
Vue.use(PageHeader);
Vue.use(Breadcrumb);
Vue.use(BreadcrumbItem);
Vue.use(Main);
Vue.use(TableColumn);
Vue.use(Col);
Vue.use(Collapse);
Vue.use(CollapseItem);
Vue.use(ColorPicker);
Vue.use(RadioButton);
Vue.use(CheckboxButton);
Vue.use(Button);
Vue.use(ButtonGroup);
Vue.use(Row);
Vue.use(Upload);
Vue.use(Badge);
Vue.use(Table);
Vue.use(Dialog);
Vue.use(Image);
Vue.use(Carousel);
Vue.use(CarouselItem);
Vue.use(DatePicker);
Vue.use(Radio);
Vue.use(RadioGroup);
Vue.use(Checkbox);
Vue.use(CheckboxGroup);
Vue.use(Pagination);
Vue.use(Tree);
Vue.use(Backtop);
Vue.use(Transfer);
Vue.use(Divider);
Vue.use(Cascader);
Vue.use(CascaderPanel);
Vue.use(Card);
Vue.use(Tabs);
Vue.use(TabPane);
Vue.use(Tag);
Vue.use(Steps);
Vue.use(Step);
Vue.use(Autocomplete);
Vue.use(Progress);
Vue.use(Timeline);
Vue.use(TimelineItem);
Vue.use(Loading.directive);
Vue.prototype.$loading = Loading.service;
Vue.prototype.$msgbox = MessageBox;
Vue.prototype.$alert = MessageBox.alert;
Vue.prototype.$confirm = MessageBox.confirm;
Vue.prototype.$prompt = MessageBox.prompt;
Vue.prototype.$notify = Notification;
Vue.prototype.$message = Message;