背景:
由于公司业务需要维护一个组件库,主要目的是
1.为了展示组件官网
2.提供组件打包能力,暴露入口
基于之前的维护经验来说,一旦组件到达几十个点时候,需要不停的写import 语句,越多越难维护
import Header from '../packages/header';
import TagsView from '../packages/TagsView';
import Select from '../packages/Select';
import Radio from '../packages/Radio';
import Transfer from '../packages/common/transfer';
import CodeTableMenu from '../packages/codeTableMenu';
import Tabs from '../packages/tabs';
import Pagination from '../packages/pagination';
import Search from '../packages/search';
import FormBlock from '../packages/formBlock';
import FormSearch from '../packages/formSearch';
import TableData from '../packages/tableData';
import PopTree from '../packages/popTree';
import PopTable from '../packages/popTable';
import LayoutNew from '../packages/layoutNew';
import notFound from '../packages/notFound';
import error from '../packages/errorPage';
const components = [
DateRangeUnion,
PriceTable,
InputNumber,
TheadTooltips,
DateRange,
Switch,
Empty,
CpoeName,
HpPreview,
RateBoard,
PatientInfoBoard,
OrderName,
OrderTypeIcon,
]
const install = function (Vue, opts = {}) {
components.forEach((component) => { Vue.component(component.name, component);
});};
再通过把组件放在组件中通过循环进行组件全局注册,但是这样不断的在做重复的工作
解决思路:
之前工作中维护过element代码,印象中记得element是通过json生成的,于是去瞟了一眼源码,大致实现了用代码生成组件注册代码
1.维护一个组件json路径文件components.json
{
"button": "./packages/button/index.js",
"icon": "./packages/icon/index.js",
"input": "./packages/input/index.js"
}
2.构建模板语法
1.其中需要用到json-templater/string,字符串模板生成器
const Components = require("./components.json");
const path = require("path");var fs = require("fs");
const render = require("json-templater/string");
const uppercamelcase = require("uppercamelcase");
const endOfLine = require("os").EOL;
const OUTPUT_PATH = path.join(__dirname, "./src/index.js");
const INSTALL_COMPONENT_TEMPLATE = " {{name}}";
var MAIN_TEMPLATE = `/* Automatically generated by './build-entry.js' */
import Vue from 'vue';{{include}}const components = [{{install}},];
const install = function(Vue, opts = {}) { components.forEach(component => { Vue.component(component.name, component); });
Vue.prototype.$ELEMENT = { size: '', zIndex: 2000, }; // Vue.prototype.$confirm = MessageBox.confirm;
const En = ['success', 'warning', 'error']; En.forEach((type) => { if(Vue.prototype.$message){
Vue.prototype.$message[type] = (msg) => {
Vue.prototype.$message({
showClose: true,
message: msg,
type,
});
};
}
});
window.$version ={
version:'{{version}}',
}};
export default {
version: '{{version}}',
install,{{list}}
};`;
// import 语句语法模版
const IMPORT_TEMPLATE = "import {{name}} from '../packages/{{package}}/index.js';";
// 通过维护不同的数组,控制模板语句的for循环生成的数据
const ComponentNames = Object.keys(Components);
const includeComponentTemplate = [];
const installTemplate = [];const listTemplate = [];
ComponentNames.forEach((name) => { const componentName = uppercamelcase(name);
includeComponentTemplate.push(
// 单条import生成语句
render(IMPORT_TEMPLATE, {
name: componentName,
package: name, })
);
if (["MessageBox"].indexOf(componentName) === -1) {
installTemplate.push(
render(INSTALL_COMPONENT_TEMPLATE, {
name: componentName,
component: name,
})
);
}
if (componentName !== "Loading") listTemplate.push(` ${componentName}`);});
// 接受一个字符串模板,把数据传入模板中,返回一个组合完成的字符串
var template = render(MAIN_TEMPLATE, {
include: includeComponentTemplate.join(endOfLine),
install: installTemplate.join("," + endOfLine),
version: process.env.VERSION || require("./package.json").version,
list: listTemplate.join("," + endOfLine),
});
// 将字符串写入新的文件夹
fs.writeFileSync(OUTPUT_PATH, template);console.info(template);
3.构建一个node 指令
"scripts": { "entry": "node ./build-entry.js", },
这样就实现了一个脚本自动生成组件库需要的mian入口文件
4.在打包的时候先执行entry脚本,即不需要在维护import语句与main文件入口了
生成结果
/* Automatically generated by './build-entry.js' */
import Vue from 'vue';
import Button from '../packages/button/index.js';
import Icon from '../packages/icon/index.js';import Input from '../packages/input/index.js';
const components = [
Button,
Icon,
Input
];
const install = function(Vue, opts = {}) {
components.forEach(component => {
Vue.component(component.name, component); });
Vue.prototype.$ELEMENT = { size: '', zIndex: 2000, };
Vue.prototype.$confirm = MessageBox.confirm;
const En = ['success', 'warning', 'error'];
En.forEach((type) => {
if(Vue.prototype.$message){
Vue.prototype.$message[type] = (msg) => {
Vue.prototype.$message({
showClose: true,
message: msg,
type,
});
};
}
});
window.$version ={
version:'1.0.0',
}
};
export default {
version: '1.0.0',
install,
Button,
Icon,
Input
};