场景
当前项目是一个微服务项目,外框架使用的是其他组搭建好的外框架。本小组利用该资源实现多个子系统比如a/b/c等。
项目开发到一定程度后,发现a,b,c子系统存在公共组件,现希望对组件进行提取,实现一次修改,所有子系统均升级效果。且本小组权限仅只能在子系统内进行代码编辑。对外框架的修改需要进行提案,因为提案周期比较长,且任务需要排期,现考虑组内实现效果。
方案
使用rollup进行打包,打包成amd格式的js。
使用requirejs进行引入,因为子系统没有index.html,只有index.js作为入口,故使用requirejs进行引入公共组件js。(为什么没考虑js生成<script src="xxx"></script>?)
实现
新建一个项目common,然后npm init -y,初始化package,安装rollup以及它的一些插件。
{
"devDependencies": {
"@vue/compiler-sfc": "^3.2.33", // sfc解析
"rollup-plugin-cleanup": "^3.2.1", // 多余代码清除插件
"rollup-plugin-terser": "^7.0.2", // 压缩插件
"rollup-plugin-vue": "^5.1.0", // vue模板解析插件
"vue-template-compiler": "^2.6.14" // vue模板解析插件
},
"dependencies": {
"rollup": "^2.74.1"
}
}
新建目录如下:
第一步:抽离
把组件移植到src的components文件夹中,一些必要的依赖放入相关的文件夹中。(这样的话,如果子系统组件要用到这些依赖,公共组件也要用到该依赖,这样就存在两份依赖,代码体积变大,这块大家怎么解决呢?)
注意打包格式: 如果使用requirejs引入,那么应该打包成amd格式。主入口配置为:
// main.js
import Xx from './components/Xx.vue';
const components = {
Xx
};
const install = function(Vue) {
Object.keys(components).forEach(key => {
Vue.component(key, components[key]); // 全局注册
})
};
export {
components,
install
}
打包后的js:
define(['exports'], (function(e){'use strict'; ...}))
即格式:define(id?, dependencies?, factory)
第二步:使用
打包后的公共组件js后续会放入服务器。如果放入子系统,那么每个子系统都需要放置一份代码,还不如原先每个子系统存一套代码方便。
本地开发时,如果要调试公共组件js,可以打开项目common,配置package.json中打包命令,加个-w,实现改动重新打包。
本地使用
打包出来的是amd格式,使用requirejs引入,在index.js中:
requirejs.config({
paths: {
ufCom: './xx/ufCom-amd', // 包的资源路径,如果本地用,可以放本地static作为静态资源,也可以改为线上服务器地址,只要能访问到,这里不加js,因为访问时会加js。
}
});
requirejs(['ufCom'], function(ufCom) {
// ufCom是引入的js的暴露的对象,即设置的name。根据上面的配置,有install方法和components组件集合。
ufCom.install(Vue); // 如果需要全局注册就执行该方法,可直接使用组件
Vue.prototype.$ufCom = ufCom.components; // 或者挂载到vue原型上
})
线上部署使用
线上部署完毕后,获得其服务器上的相对地址,比如:http://128.0.1.2:8081/static/js/ufCom.js,那么requirejs.config配置时,地址就改为上述地址,前缀通过js拿到。这里可以加个环境判断:process.env.NODE_ENV,如果值为development即为开发环境,使用本地地址,否则使用线上服务资源。
第三步:升级更新
后续公共组件更新升级,打包公共组件,将线上的资源包替换成新的。为了避免缓存影响,我们可以在我们的公共组件包里面多暴露一个参数,即当前资源包版本:version,和install,components同级,同时子模块中设置需要的公共组件的版本,项目运行时,发现子模块的公共组件版本高于缓存中已有的版本,那么会重新进行请求。否则使用缓存。
// main.js
const ufComVersion = 1.0;
if (Vue.prototype.$ufCom?.version <= ufComVersion) {
requirejs.config({
paths: {
ufCom: './xx/ufCom-amd', // 包的资源路径,如果本地用,可以放本地static作为静态资源,也可以改为线上服务器地址,只要能访问到,这里不加js,因为访问时会加js。
}
});
requirejs(['ufCom'], function(ufCom) {
// ufCom是引入的js的暴露的对象,即设置的name。根据上面的配置,有install方法和components组件集合。
ufCom.install(Vue); // 如果需要全局注册就执行该方法,可直接使用组件
Vue.prototype.$ufCom = ufCom.components; // 或者挂载到vue原型上
})
}
缺点
- 无法进行多版本控制,如果不同的子模块需要不同的公共组件版本,该功能无法实现。
- 组件挂载到全局,而非按需引入,性能效率不高。