使用 egg.js 定製業務 web 框架

Web 框架作的事情太少就會致使可用性差,作的太多就會比較定製,而 Egg 是框架的框架,幫助團隊的技術負責人,來定製適合特定的業務場景的上層業務框架。egg.js 的名稱含義正是這樣,像 egg 同樣孕育 Web 框架html

前面章節介紹瞭如何使用 egg.js 完成業務開發、定製插件,這些是把 egg.js 當作一個 web 框架使用,本章節介紹下 egg.js 作爲框架的框架爲業務定製一個 web 框架的能力node

設計目標

能夠把前面章節實現的基礎功能作爲 demo 框架的默認功能,封裝完成後提供給團隊使用git

  1. 自帶 handlebars 模板渲染能力
  2. 全部請求自動統計耗時
  3. enum、util 掛載到 this.app

配置框架

初始化代碼

使用 egg.js 提供的 framework 腳手架初始化框架代碼github

$ mkdir framework-demo && cd framework-demo
$ npm init egg --type=framework
複製代碼

目錄結構應該很熟悉了,多出來的lib/framework.js 是框架的入口web

framework-demo
├── app
│   ├── extend
│   └── service
├── config
│   ├── config.default.js
│   └── plugin.js
├── lib
│   └── framework.js
├── test
├── README.md
├── index.js
└── package.json
複製代碼

handlebars 模板引擎支持

egg.js 使用的章節介紹過 如何配置模板引擎,定製框架的時候步驟同樣npm

安裝 egg-view-handlebars

$ npm i egg-view-handlebars --save
複製代碼

啓用插件

// config/plugin.js
module.exports = {
  handlebars: {
    enable: true,
    package: 'egg-view-handlebars',
  },
};
複製代碼

配置 view 渲染項

// config/config.default.js
config.view = {
  defaultViewEngine: 'handlebars',
  defaultExtension: '.hbs',
  mapping: {
    '.hbs': 'handlebars',
  },
};
複製代碼

這樣使用該框架就默認具有了 handlebars 渲染能力json

內置請求耗時中間件

中間件的編寫規則和在 egg.js 中直接使用一致,不過添加到框架的方式有所不一樣markdown

添加 cost 中間件

// app/middleware/cost.js
module.exports = options => {
  const header = options.header || 'X-Response-Time';

  return async function cost(ctx, next) {
    const now = Date.now();
    await next();
    ctx.set(header, `${Date.now() - now}ms`);
  };
};
複製代碼

應用中間件

框架和插間添加中間件和直接在應用中使用不一樣,不支持修改 config 文件,須要在項目根目錄下的 app.js 修改app

// app.js
module.exports = app => {
  // 在中間件最前面統計請求時間
  app.config.coreMiddleware.unshift('cost');
};
複製代碼

enum、util 掛載

在框架中有不少業務的字段枚舉或者通用的工具類,通常是定義了文件夾統一管理,開發使用的時候手工 require,使用 egg.js 後能夠把約定內置框架,在指定目錄編寫後自動加載到框架框架

文件添加

添加文件 app/enum/error.jsapp/util/dto.js

framework-demo
├── app
│   ├── extend
│   ├── service
│   ├── enum
│   │       └── error.js
│   └── util
│   │       └── dto.js
└── package.json

// app/enum/error.js
'use strict';

exports.ERR_AUTH = {
  code: '403',
  msg: 'not perm',
};

exports.ERR_NOTFOUND = {
  code: '404',
  msg: 'not found',
};

exports.ERR_SERVER = {
  code: '500',
  msg: 'internal server error',
};

// app/util/dto.js
'use strict';

const assert = require('assert');

function isObject(obj) {
  const objType = Object.prototype.toString.call(obj);
  return objType === '[object Object]' || objType === '[object Array]' || objType === '[object Null]';
}

class ResultDto {
  constructor(result, code = 200, errorMsg = '', errorStack = null) {
    assert(isObject(result), '[ResultDto:constructor]: arg[0] must be an object or null!');

    this.result = result;
    this.success = code === 200;
    this.code = code;
    if (code !== 200) {
      this.errorMsg = errorMsg;
      this.errorStack = errorStack;
    }
  }
}

exports.ResultDto = ResultDto;
複製代碼

配置 loader

在配置文件中爲文件夾聲明路徑和注入的對象,更多細節參考 EggJS 加載器

// config/config.default.js
config.customLoader = {
  enum: {
    directory: 'app/enum',
    inject: 'app',
    loadunit: true,
  },
  util: {
    directory: 'app/util',
    inject: 'app',
    loadunit: true,
  },
};
複製代碼

自動提示

因爲 Egg 是動態掛載的,如需 TS 和智能提示支持,須要經過 egg-ts-helper 來自動生成映射

首先修改 package.json 文件聲明

// package.json
{
  "name": "framework-demo",
  "egg": {
    "declaration": true,
    "tsHelper": {
      "watchDirs": {
        "enum": {
          "enabled": true,
          "directory": "app/enum",
          "declareTo": "Application.enum"
        },
        "util": {
          "enabled": true,
          "directory": "app/util",
          "declareTo": "Application.util"
        }
      }
    }
  }
}
複製代碼

egg-bin 內置支持了自動生成 typings 文件夾,但框架開發一般不會使用 egg-bin dev 爲了方便框架開發能夠在 scripts 配置生成 typeings 的命令

"scripts": {
  "typing": "npx ets"
},
複製代碼

使用

image.png

測試 & 發佈

這樣就完成了框架定製,框架由於涉及多人使用,須要有完善的測試保證可用性,egg.js 提供了完備的測試支持,測試工做完成後能夠進入發佈流程

  1. 根據語義化版本號規則使用合適的版本
  2. 發佈 beta 版本 npm publish --tag=beta
  3. 測試 OK 後發佈正式版本 npm publish

使用框架

在 egg.js 應用中使用框架很簡單,把 egg 腳手架生成的應用 package.json 稍做修改便可

{
  "name": "egg-demo",
  "version": "1.0.0",
  "egg": {
    "declarations": true,
    "framework": "egg-framework-demo"
  },
  "dependencies": {
    "egg-framework-demo": "^1",
    "egg-scripts": "^2.11.0"
  }
}
複製代碼

package.json 聲明框架後 npm run dev 能夠看到已經使用 egg-demo-framework 啓動框架了,cost 中間件也正常工做

INFO 76333 [master] egg-framework-demo started on http://127.0.0.1:7001 (1901ms)
複製代碼

image.png

完整代碼:github.com/Samaritan89…

參考

  1. 如何爲團隊量身定製 EggJS 目錄掛載規範
  2. 基於 EggJS 爲團隊定製本身的 Node.js 框架
相關文章
相關標籤/搜索