Edited at
Node.jsDay 17

Koa v1からv2へのアップデート

More than 1 year has passed since last update.

Koa v1.2.1で書かれたアプリケーションをKoa v2.0.0にアップデートしたのでそのログ的なものです。

v1からの大きな変更点として、middlewareのインターフェースがgenerator functionからasync/awaitへと変わっています。


環境の用意

Koa v2ではasync/awaitが使える環境が必要となります。現状Node.jsでasync/awaitを使うためには主に


  • Node.js v7系を使い --harmony-async-await オプションをつけて起動

  • Babelでトランスパイル&polyfill

という二種類の方法がありますが、ここでは後者のBabelを使う方法で進めていきます。


pluginとpolyfillのインストール

$ npm install babel-polyfill babel-plugin-transform-async-to-generator


既にクライアント側でBabelを使用していて、presetやpluginsの設定を分けたい場合はenvを設定します。


.babelrc

{

"env": {
"client": {
"presets": [ "es2015", "react" ],
"plugins": [
"add-module-exports",
"transform-class-properties",
"transform-object-rest-spread",
"transform-export-extensions"
]
},
"server": {
"presets": [ "es2015" ],
"plugins": [
"transform-async-to-generator"
]
}
}
}

BABEL_ENVを指定した上でbabel-nodeを使って動かします。


scriptsに追加

"start": "BABEL_ENV=server babel-node index.js"


なおパフォーマンスなどの問題から、productionではbabel-nodeではなくフロントのコード同様トランスパイルしたものを使用することが推奨されています。

babel/example-node-server


production用にトランスパイル

"build": "BABEL_ENV=server babel index.js --out-file bundle.js",

"start:production": "node bundle.js"


Koa v2のインストール

$ npm i koa@2

v2ではクラスコンストラクタを返すようになったので対応します。


before

import koa from 'koa';

const app = koa();


after

import Koa from 'koa';

const app = new Koa();


migration


generator -> async/await or Promise

generator functionをasync/awaitに書き換えていきます。


before

app.use(function *(next) {

try {
yield next;
} catch (err) {
if (401 == err.status) {
this.status = 401;
this.set('WWW-Authenticate', 'Basic');
this.body = 'authorization required';
} else {
this.throw(err);
}
}
});


async/await

app.use(async (ctx, next) => {

try {
await next;
} catch (err) {
if (401 == err.status) {
ctx.status = 401;
ctx.set('WWW-Authenticate', 'Basic');
ctx.body = 'authorization required';
} else {
ctx.throw(err);
}
}
});

あるいはPromiseで書くこともできます。


promise

app.use((ctx, next) => {

next().catch((err) => {
if (401 == err.status) {
ctx.status = 401;
ctx.set('WWW-Authenticate', 'Basic');
ctx.body = 'authorization required';
} else {
ctx.throw(err);
}
});
});


koa-convert

未対応のmiddlewareは、koa-convertを使ってgenerator functionをPromiseを使用したものに変換することができます。


before

import logger from 'koa-logger';

import serve from 'koa-static';

app.use(logger());
app.use(serve('.'));



after

import logger from 'koa-logger';

import serve from 'koa-static';
import convert from 'koa-convert';

app.use(convert(logger()));
app.use(convert(serve('.')));



さいごに

とりあえずconvertで囲ってしまえばどうにかなるのは楽でいいですね。

async/awaitのためだけにサーバーサイドでBabelを使用するのは、ビルドプロセスも複雑になるし正直あまり筋のいい方法とは言えないのでNode.js v7入れられるならそちらの方が良いでしょう。

ちなみにKoa v2の正式リリースはNode.js上でstableなasync/awaitが実装されたらとのことなので、Node.js v8が出る頃には出そうですね:smiley:


FYI: フレームワークDL数比較

Koaよりhapi,restifyの方が多いようです。。。1

last month(2016/12/17)

express
7,942,528

restify
258,329

hapi
246,358

Koa
156,030

sails
67,201

Trails
10,423

Node.js Advent Calendar 2016 17日目の記事でした。





  1. Meteorはnpmで入らないためDL数判らず