学了一段时间的 js 了,突然想实践一下。正好公司有个小的项目要做,就顺手拿 Koa2 来做了。真是不做不知道,做了想不到。踩了一堆新手坑。
初次接触 Koa2
在知道 Koa2 之前,我也了解过 Express,可惜并没有实战用过。后来大家都说 Koa 是一个比 Express 更牛X的东西,于是在好(作)奇(死)心作祟下,直接去用 Koa2 了。后来证明的确是作死,原本用 PHP 一天就能写完东西,愣是让我搞了三天。
安装
最近 Node.js V8 发布了,原生支持 async
和 await
调用了,所以直接把 Node.js 升级了一下。
根据 Koa2 的教程,安装很简单,我是使用的 yarn 的(还真是比 npm 快)。
yarn add koa
默认就装了 Koa 2.2。然后装完了,其实我是一脸懵逼的,文档上说这样用。
const Koa = require('koa')
const app = new Koa()
// response
app.use(ctx => {
ctx.body = 'Hello Koa'
})
app.listen(3000)
我照着代码写了下来,的确成功了。可是,难不成我要把所有的逻辑写在 app.use
里?
中间件
我感觉我受到了惊吓,吓得我赶紧往下看文档。原来 Koa2 是一个中间件模型。app.use
可以有很多,每一个 app.use
会注册一个中间件,这个中间件是具体做事情的。每个中间件是依次执行的。一个经典的洋葱图可以解释这一切。
那么,上面的实例就可以改造成这样。
app.use(async (ctx, next) => {
await next()
ctx.body = 'Hello Koa'
})
按照上面的洋葱头,以心为单位,next的两侧的语句分别在洋葱的左侧和右侧进行执行,颇像 Laravel
的中间件。
就这样,我知道了,所有的操作不必写在同一个 app.use
里。可是,下一个问题来了,我要把所有的逻辑都写再一个文件里?说好的 MVC 呢?没有 MVC 也叫做框架?Are you kidding me?(好吧后来发现原来 Koa2 并不是一个装置做网站的框架)
既然没有 MVC,那就自己动手丰衣足食吧。
路由
首先要处理的就是路由的问题。不过,由于是第一次用这货写项目,时间紧,(伪)任务重,看了文档后发现,原来还有一个中间件列表的链接,里面有各种开源的中间件。我想你们一定隔着屏幕都能听到我发出杠铃般的笑声了。有一个中间件非常棒,叫做 koa-router。这货是这么用的。
var Koa = require('koa')
var Router = require('koa-router')
var app = new Koa()
var router = new Router()
router.get('/', function (ctx, next) {
// ctx.router available
});
app.use(router.routes())
虽然是把逻辑和 app.use
分开了,但是,好像还是没有解决刚才的问题。说好的 MVC 也没有出现。于是我再去找了找,居然没有 Controller
的中间件。我一下就懵逼了,玩脱了?还有一天啊我的宝贝儿。经过我半秒钟的慎重思考,我还是用 koa-router
自己实现一个控制器吧。
Controller
const fs = require('fs')
function addRoutes(router, routes) {
for (let route in routes) {
switch (route.method) {
case: 'post':
router.post(route.uri, route.fn)
console.log(`Register post url: ${route.uri}`)
break
case: 'get':
router.get(route.uri, route.fn)
console.log(`Register get url: ${route.uri}`)
break
default:
console.log(`Invalid url: ${route}`)
}
}
}
function addControllers(router) {
let files = fs.readdirSync(__dirname + '/controllers')
let controllerFiles = files.filter(f => {
return f.endsWith('.js')
})
for (let controllerFile in controllerFiles) {
console.log(`process controller: ${controllerFile}...`)
let routes = require(__dirname + '/controllers')
addRoutes(router, routes)
}
}
module.exports = () => {
let router = require('koa-router')()
addControllers(router)
return router.routes()
}
我通过在 controllers
文件夹中,创建若干 js
文件来作为 Controller
来使用。这里稍微参考了下 廖雪峰的文章。
然后,我们只需要在 controllers
文件夹中添加合适的文件就可以了。例如我们添加一个文件叫做 chart.js
,然后这样写代码。
let hello = async (ctx, next) => {
ctx.body = 'Hello the fucking world!'
}
module.exports = [
{
method: 'get',
uri: 'hello',
fn: hello,
}
]
最后再在 app.js
注册中间件即可。
除此之外,我们还需要能够处理 ctx
里的内容,因为它里面存储的是原始的内容。还是由于时间紧,任(填)务(坑)重(急),我用了 koa-bodyparser。
const bodyParser = require('koa-bodyparser')
app.use(bodyParser())
这里要提醒的是,这货一定要放在处理路由中间件的前面。
Model
MVC
的 C
已经解决了,接下来就要解决 M
的问题了。这里我用的是 Sequelize。这个 ORM
和大多数的 ORM
都差不多,所以在这里这次没有踩到什么坑。我在根目录下新建了一个 config.js
的配置文件,然后新建了 model.js
用来定义模型。
const Sequelize = require('sequelize')
const config = require('./config').databases
...
module.exports = {
//models
}
View
视图,我是使用了一个中间件叫做 koa-view。由于它使用的是 Nunjucks 模板引擎,对于写 PHP
的我相对熟悉一点。
const view = require('koa-view')
const app = Koa()
app.use(view(__dirname + '/views'))
//controller
let Hello = (ctx, next) => {
ctx.render('hello', datas)
}
只要在 'views' 文件夹中定义相对应的 html 文件即可。
后记
这次的尝试,终于在我的修修补补中,搞出了一个简陋的 MVC
模型。赶在了 deadline 前完成,真是一波三折啊。学习新技术,就是这样,要实践嘛= =下面给出我的项目目录作参考
koa2/
|
+- controllers/
| |
| +- chart.js
| ...
|
+- static/
| |
| +- js/
| ...
| |
| +- style/
| |
| +- img
| ...
|
+- views/
| |
| +- game.html
| ...
|
+- app.js
|
+- config.js
|
+- controller.js
|
+- model.js
|
+- package.json
|
+- yarn.lock
|
+- node_modules/
菜鸟作品,如有错误请指正,不胜感激。
如果你喜欢我的文章,那就请我喝杯奶茶吧~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。