一个 PHPer 第一次用 Koa2 写 Node.js 的心路历程

学了一段时间的 js 了,忽然想实践一下。正好公司有个小的项目要作,就顺手拿 Koa2 来作了。真是不作不知道,作了想不到。踩了一堆新手坑。javascript

初次接触 Koa2

在知道 Koa2 以前,我也了解过 Express,惋惜并无实战用过。后来你们都说 Koa 是一个比 Express 更牛X的东西,因而在好(做)奇(死)心做祟下,直接去用 Koa2 了。后来证实的确是做死,本来用 PHP 一天就能写完东西,愣是让我搞了三天。html

安装

最近 Node.js V8 发布了,原生支持 asyncawait 调用了,因此直接把 Node.js 升级了一下。java

根据 Koa2 的教程,安装很简单,我是使用的 yarn 的(还真是比 npm 快)。node

yarn add koa

默认就装了 Koa 2.2。而后装完了,其实我是一脸懵逼的,文档上说这样用。git

const Koa = require('koa')
const app = new Koa()
 
// response 
app.use(ctx => {
  ctx.body = 'Hello Koa'
})
 
app.listen(3000)

我照着代码写了下来,的确成功了。但是,难不成我要把全部的逻辑写在 app.use 里?github

a

中间件

我感受我受到了惊吓,吓得我赶忙往下看文档。原来 Koa2 是一个中间件模型。app.use 能够有不少,每个 app.use 会注册一个中间件,这个中间件是具体作事情的。每一个中间件是依次执行的。一个经典的洋葱图能够解释这一切。npm

那么,上面的实例就能够改形成这样。json

app.use(async (ctx, next) => {
  await next()
  ctx.body = 'Hello Koa'
})

按照上面的洋葱头,以心为单位,next的两侧的语句分别在洋葱的左侧和右侧进行执行,颇像 Laravel 的中间件。bash

就这样,我知道了,全部的操做没必要写在同一个 app.use 里。但是,下一个问题来了,我要把全部的逻辑都写再一个文件里?说好的 MVC 呢?没有 MVC 也叫作框架?Are you kidding me?(好吧后来发现原来 Koa2 并非一个装置作网站的框架)app

既然没有 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

MVCC 已经解决了,接下来就要解决 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/

菜鸟做品,若有错误请指正,不胜感激。

若是你喜欢个人文章,那就请我喝杯奶茶吧~

相关文章
相关标签/搜索