diff --git a/Readme.md b/Readme.md index e1cd7e979..5d2c2dfed 100644 --- a/Readme.md +++ b/Readme.md @@ -44,11 +44,11 @@ app.listen(3000); ## Middleware + Koa is a middleware framework that can take 3 different kinds of functions as middleware: * common function * async function - * generator function Here is an example of logger middleware with each of the different functions: @@ -78,69 +78,46 @@ app.use((ctx, next) => { }); ``` -### GeneratorFunction - -To use generator functions, you must use a wrapper such as [co](https://github.com/tj/co) that is no longer supplied with Koa. - -```js -app.use(co.wrap(function *(ctx, next) { - const start = new Date(); - yield next(); - const ms = new Date() - start; - console.log(`${ctx.method} ${ctx.url} - ${ms}ms`); -})); -``` - -### Old signature middleware (v1.x) - Deprecated - -**Old signature middleware (v1.x) support will be removed in v3** - -Koa v2.x will try to convert legacy signature, generator middleware on `app.use`, using [koa-convert](https://github.com/koajs/convert). -It is however recommended that you choose to migrate all v1.x middleware as soon as possible. - -```js -// Koa will convert -app.use(function *(next) { - const start = new Date(); - yield next; - const ms = new Date() - start; - console.log(`${this.method} ${this.url} - ${ms}ms`); -}); -``` +### Koa v1.x Middleware Signature -You could do it manually as well, in which case Koa will not convert. +The middleware signature changed between v1.x and v2.x. The older signature is deprecated. -```js -const convert = require('koa-convert'); +**Old signature middleware support will be removed in v3** -app.use(convert(function *(next) { - const start = new Date(); - yield next; - const ms = new Date() - start; - console.log(`${this.method} ${this.url} - ${ms}ms`); -})); -``` +Please see the [Migration Guide](docs/migration.md) for more information on upgrading from v1.x and +using v1.x middleware with v2.x. ## Babel setup -For Node 4.0+ and Babel 6.0 you can setup like this: +If you're not using `node v7.6+`, we recommend setting up `babel` with [`babel-preset-env`](https://github.com/babel/babel-preset-env): ```bash -$ npm install babel-register babel-plugin-transform-async-to-generator --save +$ npm install babel-register babel-preset-env --save ``` +Setup `babel-register` in your entry file: + ```js -// set babel in entry file -require('babel-register')({ - plugins: ['transform-async-to-generator'] -}); +require('babel-register'); ``` -Check out an example in koa's [test](test/babel/index.js). +And have your `.babelrc` setup: + +```json +{ + "presets": [ + ["env", { + "targets": { + "node": true + } + }] + ] +} +``` ## Troubleshooting -Check the [Troubleshooting Guide](docs/troubleshooting.md) or [Debugging Koa](docs/guide.md#debugging-koa) in +Check the [Troubleshooting Guide](docs/troubleshooting.md) or [Debugging Koa](docs/guide.md#debugging-koa) in the general Koa guide. ## Running tests diff --git a/docs/migration.md b/docs/migration.md new file mode 100644 index 000000000..52625b4f9 --- /dev/null +++ b/docs/migration.md @@ -0,0 +1,133 @@ +# Migrating from Koa v1.x to v2.x + +## New middleware signature + +Koa v2 introduces a new signature for middleware. + +**Old signature middleware (v1.x) support will be removed in v3** + +The new middleware signature is: + +```js +// uses async arrow functions +app.use(async (ctx, next) => { + try { + await next() // next is now a function + } catch (err) { + ctx.body = { message: err.message } + ctx.status = err.status || 500 + } +}) + +app.use(async ctx => { + const user = await User.getById(this.session.userid) // await instead of yield + ctx.body = user // ctx instead of this +}) +``` + +You don't have to use asynchronous functions - you just have to pass a function that returns a promise. +A regular function that returns a promise works too! + +The signature has changed to pass `Context` via an explicit parameter, `ctx` above, instead of via +`this`. The context passing change makes koa more compatible with es6 arrow functions, which capture `this`. + +## Using v1.x Middleware in v2.x + +Koa v2.x will try to convert legacy signature, generator middleware on `app.use`, using [koa-convert](https://github.com/koajs/convert). +It is however recommended that you choose to migrate all v1.x middleware as soon as possible. + +```js +// Koa will convert +app.use(function *(next) { + const start = new Date(); + yield next; + const ms = new Date() - start; + console.log(`${this.method} ${this.url} - ${ms}ms`); +}); +``` + +You could do it manually as well, in which case Koa will not convert. + +```js +const convert = require('koa-convert'); + +app.use(convert(function *(next) { + const start = new Date(); + yield next; + const ms = new Date() - start; + console.log(`${this.method} ${this.url} - ${ms}ms`); +})); +``` + +## Upgrading middleware + +You will have to convert your generators to async functions with the new middleware signature: + +```js +app.use(async ctx => { + const user = await Users.getById(this.session.user_id); + await next(); + ctx.body = { message: 'some message' }; +}) +``` + +Upgrading your middleware may require some work. One migration path is to update them one-by-one. + +1. Wrap all your current middleware in `koa-convert` +2. Test +3. `npm outdated` to see which koa middleware is outdated +4. Update one outdated middleware, remove using `koa-convert` +5. Test +6. Repeat steps 3-5 until you're done + + +## Updating your code + +You should start refactoring your code now to ease migrating to Koa v2: + +- Return promises everywhere! +- Do not use `yield*` +- Do not use `yield {}` or `yield []`. + - Convert `yield []` into `yield Promise.all([])` + - Convert `yield {}` into `yield Bluebird.props({})` + +You could also refactor your logic outside of Koa middleware functions. Create functions like +`function* someLogic(ctx) {}` and call it in your middleware as +`const result = yield someLogic(this)`. +Not using `this` will help migrations to the new middleware signature, which does not use `this`. + +## Application object constructor requires new + +In v1.x, the Application constructor function could be called directly, without `new` to +instantiate an instance of an application. For example: + +```js +var koa = require('koa'); +var app = module.exports = koa(); +``` + +v2.x uses es6 classes which require the `new` keyword to be used. + +```js +var koa = require('koa'); +var app = module.exports = new koa(); +``` + +## ENV specific logging behavior removed + +An explicit check for the `test` environment was removed from error handling. + +## Dependency changes + +- [co](https://github.com/tj/co) is no longer bundled with Koa. Require or import it directly. +- [composition](https://github.com/thenables/composition) is no longer used and deprecated. + +## v1.x support + +The v1.x branch is still supported but should not receive feature updates. Except for this migration +guide, documentation will target the latest version. + +## Help out + +If you encounter migration related issues not covered by this migration guide, please consider +submitting a documentation pull request. diff --git a/lib/application.js b/lib/application.js index ec30cdc2b..4c4dab414 100644 --- a/lib/application.js +++ b/lib/application.js @@ -107,8 +107,7 @@ module.exports = class Application extends Emitter { if (isGeneratorFunction(fn)) { deprecate('Support for generators will be removed in v3. ' + 'See the documentation for examples of how to convert old middleware ' + - 'https://github.com/koajs/koa/blob/master/Readme.md' + - '#old-signature-middleware-v1x---deprecated'); + 'https://github.com/koajs/koa/blob/master/docs/migration.md'); fn = convert(fn); } debug('use %s', fn._name || fn.name || '-');