1.搭建方式
- 一共有两种搭建方式,一种运用脚手架快速搭建,一种是手动搭建。
- 1.脚手架快速搭建
npm i egg-init -g
egg-init egg-example --type=simplecd egg-example
npm i复制代码
启动项目
npm run dev
open localhost:7001复制代码
- 2.逐步手动搭建
初始化
mkdir egg-examplecd egg-example
npm init
npm i egg --save
npm i egg-bin --save-dev复制代码
添加npm scripts到package.json中
{"name":"egg-example","scripts": {"dev":"egg-bin dev"
}
}复制代码
编写controller和router
// app/controller/home.js
const Controller = require('egg').Controller;
class HomeController extends Controller {
asyncindex() {
this.ctx.body ='Hello world';
}
}
module.exports = HomeController;复制代码
配置路由
// app/router.js
module.exports = app => {
const { router, controller } = app;
router.get('/', controller.home.index);
};复制代码
配置文件
// config/config.default.js
exports.keys = <此处改为你自己的 Cookie 安全字符串>;复制代码
此时项目目录如下
egg-example
├── app
│ ├── controller
│ │ └── home.js
│ └── router.js
├── config
│ └── config.default.js
└── package.json复制代码
启动应用
npm run dev
open localhost:7001复制代码
静态资源
egg内置了static插件,线上环境部署到cdn上,无需配置该插件
app/public
├── css
│ └── news.css
└── js
├── lib.js
└── news.js复制代码
渲染模板
- 首先安装对应的模板插件egg-view-nunjucks
npm i egg-view-nunjucks --save复制代码
开启插件
// config/plugin.js
exports.nunjucks = {enable:true,
package:'egg-view-nunjucks'
};复制代码
// config/config.default.js
exports.keys = <此处改为你自己的 Cookie 安全字符串>;
// 添加 view 配置
exports.view = {
defaultViewEngine:'nunjucks',
mapping: {'.tpl':'nunjucks',
},
};复制代码
为列表页编写模板文件,一般放置在app/view下
<!-- app/view/news/list.tpl -->
<html>
<head>
<title>Hacker News</title>
<link rel="stylesheet" href="/public/css/news.css" />
</head>
<body>
<ul class="news-view view">
{%for itemin list %}
<li class="item">
<a href="{{ item.url }}">{{ item.title }}</a>
</li>
{% endfor %}
</ul>
</body>
</html>复制代码
为其添加controller和router
// app/controller/news.js
const Controller = require('egg').Controller;
class NewsController extends Controller {
asynclist() {
const dataList = {
list: [
{ id: 1, title:'this is news 1', url:'/news/1' },
{ id: 2, title:'this is news 2', url:'/news/2' }
]
};
await this.ctx.render('news/list.tpl', dataList);
}
}
module.exports = NewsController;
// app/router.js
module.exports = app => {
const { router, controller } = app;
router.get('/', controller.home.index);
router.get('/news', controller.news.list);
};复制代码
开发期默认开启了 development 插件,修改后端代码后,会自动重启 Worker 进程。
编写service(复杂的业务逻辑)
抓取hackernews
// app/service/news.js
const Service = require('egg').Service;
class NewsService extends Service {
async list(page = 1) {
//read config
const { serverUrl, pageSize } = this.config.news;
// use build-in http client to GET hacker-news api
const { data: idList } = await this.ctx.curl(`${serverUrl}/topstories.json`, {
data: {
orderBy:'"$key"',
startAt: `"${pageSize * (page - 1)}"`,
endAt: `"${pageSize * page - 1}"`,
},
dataType:'json',
});
// parallel GET detail
const newsList = await Promise.all(
Object.keys(idList).map(key => {
const url = `${serverUrl}/item/${idList[key]}.json`;return this.ctx.curl(url, { dataType:'json' });
})
);return newsList.map(res => res.data);
}
}
module.exports = NewsService;复制代码
修改controller
// app/controller/news.js
const Controller = require('egg').Controller;
class NewsController extends Controller {
asynclist() {
const ctx = this.ctx;
const page = ctx.query.page || 1;
const newsList = await ctx.service.news.list(page);
await ctx.render('news/list.tpl', { list: newsList });
}
}
module.exports = NewsController;复制代码
还需增加 app/service/news.js 中读取到的配置:
// config/config.default.js
// 添加 news 的配置项
exports.news = {
pageSize: 5,
serverUrl:'https://hacker-news.firebaseio.com/v0',
};复制代码
编写扩展
遇到一个小问题,我们的资讯时间的数据是 UnixTime 格式的,我们希望显示为便于阅读的格式.在这里,我们可以使用 View 插件支持的 Helper 来实现.
npm i moment --save复制代码
// app/extend/helper.js
const moment = require('moment');
exports.relativeTime = time => moment(new Date(time * 1000)).fromNow();复制代码
在模板里面使用:
<!-- app/view/news/list.tpl -->
{{ helper.relativeTime(item.time) }}复制代码
编写middleware
假设有个需求:我们的新闻站点,禁止百度爬虫访问。
聪明的同学们一定很快能想到可以通过 Middleware 判断 User-Agent
// app/middleware/robot.js
// options === app.config.robot
module.exports = (options, app) => {return asyncfunction robotMiddleware(ctx, next) {
constsource = ctx.get('user-agent') ||'';
const match = options.ua.some(ua => ua.test(source));if (match) {
ctx.status = 403;
ctx.message ='Go away, robot.';
}else {
await next();
}
}
};
// config/config.default.js
// add middleware robot
exports.middleware = ['robot'
];
// robot's configurations
exports.robot = {
ua: [
/Baiduspider/i,
]
};复制代码
框架提供了强大的配置合并管理功能
- 支持按环境变量加载不同的配置文件,如 config.local.js, config.prod.js 等等。
- 应用/插件/框架都可以配置自己的配置文件,框架将按顺序合并加载。
// config/config.default.js
exports.robot = {
ua: [
/curl/i,
/Baiduspider/i,
],
};
// config/config.local.js
// onlyread at development mode, will override default
exports.robot = {
ua: [
/Baiduspider/i,
],
};
// app/service/some.js
const Service = require('egg').Service;
class SomeService extends Service {
asynclist() {
const rule = this.config.robot.ua;
}
}
module.exports = SomeService;复制代码