现状
公司现有一个大型项目分为多个子系统(或叫子模块),现公司产品经理提出要求,各子系统要实现即可独立分包部署,又可以整合为一个整体包。按照以前项目经验及一贯作风,是将每个子系统构建一个git代码仓库管理,部署时无论是独立部署,还是统一出口都可以使用nginx来进行代理而实现。
但是各个子系统的共用组件、依赖、认证等都是一样,分多个git仓库源代码来管理,会存在很多重复工作,并且修改一个组件需要在每个子系统中进行修改。不便于管理及维护。
分析
要实现多子系统互相不干扰,并主系统能集成任意子系统,那么我们考虑就需要对每个子系统有一个独立的入口文件,同时主系统也有自己的入口文件。从而实现可拔插式结构,子系统之间通过统一的token进行交互认证。逻辑结构如下图:
实现
1、使用脚手架构建项目,在src下新建文件夹projects,用于存放主系统及各子系统文件,其中任何一个项目文件都相当于一个小vue,可以进行单独运行。具体如下:
2、任何小vue项目中包含入口文件main.js,以及项目需要的views页面,这里我们将路由进行拆分为index.js,和path.js,目的是便于我们主系统需要子系统路由而进行路由合并。
index.js——主要用于创建路由对象,以及合并需要的路由。
path.js——用于放置项目中需要的具体路由。
以主系统为例:
index.js 文件内容:
import Vue from "vue";
import VueRouter from "vue-router";
//引入主系统路由path.js
import mainRouter from "@/projects/mainSystem/router/path.js"//导入主系统路由文件
//引入其他子系统path.js
import projectARouter from "@/projects/projectA/router/path.js"//导入子系统路由文件
Vue.use(VueRouter);
//合并路由(将需要的路由进行合并)
let routes = new Set([...mainRouter, ...projectARouter ]);
const router = new VueRouter({
mode: 'hash',
base: process.env.BASE_URL,
routes
})
//解决路由导航冗余报错(路由重复)
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}
export default router
path.js文件内容(主系统自身的路由):
/**
* 主系统路由地址
* @returns {Promise<*>|*}
*/
let firstPageIndex=()=>import(/* webpackChunkName: "mainSystem" */ "@/projects/mainSystem/views/index/index.vue")
let mainHome=()=>import(/* webpackChunkName: "mainSystem" */ "@/projects/mainSystem/views/Home")
let mainLayout=()=>import(/* webpackChunkName: "mainSystem" */ "@/components/base/publicLayout")
export default [
{
path: "/",
name: "home",
component: mainHome
}, {
path: '/mainSystem-layout.html/:childSystemCode',
name: 'mainSystem-layout',
component: mainLayout,
children: [
{
path: "/mainSystem/index.html",
name: "/mainSystem/index",
component: firstPageIndex,
meta: {
isFork: false,
hideHeader: false,
notPadding: true
}
}
]
}
]
3、在根目录下创建config文件夹及projectsConfig.js,用于存放各系统入口配置。
const config = {
//主系统
mainSystem: {
pages: {
index: {
entry: "src/projects/mainSystem/main.js",
template: "public/index.html",
filename: "index.html"
}
},
devServer: {
port: 8081, // 端口地址
open: false, // 是否自动打开浏览器页面
host: "0.0.0.0", // 指定使用一个 host,默认是 localhost
https: false, // 使用https提供服务
disableHostCheck: true,
}
},
//子系统A
projectA: {
pages: {
index: {
entry: "src/projects/projectA/main.js",
template: "public/index.html",
filename: "index.html"
}
},
devServer: {
port: 8080, // 端口地址
open: false, // 是否自动打开浏览器页面
host: "0.0.0.0", // 指定使用一个 host,默认是 localhost
https: false, // 使用https提供服务
disableHostCheck: true,
}
},
};
module.exports = config;
4、将配置文件projectsConfig.js在vue.config.js引入,通过控制入口文件的路径和输出的路径实现,分模块打包。
//多子系统分模块打包
const config = require("./config/projectsConfig.js");
let projectName = process.env.PROJECT_NAME;
module.exports = {
......
......
......
// webpack-dev-server 相关配置
...config[projectName],
}
5、安装cross-env,在我们执行打包命令的时候,通过cross-env找到我们的入口文件。
npm install --save-dev cross-env
6、修改package.json中脚本。
{
"scripts": {
"dev:mainSystem": "cross-env PROJECT_NAME=mainSystem vue-cli-service serve",
"dev:projectA": "cross-env PROJECT_NAME=projectA vue-cli-service serve",
"build:mainSystem": "cross-env PROJECT_NAME=mainSystem vue-cli-service build",
"build:projectA": "cross-env PROJECT_NAME=projectA vue-cli-service build",
},
}
7、现在可以使用命令分别进行运行 和 打包各系统
运行及打包主系统
npm run dev:mainSystem
npm run build:mainSystem
运行及打包子系统
npm run dev:projectA
npm run build:projectA
注意
1、除入口文件需要配置正确外,任何小vue需要使用的路由必须引入合并。
2、由于路由需要合并使用,所以在各子系统中定义路由最好添加固定的前缀,从而避免路由名冲突。
3、各系统中使用统一认证token进行交互,所以在业务逻辑中,注意token的使用。