EggJS
Midway 可以使用 EggJS 作为上层 Web 框架,EggJS 提供了非常多常用的插件和 API,帮助用户快速构建企业级 Web 应用。本章节内容,主要介绍 EggJS 在 Midway 中如何使用自身的能力。
描述 | |
---|---|
包含独立主框架 | ✅ |
包含独立日志 | ✅ |
安装依赖
$ npm i @midwayjs/web@3 egg --save
$ npm i @midwayjs/egg-ts-helper --save-dev
针对 EggJS 场景,这些包列举如下。
"dependencies": {
"@midwayjs/web": "^3.0.0",
"@midwayjs/core": "^3.0.0",
"egg": "^2.0.0",
"egg-scripts": "^2.10.0"
},
"devDependencies": {
"@midwayjs/egg-ts-helper": "^1.0.1",
},
@midwayjs/web | 必须,Midway EggJS 适配层 |
---|---|
@midwayjs/core | 必须,Midway 核心包 |
egg | 必须,EggJS 依赖包,提供定义等其他能力 |
egg-scripts | 可选,EggJS 启动脚本 |
@midwayjs/egg-ts-helper | 可选,EggJS 定义生成工具 |
也可以直接使用脚手架创建示例。
# npm v6
$ npm init midway --type=egg-v3 my_project
# npm v7
$ npm init midway -- --type=egg-v3 my_project
开启组件
import { Configuration, App } from '@midwayjs/core';
import * as web from '@midwayjs/web';
import { join } from 'path';
@Configuration({
imports: [web],
importConfigs: [join(__dirname, './config')],
})
export class MainConfiguration {
@App()
app: web.Application;
async onReady() {
// ...
}
}
和默认 EggJS 的不同之处
- 1、从 v3 开始,midway 提供了更多的组件,大部分 egg 内置插件默认禁用
- 2、baseDir 默认调整为
src
目录,服务器上为dist
目录 - 3、禁用 egg-logger,全部替换为 @midwayjs/logger,不可切换
整个架构如下:
目录结构
除了 Midway 提供的目录结构外,EggJS 还有一些特殊的目录结构(不可变),整个结构如下。
➜ my_midway_app tree
.
├── src
| ├── app.ts ## EggJS 扩展 Worker 生命周期文件(可选)
| ├── agent.ts ## EggJS 扩展 Agent 生命周期文件(可选)
| ├── app ## EggJS 固定的根目录(可选)
| │ ├── public ## EggJS 静态托管插件的默认目录(可配)
| │ | └── reset.css
| │ ├── view (可选) ## EggJS 模板渲染的默认目录(可配)
| │ | └── home.tpl
| │ └── extend (可选) ## EggJS 扩展目录(可配)
| │ ├── helper.ts (可选)
| │ ├── request.ts (可选)
| │ ├── response.ts (可选)
| │ ├── context.ts (可选)
| │ ├── application.ts (可选)
| │ └── agent.ts (可选)
| │
| ├── config
| | ├── plugin.ts
| | ├── config.default.ts
| │ ├── config.prod.ts
| | ├── config.test.ts (可选)
| | ├── config.local.ts (可选)
| | └── config.unittest.ts (可选)
│ ├── controller ## Midway 控制器目录(推荐)
│ ├── service ## Midway 服务目录(推荐)
│ └── schedule ## Midway 定时器目录(推荐)
│
├── typings ## EggJS 定义生成目录
├── test
├── package.json
└── tsconfig.json
以上是 EggJS 的目录结构全貌,其中包含了很多 EggJS 特有的目录,有一些在 Midway 体系中已经有相应的能力替代,可以直接替换。整个结构,基本上等价 于将 EggJS 的目录结构移动到了 src
目录下。
由于 EggJS 是基于约定的框架,整个工程的目录结构是固定的,这里列举一些常用的约定目录。
src/app/public/** | 用于放置静态资源,可选,具体参见内置插件 egg-static。 |
---|---|
src/config/config.{env}.ts | 用于编写配置文件,具体参见配置。 |
src/config/plugin.js | 用于配置需要加载的插件,具体参见插件。 |
test/** | 具体参见单元测试。 |
src/app.js 和 src/agent.js | 用于自定义启动时的初始化工作,可选,具体参见启动自定义。关于agent.js 的作用参见Agent机制。 |
配置定义
Midway 在脚手架中提供了标准的 EggJS 的 TS 配置写法,MidwayConfig 中包括了 egg 中配置的定义和属性提示,结构如下。
// src/config/config.default.ts
import { MidwayConfig, MidwayAppInfo } from '@midwayjs/core';
export default (appInfo: MidwayAppInfo) => {
return {
// use for cookie sign key, should change to your own and keep security
keys: appInfo.name + '_xxxx',
egg: {
port: 7001,
},
// security: {
// csrf: false,
// },
} as MidwayConfig;
};
通过这样返回方法的形式,在运行期会被自动执行,合并进完整的配置对象。
这个函数的参数为 MidwayAppConfig
类型,值为以下内容。
appInfo | 说明 |
---|---|
pkg | package.json |
name | 应用名,同 pkg.name |
baseDir | 应用代码的 src (本地开发)或者 dist (上线后)目录 |
appDir | 应用代码的目录 |
HOME | 用户目录,如 admin 账户为 /home/admin |
root | 应用根目录,只有在 local 和 unittest 环境下为 baseDir,其他都为 HOME。 |
注意,这里的 baseDir
和 appDir
和 EggJS 应用有所区别。
使用 Egg 插件
插件是 EggJS 的特色之一,@midwayjs/web
也支持 EggJS 的插件体系,但是在有 Midway 组件的情况下,尽可能优先使用 Midway 组件。
插件一般通过 npm 模块的方式进行复用。
$ npm i egg-mysql --save
然后需要在应用或框架的 src/config/plugin.js
中声明开启。
如果有 export default
,请写在其中。
import { EggPlugin } from 'egg';
export default {
static: false, // default is true
mysql: {
enable: true,
package: 'egg-mysql'
}
} as EggPlugin;
如果没有 export default
,可以直接导出。
// src/config/plugin.ts
// 使用 mysql 插件
export const mysql = {
enable: true,
package: 'egg-mysql',
};
在开启插件 之后,我们就可以在业务代码中使用插件提供的功能了。一般来说,插件会将对象挂载到 EggJS 的 app
和 ctx
之上,然后直接使用。
app.mysql.query(sql, values); // egg 提供的方法
在 Midway 中可以通过 @App
获取 app
对象,以及在请求作用域中通过 @Inject() ctx
获取 ctx
对象,所以我们可以通过注入来获取插件对象。
import { Provide, Inject, Get } from '@midwayjs/core';
import { Application, Context } from '@midwayjs/web';
@Provide()
export class HomeController {
@App()
app: Application;
@Inject()
ctx: Context;
@Get('/')
async home() {
this.app.mysql.query(sql, values); // 调用 app 上的方法(如果有的话)
this.ctx.mysql.query(sql, values); // 调用挂载在 ctx 上的方法(如果有的话)
}
}