vue项目架构:多子系统拆分与集成

现状

公司现有一个大型项目分为多个子系统(或叫子模块),现公司产品经理提出要求,各子系统要实现即可独立分包部署,又可以整合为一个整体包。按照以前项目经验及一贯作风,是将每个子系统构建一个git代码仓库管理,部署时无论是独立部署,还是统一出口都可以使用nginx来进行代理而实现。
但是各个子系统的共用组件、依赖、认证等都是一样,分多个git仓库源代码来管理,会存在很多重复工作,并且修改一个组件需要在每个子系统中进行修改。不便于管理及维护。

分析

要实现多子系统互相不干扰,并主系统能集成任意子系统,那么我们考虑就需要对每个子系统有一个独立的入口文件,同时主系统也有自己的入口文件。从而实现可拔插式结构,子系统之间通过统一的token进行交互认证。逻辑结构如下图:


逻辑结构.png

实现

1、使用脚手架构建项目,在src下新建文件夹projects,用于存放主系统及各子系统文件,其中任何一个项目文件都相当于一个小vue,可以进行单独运行。具体如下:

工程目录结构.png

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的使用。