Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create v2 Migration document #920

Closed
wants to merge 12 commits into from
33 changes: 6 additions & 27 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ 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.
To use generator functions, you must use a wrapper such as [co](https://github.com/tj/co).
Copy link
Member

@jonathanong jonathanong Feb 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we should just remove this section as it would only confuse people

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it was weak, but didn't know if the unbundling of co mattered. Seems not. Removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, wait! I completely misread this. My mistake. I thought you were referring to the dependency section in the migration page which is where I moved the "no longer supplied text" to.

@jonathanong When you refer to "this section" are you referring to the "GeneratorFunction" section?

Should I add back the dependency section I just removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After thinking about it, I agree. The overview document should focus on the recommended way, which I think now is async and leave the other two formats for deeper documentation. I'd like to submit that as a separate PR, though, so as to not block the merging of this migration guide.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went ahead and restored the Dependency changes section I mistakenly removed. I don't know if its meaningful, I'm not actually a v1.x user, I was attracted by the v2.x release.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup, I meant the GeneratorFunction section. we shouldn't be recommending people to use generator functions, and if they do, it should be the v1.x version that should be migrated to async functions. this is a generation function with (ctx, next) arguments, which is a mix of v1.x and v2.x APIs and is awkward


```js
app.use(co.wrap(function *(ctx, next) {
Expand All @@ -91,35 +91,14 @@ app.use(co.wrap(function *(ctx, next) {
}));
```

### Old signature middleware (v1.x) - Deprecated
### Koa v1.x Middleware Signature

**Old signature middleware (v1.x) support will be removed in v3**
The middleware signature changed between v1.x and v2.x. The older signature is deprecated.

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.
**Old signature middleware support will be removed in v3**

```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`);
}));
```
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

Expand Down
133 changes: 133 additions & 0 deletions docs/migration.md
Original file line number Diff line number Diff line change
@@ -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:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would show next() in the signature

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Fixed.


```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.
3 changes: 1 addition & 2 deletions lib/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 || '-');
Expand Down