环境准备
egg.js 支持 macOS、Linux、Windows,Node.js 最低 8.x
初始化
初始化 egg.js 可以使用官方推荐的脚手架
$ mkdir egg-example && cd egg-example
$ npm init egg --type=simple
$ npm i
npm init egg 相当于执行
npx create-egg
,npx 在 npm 5.2.0 后支持,可以在不安装包的情况下执行其二进制文件
脚手架支持多种类型 egg.js 项目创建,对于 Web 服务器可以使用 simple
- simple - Simple egg app boilerplate
- microservice - Microservice app boilerplate based on egg
- sequelize - egg app with sequelize
- ts - Simple egg && typescript app boilerplate
- empty - Empty egg app boilerplate
- plugin - egg plugin boilerplate
- framework - egg framework boilerplate
目录结构
初始化后可以得到主要文件如下的目录结构egg-example
├── package.json
├── app
| ├── router.js
│ ├── controller
│ | └── home.js
├── config
| ├── plugin.js
| ├── config.default.js
└── test
└── controller
└── app
└── home.test.js
路由设置
app/router.js
是用户请求的起点,脚手架初始化了一个首页的路由module.exports = app => {
const { router, controller } = app;
router.get('/', controller.home.index);
};
controller.home.index
的含义是app/controller/home.js
文件的index
函数,这是 egg.js 约定的一部分,按照约定路由还可以写成如下形式
这样的书写更为简单,约定了所有的 Controller 都在 app/controller 目录下module.exports = app => {
app.get('/', 'home.index');
};
MVP 模式
在示例代码中所有的页面生成逻辑都写在了 Controller(虽然文件夹名字是 controller,但实际作用是 MVP 模式中的 presenter) 中,按照 egg.js 目录约定可以添加几个文件,轻松实现 MVP 模式egg-example
├── package.json
├── app
| ├── router.js
│ ├── controller
│ | └── home.js
│ ├── service
│ | └── home.js
│ ├── view
│ | └── home.hbs
├── config
| ├── plugin.js
| ├── config.default.js
└── test
└── controller
└── app
└── home.test.js
- app/view 目录可以存放 View 相关的模板文件
- app/service 目录存放 Model 相关的 js 文件
service 实现
修改 app/service/home.js 为 ```javascript ‘use strict’;
const Service = require(‘egg’).Service;
class HomeService extends Service { async getUser() { return ‘Sunluyong’; } }
module.exports = HomeService;
文件 export 的类继承 `require('egg').Service` 即可实现一个 Model,内部定义 Presenter 会用到的数据处理方法,支持 async/await 的写法
和具体业务逻辑无关的数据处理,比如数据库查询、文件读写等可以定义在 service
<a name="87MFZ"></a>
### view 实现
View 的渲染不变使用模板引擎,egg.js 本身并不包含模板引擎的实现,而是通过[渲染插件](https://www.npmjs.com/search?q=egg-view-)来实现,我们选择使用 [egg-view-handlebars](https://www.npmjs.com/package/egg-view-handlebars) 示例
> egg.js 支持的模板引擎:[https://github.com/topics/egg-view](https://github.com/topics/egg-view)
<a name="5iB5v"></a>
#### 1. 安装插件
```bash
npm i egg-view-handlebars --save
2. 启用插件
插件安装后需要显式的启用声明才会正常工作,修改文件 /config/plugins.js
module.exports = {
handlebars: {
enable: true,
package: 'egg-view-handlebars',
},
};
3. 配置 View 渲染选项
修改应用配置文件 /config/config.default.js
中关于 View 渲染相关的设置,把 handlebars 配置为默认的渲染引擎
config.view = {
defaultViewEngine: 'handlebars',
defaultExtension: '.hbs',
mapping: {
'.hbs': 'handlebars',
},
};
4. 修改模板文件
修改 app/view/home.hbs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{title}}</title>
</head>
<body>
Hi {{user}}, welcom to use egg.js.
</body>
</html>
presenter
presenter 用于接收用户请求进行业务逻辑处理,获取数据后驱动视图渲染,对 app/controller/home.js 的 index
方法做调整,渲染用户名称
const Controller = require('egg').Controller;
class HomeController extends Controller {
async index() {
const { ctx } = this;
const user = await ctx.service.home.getUser();
await this.ctx.render('home', {
title: 'Egg.js demo homepage',
user,
});
}
}
module.exports = HomeController;
和 Koa 非常类似,egg.js 也把请求级对象挂载到了 this.ctx
,应用全局设置挂载到了 this.app
,在代码中使用了 egg.js 的几个约定
- app/service 下文件 export 的 class 会被挂载到
this.ctx.service.fileName
,文件名会自动转成驼峰格式,无需手工配置 await this.ctx.render()
等同于ctx.body = await this.ctx.render()
,用于设置 HTTP response body官方建议
其实在 egg.js 官方建议中
controller 用来解析用户输入,处理返回结果
- service 用来处理业务逻辑
- model 才是用来处理业务无关的数据处理(ORM)
但在普通规模的业务实现中按照上述目录结构,大部分方法需要层层调用,比较繁琐,在普通项目中可以按照上文介绍的方式书写代码,涉及 ORM 时候可以引入 model 层
程序启动
脚手架在 package.json 中设置了几个开发、调试的 scripts
"scripts": {
"start": "egg-scripts start --daemon --title=egg-server-example",
"stop": "egg-scripts stop --title=egg-server-example",
"dev": "egg-bin dev",
"debug": "egg-bin debug",
"test": "npm run lint -- --fix && npm run test-local",
"test-local": "egg-bin test",
"cov": "egg-bin cov",
"lint": "eslint .",
"ci": "npm run lint && npm run cov",
"autod": "autod"
}
在日常开发时候可以使用 npm run dev
进行开发,默认应用会在 7001 端口启动,文件修改时应用会自动重新启动
[egg-ts-helper] create typings/app/controller/index.d.ts (2ms)
[egg-ts-helper] create typings/config/index.d.ts (14ms)
[egg-ts-helper] create typings/config/plugin.d.ts (1ms)
[egg-ts-helper] create typings/app/service/index.d.ts (1ms)
[egg-ts-helper] create typings/app/index.d.ts (0ms)
2020-07-12 19:18:14,138 INFO 605 [master] node version v14.5.0
2020-07-12 19:18:14,138 INFO 605 [master] egg version 2.27.0
2020-07-12 19:18:14,875 INFO 605 [master] agent_worker#1:607 started (733ms)
2020-07-12 19:18:15,753 INFO 605 [master] egg started on http://127.0.0.1:7001 (1615ms)
调试
egg.js 的调试也非常方便,执行 npm run debug
就可进入调试流程,具体操作和普通 Node.js 调试没区别
官方文档还介绍了使用 debug 模块、WebStorm、VSCode 的调试方法,具体可以参考 Egg.js 本地开发
总结
这样就实现了一个简单的 MVP 模式 Web 应用,完整代码参考 https://github.com/Samaritan89/egg-demo/tree/v1
官方快速入门教程