Skip to content
On this page

前端微架构实践

前言

为了拆分与适当解耦聚合业务各模块,我们需要采用一种友好的开发模式去解决这些问题,我们的愿景是:

  • ☕️ 主子项目独立开发、部署
  • 🔥 主子项目开发时保持热更新
  • 🚗 主项目提供路由容器,子项目只是挂载到容器中的视图
  • 👊 主子项目共用一个 Vue、Router、Store 实例,这样能保证能共享全局组件或 Vue 插件
  • 📦 子项目在开发时会动态注入主项目容器、打包后不会包含任何主项目代码
  • 💻 不涉及 Node 服务,配置文件存储在 CDN 中

Tips: 为了避免主项目打包体积过大,可以将库代码抽取为 CDN 引入(默认),这样子项目动态注入时下载更快。

⚠️ 关于按需加载,在开发环境下,由于webpack devServer 加载资源时是不会跨项目加载的,所以是无法做到的,当然可以改造 webpack 的加载逻辑,把待加载的资源 origin 设置为 项目菜单配置中的 origin。打包后如果主子项目的静态资源部署在同一个目录下,是可以支持按需加载的。

开发流程

1.安装 micro-structure-cli 插件

npm install -g micro-structure-cli

2.创建配置文件,并可以通过 http 访问到该文件

Tips: 在开发时,你可以在主项目的 /public/ 目录下创建

配置文件结构示例:

js
/*
 * 目前这个配置文件的格式有待完善
 * 配置文件对应着加载器逻辑
 */
window._MICRO_APP_CONFIG = {
  // 开发环境的配置
  devMenu: [
    {
      // 资源的唯一标识,用来避免重复加载
      id: 'index',
      name: '首页',
      path: '/',
      // 该项目入口文件的 path,也就是去掉下面 origin 后的地址
      urlPath: '/app.js',
      // 将 origin 抽取出来的目的是用来判断
      // 当前路由对应的项目资源 是否为 当前 devServer ,避免重复加载
      origin: 'http://localhost:8080'
    }
  ],
  // 非开发环境
  normalMenu: []
}

3.创建主项目

# 初始化选择主项目
micro init

# 提示输入菜单配置文件 url 地址

# 安装依赖
npm install 

启动服务
npm run serve

4.创建子项目

借助 vue-cli-plugin-micro 插件来注入主项目资源

# 初始化选择子项目
micro init

# 安装依赖
npm install 

# 安装主项目资源注入插件
vue add micro

# 启动服务
npm run serve

# 在配置文件中,增加子项目的菜单信息

# 主项目有更新时,运行命令会自动刷新
npm run micro

加载器

加载器存在于主项目中,用来加载当前 path 对应的子项目,同时给路由添加守卫,在离开前加载对应路由的子项目。

由上面的配置文件暴露的 window 对象 _MICRO_APP_CONFIG 加载器的逻辑也在该对象下

js
window. _MICRO_APP_CONFIG = {
  // 已区分环境的菜单列表
  menu: [],
  // 加载方法
  load: function (menuItem) {
  },
  // 初始化时为路由添加的守卫
  addWatch: function () {}
}

如果是正常的路由跳转,加载器会自动处理。如果需要预加载,可以手动触发 load 方法。

Tips: 加载时的 loading 未实现

流程图

7a76706e4f291870232542527e531258a22cdcae

最后完整的项目地址:micro-structure

适用场景

业务复杂的中台系统不用多说,很有必要。另外,同类性质的简单页面也适用,例如营销活动页面,可以将库、请求、通用逻辑抽象到主项目上,子项目只用关注活动本身,减小了项目体积,能非常有效的提升开发速度。

也就是说,并不是在业务上属于一个模块的才归属到子项目中,子项目是路由集合,形态结构上属于同一类的业务也可以被归属到一起。

扩展

很显然,这是基于 Vue 及 Vue 原型来实现的一套方案,如果换做是 React 呢?或者主子项目跨技术栈呢?我想这些都会比较容易去思考实现。因为这是接下来要做的事情。