世界上最伟大的投资就是投资自己的教育

全场限时 5 折

首页JavaScript
随风 · 练气

koa2 开发实践指南

随风发布于6772 次阅读

1. 介绍

最近用 koa2 来开发应用,把自己的经验记录一下。

介绍 koa 的文章,请查看es6 的 generator 和 nodejs 的下一代框架 koa这篇文章。

2. n 版本管理器

首先使用最新版本的 nodejs。

我使用n来管理 nodejs 的版本,也用 n 来安装比较新的 nodejs。

3. 用 db-migrate 来管理数据库迁移

我想像 rails 那样来管理 migration,只有db-migrate才比较好用。

具体可以查看这篇文章node-db-migrate 入门教程

4. 用 bookshelf 来作为数据库的 orm

数据库我使用 postgresql,而bookshelf才比较像 rails 的 active_record。

const knex = require('knex')({
  client: 'pg',
  searchPath: 'public',
  connection: {
    host : '127.0.0.1',
    user : 'hfpp2012',
    password : '',
    database : 'tspd_dev'
  }
});

const bookshelf = require('bookshelf')(knex);

const Repo = bookshelf.Model.extend({
  tableName: 'regional_designs'
});

const Koa = require('koa');
const app = new Koa();

// 路由
const Router = require('koa-router');
const router = new Router({
  prefix: '/api'
});

// promise写法
router.get('/', function (ctx, next) {
  // new Repo({name: 'New Article', created_at: '2016-11-01T03:30:48.351Z', updated_at: '2016-11-01T03:30:48.351Z'}).save().then(function(model) {
  // });
  return Repo.where('id', 1).fetch().then((json) => {
    ctx.body = json;
  })
});

5. koa-views 结合 nunjucks 作为模版引擎

koa-views作为 koa 的插件,支持 koa2,它能够支持绝大多数 nodejs 的模版引擎,而我喜欢用 nunjucks 作模版引擎。

类似这样:

var views = require('koa-views');

// Must be used before any router is used
app.use(views(__dirname + '/views', {
  map: {
    njk: 'nunjucks',
    html: 'ejs'
  }
}));

router.get('/views', function (ctx, next) {
  // return next().then(() => {
  //   ctx.render('basic.ejs')
  // })
  ctx.state = {
    session: this.session,
    title: 'app',
    username: 'hfpp2012'
  };
  // return ctx.render('basic.html')
  return ctx.render('test.njk')
});

test.njk文件内容为:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
{% block header %}
This is the default content
{% endblock %}

<section class="left">
  {% block left %}{% endblock %}
</section>

<section class="right">
  {% block right %}
  This is more content
  {% endblock %}
</section>
</body>
</html>

6. 开发环境使用 nodemon 作为启动服务

nodemon可以修改完文件之后自动重启服务。

安装

npm install -g nodemon

7. 使用 koa-logger 来记录日志

koa 默认没啥日志,[koa-logger] 又支持 koa2,所以用它来显示日志。

// 日志
const logger = require('koa-logger');
app.use(logger());

8. 用 koa-router 来作为路由控件

写一个应用,总要暴露路由给人用。koa-router支持 koa2,又比较好用。

// 路由
const Router = require('koa-router');
const router = new Router({
  prefix: '/api'
});

router.post('/regional_design/repos.json', function (ctx, next) {
  let json = {"id":11,"name":"新的药库","pos_x":null,"pos_y":null,"parent_id":null,"drug_id":null,"created_at":"2016-12-23T03:16:58.728Z","updated_at":"2016-12-23T03:16:58.728Z"};
  ctx.body = json;
});

router.get("/regional_design/repos/:id(\\d+).json", function (ctx, next) {
  let json = {"name":"西药库","type":"RegionalDesign::Repo","children_object_type":"drug_repo","children":[{"id":5,"name":"药库","initialPos":{"x":73,"y":54}},{"id":6,"name":"药库","initialPos":{"x":276,"y":120}}]};
  ctx.body = json;
});

9. 使用 koa-send 发送静态文件

有时候需要直接提供 html 文件,或 js css 静态文件,在生产环境下可能可以直接使用 nginx 来读取,但是在开发环境下也可以用koa-send跟生产环境下保持一致。

var send = require('koa-send');

app.use(async function (ctx, next){
  await send(ctx, ctx.path, { root: __dirname + '/public' });
})

10. koa2 的三种函数写法

第一种是最常见的写法,使用 promise。

// promise写法
router.get('/', function (ctx, next) {
  // new Repo({name: 'New Article', created_at: '2016-11-01T03:30:48.351Z', updated_at: '2016-11-01T03:30:48.351Z'}).save().then(function(model) {
  // });
  return Repo.where('id', 1).fetch().then((json) => {
    ctx.body = json;
  })
});

第二种使用 co 库的写法:

// co写法
const co = require('co');

router.get('/', co.wrap(function *(ctx, next) {
  ctx.body = yield Repo.where('id', 1).fetch();
}));

第三种:async/await 写法

router.get('/', async (ctx, next) => {
  ctx.body = await Repo.where('id', 1).fetch();
});

最后一种写法需要用 babel 来转化源码,转成 node 可以读取的代码。

使用babel-plugin-transform-async-to-generator这个插件就可以转化。

// .babelrc
{
  "plugins": ["transform-async-to-generator"]
}
// package.json
"scripts": {
    "start": "nodemon index.js",
    "build": "babel index.js --out-file main.js",
    "babel-start": "nodemon --exec babel-node index.js"
  },

11. 使用 shipit 和 pm2 来部署应用

shipit是全自动化部署脚本,有点类似于 ruby 的capistrano,使用它,以后只要一行命令就可以自动完成部署。

在生产环境下使用pm2来管理 nodejs 的进程。

部署脚本示例:

// shipitfile.js
module.exports = function (shipit) {
  require('shipit-deploy')(shipit);
  require('shipit-npm')(shipit);
  require('shipit-shared')(shipit);
  // require('shipit-db')(shipit);
  // require('shipit-assets')(shipit);

  shipit.initConfig({
    default: {
      workspace: './.deploy_build',
      deployTo: '/home/hfpp2012/koa-app-start',
      repositoryUrl: 'git@git.oschina.net:hfpp2012/koa-app-start.git',
      branch: 'master',
      ignores: ['.git', 'node_modules'],
      rsync: ['--del'],
      keepReleases: 2,
      shallowClone: true,
      shared: {
        overwrite: true,
        dirs: ['public/uploads'],
        files: ['database.json',
          {
            path: 'database.json',
            overwrite: false,
            chmod: '755',
          }
        ]
      }
    },
    production: {
      servers: 'hfpp2012@koa.rails365.net'
    }
  });

  shipit.task('install-db-migrate', function () {
    return shipit.remote('sudo npm install -g db-migrate');
  });

  shipit.task('db-migrate', function () {
    return shipit.remote('cd /home/hfpp2012/koa-app-start/current && db-migrate up -e prod');
  });

  shipit.on("published", function(){
    shipit.start("db-migrate");
  });

  require('shipit-pm2')(shipit);

  // shipit.task('pm2', function () {
  //   return shipit.remote('cd /home/hfpp2012/koa-app-start/current && pm2 startOrRestart ./app.json --env production');
  // });
};

以后可以使用一行命令来部署:

shipit production deploy

参考资料:使用 Shipit+Gulp+PM2+Nginx 自动部署 Nodejs 应用

nginx 配置示例如下:

upstream my_nodejs_upstream {
    server 127.0.0.1:3001;
    keepalive 64;
}

server {
    listen 80;
    server_name koa.rails365.net;
    root /home/hfpp2012/koa-app-start/current/public;

    try_files $uri/index.html $uri @koa;
    location @koa {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_max_temp_file_size 0;
        proxy_pass http://my_nodejs_upstream;
        proxy_redirect off;
        proxy_read_timeout 240s;
    }
}

参考链接:

完结。

本站文章均为原创内容,如需转载请注明出处,谢谢。

0 条回复
暂无回复~~
喜欢
统计信息
    学员: 29061
    视频数量: 1973
    文章数量: 489

© 汕尾市求知科技有限公司 | Rails365 Gitlab | Qiuzhi99 Gitlab | 知乎 | b 站 | 搜索

粤公网安备 44152102000088号粤公网安备 44152102000088号 | 粤ICP备19038915号

Top