模块的意义

在大型Web业务系统中,不可避免包括大量的业务和功能。采用模块化进行系统开发,会带来如下优势:

  1. 代码结构清晰,逻辑充分解耦
  2. 便于团队开发
  3. 便于沉淀技术资产,便于在不同的系统中重复利用
  4. 便于单独编译,保护商业价值
  5. 便于代码版本管理,便于无缝升级

命名约定

为了不断沉淀业务模块,达到高度可复用的效果,所有模块的命名空间必须充分隔离,避免相互污染与冲突,故采用如下命名规范:

egg-born-module-{providerId}-{moduleName}
  • providerId: 开发者Id,强烈建议采用Github的Username,从而确保贡献到社区的模块不会冲突
  • moduleName: 模块名称

基于此命名规范,在项目的前后端引用模块相关资源,定义使用规范如下:

以模块egg-born-module-test-party为例

  • providerId: test
  • moduleName: party
  • fullName: egg-born-module-test-party
  • relativeName: test-party
  • 前端页面路由路径: /test/party/{page}
  • 后端API路由路径: /test/party/{controller}/{action}

模块命名空间隔离

为了适应大型业务开发的场景,避免模块之间的变量污染与冲突,框架对前端和后端均实现了模块命名空间隔离机制,包括模块的前端组件、前端配置、后端逻辑、后端路由、后端配置等等诸元素(请参见后续模块开发的若干章节)

模块分类

EggBornJS中模块有两类:全局模块局部模块

  1. 全局模块:位于目录node_modules
  2. 局部模块:位于目录src/module

加载机制

后端加载

EggBornJS在EggJS的基础上实现了自定义的加载器,在系统启动时,一次性同步加载所有模块,并自动判断并完成模块数据版本的升级逻辑

前端加载

EggBornJS中模块前端代码有两种加载机制:异步加载同步加载

为了支持大型Web业务系统开发,模块默认都是异步加载

如果要实现同步加载,只需在模块名称后面加上后缀-sync,如模块egg-born-module-a-components-sync,此模块提供了基础的前端UI组件,所以同步加载,便于其他模块引用

新建模块

使用脚手架工具创建模块文件骨架

$ cd /path/to/project
$ npm init cabloy src/module/test-party --type=module-business

如果网速慢,可以使用淘宝镜像:

$ npm init cabloy src/module/test-party --type=module-business --registry=https://registry.npm.taobao.org

目前提供了两个模块文件模版:

  1. module-business: 此模版会创建与业务相关的代码,大量简化工作量
  2. module: 此模版仅包含基本的骨架代码文件

模块依赖

通过模块的package.json文件管理模块依赖关系

比如,模块aa-module1依赖aa-module2,需要在模块aa-module1package.json文件中作如下配置

{
  "name": "egg-born-module-aa-module1",
  "version": "0.0.1",
  "eggBornModule": {
    "dependencies": {
      "aa-module2": "0.0.1"
    }
  },
  "dependencies": {
    "egg-born-module-aa-module2": "^0.0.1"
  }
}
名称 说明
“aa-module2”: “0.0.1” 通过此声明,可以确保依赖模块之间的加载顺序
“egg-born-module-aa-module2”: “^0.0.1” 通过此声明,可以确保在安装模块aa-module1时自动安装模块aa-module2