DoraCMS

您现在的位置是:首页>文档内容页

文档详情

DoraCMS 插件化探索(一)

doramart 2019-10-17 00:25:17 原创教程23722
DoraCMS 从今年年初的时候开始有插件化构想,为什么会有这种想法?其实就目前发布的DoraCMS 2.1.3 来讲,对比之前的版本有很多优化,最重要的一点是建立了比较清晰的代码结构

    DoraCMS 从今年年初的时候开始有插件化构想,为什么会有这种想法?其实就目前发布的DoraCMS 2.1.3 来讲,对比之前的版本有很多优化,最重要的一点

是建立了比较清晰的代码结构,后台管理基于vue的spa模式,服务端 MVC 架构也非常明显,对比2.1.2 版本服务端抽离出了server 层,让数据操作更加便捷,避免混乱的各种查询。这是 2.1.3 的目录结构:


├─build // webpack 相关配置文件

├─client // 客户端文件(前台/后台)

│  │

│  ├─index      // 前台组件

│  │

│  ├─manage     // 后台组件

│  │

│  └─template   // 初始模版

├─databak // 默认数据备份目录

├─logs // 日志目录

├─public  // 静态文件目录

│  │

│  ├─admin // 后台vue编译后的文件目录

│  │

│  ├─apidoc // api文档目录

│  │

│  ├─plugins // 前台依赖的相关组件

│  │

│  ├─themes // 皮肤目录

│  │

│  ├─ueditor // ueditor插件目录

│  │

│  ├─upload // 文件上传目录

│  │

│  └─vendor // 后台静态dll目录

├─server    // 服务端目录

│  │

│  ├─bootstrap   // 前台渲染相关

│  │

│  ├─configs   // 系统配置

│  │

│  ├─locales   // 国际化

│  │

│  ├─middleware   // 中间件

│  │

│  │

│  ├─lib    // 核心层

│  │  ├─contorller   // 控制器

│  │  │

│  │  ├─model   // 数据模型

│  │  │

│  │  ├─service   // 数据库操作

│  │  │

│  │  └─utils

│  │     ├─cache // redis缓存

│  │     │

│  │     ├─memoryCache // 内存缓存

│  │     │

│  │     ├─authPower.js // 资源鉴权

│  │     │

│  │     ├─authSession.js // session 鉴权

│  │     │

│  │     ├─authToken.js // token鉴权

│  │     │

│  │     ├─mime.js // 文件类型

│  │     │

│  │     ├─siteFunc.js // 公共方法

│  │     │

│  │     └─validatorUtil.js // 信息校验

│  │

│  │

│  └─routers   // 路由

└─views          // 前台模板

├─dorawhite   // 主题目录

├─admin.html    // 后台管理模板

└─adminUserLogin.html    // 后台登录模板


先从基于vue后台管理说起,后台管理的界面以及逻辑在 /client/manage 下,每个模块非常清晰:

1571242508798920070.png

熟悉 DoraCMS 的童鞋都知道,开发完成后,执行

npm run build

就可以将我们开发的vue工程编译为浏览器可以识别的es5,发布到生产。非常方便,但是在开发过程中,我渐渐发现一些问题:

1、开发了很多模块后,编译速度非常慢。

2、有时候只改了一个vue文件,也需要重新编译,非常浪费资源

3、有些功能模块我现在不想用了,怎样友好的剥离掉?


这些是我们在实际开发场景下经常遇到的问题,于是通过google,我了解到了前端微服务,至今为止,我认为微服务将成为今后大型应用必不可少要考虑的架构。

什么是“微服务”,说通俗一点,我认为的微服务就是模块拆分,相互隔离解耦,互不影响,按需加载等;那么基于 DoraCMS 2.1.3 目前的架构,如何来做微服务呢?通过大量的调研和实践,我找到了一个比较合适的方案 : single-spa , 我做了如下尝试:


1、把每个模块独立出来,每个模块作为一个标准的小app抽离(基于 vue-cli)

1571242559930668929.png


2、通过 single-spa 提供的方法将每个模块串联起来,类似下面这样(DoraCMS 的实现相同) 

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Coexisting Vue Microfrontends</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="importmap-type" content="systemjs-importmap">
    <script type="systemjs-importmap">
      {
        "imports": {
          "navbar": "http://localhost:8080/app.js",
          "app1": "http://localhost:8081/app.js",
          "app2": "http://localhost:8082/app.js",
          "single-spa": "https://cdnjs.cloudflare.com/ajax/libs/single-spa/4.3.7/system/single-spa.min.js",
          "vue": "https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js",
          "vue-router": "https://cdn.jsdelivr.net/npm/vue-router@3.0.7/dist/vue-router.min.js"
        }
      }
    </script>
    <link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/single-spa/4.3.7/system/single-spa.min.js" as="script" crossorigin="anonymous" />
    <link rel="preload" href="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js" as="script" crossorigin="anonymous" />
    <script src="https://unpkg.com/import-map-overrides@1.7.2/dist/import-map-overrides.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/system.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/amd.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/named-exports.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/named-register.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/use-default.min.js"></script>
  </head>
  <body>
    <script>
      (function() {
        Promise.all([System.import('single-spa'), System.import('vue'), System.import('vue-router')]).then(function (modules) {
          var singleSpa = modules[0];
          var Vue = modules[1];
          var VueRouter = modules[2];

          Vue.use(VueRouter)

          singleSpa.registerApplication(
            'navbar',
            () => System.import('navbar'),
            location => true
          );

          singleSpa.registerApplication(
            'app1',
            () => System.import('app1'),
            location => location.pathname.startsWith('/app1')
          )

          singleSpa.registerApplication(
            'app2',
            () => System.import('app2'),
            location => location.pathname.startsWith('/app2')
          )

          singleSpa.start();
        })
      })()
    </script>
    <!-- See https://github.com/joeldenning/import-map-overrides#user-interface  -->
    <import-map-overrides-full show-when-local-storage="overrides-ui"></import-map-overrides-full>
  </body>
</html>


3、处理权限、路由等细节


经过架构变更之后,可以达到这样的效果:

1、每个模块相互独立了,编译出的js彼此分开。

2、按需编译,改哪个模块,编译哪个模块,借助jenkins,更新模块到服务器非常方便:

1571242635303246827.png

3、再也不用担心模块过多引起的编译速度过慢了,添加哪个编译哪个

4、后台的所有模块跟服务端基本没有关系了,独立开发,于是即使多个人同时开发后台管理模块,也相互不影响。 


PS: single-spa 微服务架构已经应用到 DoraCMS 2.1.4 版本,有兴趣的童鞋在后面发布后可以clone下来试试。

文章评论

Cancel the reply
Login Participate In Comments

Review(