10
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

概要

弊社では一部の社内プロジェクトでSails.jsを利用しています。その中で得られたベストプラクティスやらバッドプラクティスをまとめていこうと思います。
第1回はバックエンド側のAltJSの活用から。

動作環境

  • node.js v0.12.7
  • Sails.js v0.11.2
  • [npm]sails-hook-babel v5.0.1
  • [npm]typescript v1.5.3
  • [npm]grunt-tsconfig-update v0.0.1

AltJSの活用

Sails.jsはnode.jsのフレームワークなので実際の開発ではAltJSを使用しています。TypeScriptで書いたコードを --target es6 に変換後、babel でES5に変換しています。

TypeScript

採用理由

個人的にTypeScriptが好きなのでバックエンド側コードは全面的にTypeScriptを採用しています。TypeScriptを導入するメリットは大きいと考えていて、モジュール間の整合性を厳密に定義出来る点が気に入っています。次回以降でアーキテクチャについては詳しく説明しますが、弊社ではViewController -> ApiController -> Service -> Modelという4層構造でバックエンドを構築しています。各層のAPIを変更したときに、デグレが発生していないかをコンパイル段階で気付けるのは良いですね。

設定方法

$ npm i typescript grunt-tsconfig-update grunt-shell --save-dev

Sails.jsにはGruntが組み込まれているのでこれを活用することにします。とは言えあまり依存したくもないので、tsconfig.jsonを出力するだけのモジュール grunt-tsconfig-update と、 grunt-shell で直接tscを叩く構成にしています。今見ると改善したくなってきた。。

tasks/config/tsconfig.js
module.exports = function(grunt) {
  grunt.config.set('tsconfig', {
    main: {}
  });

  grunt.loadNpmTasks('grunt-tsconfig-update');
};
tasks/config/shell.js
module.exports = function(grunt) {
  grunt.config.set('shell', {
    typescript: {
      command: "npm run ts"
    }
  });

  grunt.loadNpmTasks('grunt-shell');
};
tasks/register/buildServer.js
module.exports = function (grunt) {
  grunt.registerTask('build-server', [
    'tsconfig:main',
    'shell:typescript'
  ]);
};
package.json
  "scripts": {
    "ts": "./node_modules/typescript/bin/tsc -p ./"
  }

あとはtsconfigを用意して終わりです。

tsconfig.json
{
  "compileOnSave": false,
  "compilerOptions": {
    "target": "es6",
    "declaration": false,
    "sourceMap": false,
    "removeComments": true,
    "noLib": false,
    "preserveConstEnums": false,
    "moduleResolution": "node"
  },
  "filesGlob": [
    "./api/**/*.ts",
    "!./**/*.d.ts",
    "!./node_modules/"
  ],
  "files": [
  ]
}

コンパイル

$ grunt build-server

Babel

採用理由

最初に書いた通り、TypeScriptは--target es6で使っています。これはいつでもTypeScriptを捨てられるようにするためです。個人的にはずっとTypeScriptで書きたいのですが、書きたくない人に引き継ぐ可能性があるので。。

設定方法

sails-hook-babelというnpmを1つ入れるだけで終わりです。これでSails起動時に自動的にbabelで変換してくれます。ただ、このnpmは今のところbabel6対応をしていないため、長期メンテする予定のシステムでは使わない方が良いかもしれません。いつもどおり返還前のコードを置くディレクトリを用意して、普通にbabelを叩いてapi/*に出力するほうが良いのかも。

$ npm i sails-hook-babel --save

使用しているd.tsファイル

Sails用の型定義ファイルが無かったので自前で作って使っています。ただ公開出来るレベルでは書いていないので。。型定義ファイルにどれだけ作成コストをかけるのかというのは常に悩む。

sails.d.ts
/// <reference path="./typings/bundle.d.ts" />

declare var sails: Sails.sails;

declare module "sails" {
  import * as express from 'express';

  module s {
    interface Request extends express.Request {
      port: number;
      user: User;
      session: Session;
      sessionID: string;

      allParams(): Object;
      logout();
      file(name: String): any; // TODO file object
    }

    interface Response extends express.Response {
      ok(params: Object | number);
      view(view: string, params?: Object);
      json(params: Object);
    }

    interface Session {
      regenerate(callback: (error) => void);
    }

    interface User {
      id: number;
    }
  }

  export = s;
}

declare module Sails {

  interface sails {
    log: log;
  }

  interface log {
    verbose(...data: any[]);
    error(...data: any[]);
    warn(...data: any[]);
    debug(...data: any[]);
    info(...data: any[]);
    silly(...data: any[]);
  }
}

コードサンプル

実際のコードの抜粋です。雰囲気は伝わるかなと。

TagController.ts
/// <reference path="../../../sails.d.ts" />
/// <reference path="../../../typings/bundle.d.ts" />

import * as Sails from 'sails';

class TagController {
  'use strict';

  constructor() { }

  find(req: Sails.Request, res: Sails.Response) {
    sails.log.verbose('api::TagController#find');
    sails.log.verbose('params', req.allParams());
    sails.log.verbose(`user=${(req.user ? req.user.id : 'null') }`);

    const page = +req.param('page') || 1;

    TagService.find({
      limit: 30,
      page: page
    }).then((tags) => {

      res.ok(tags);

    }).catch((error) => {
      sails.log.error("api::TagController.find", error);
      res.send(500);
    });
  }
}

export default new TagController();

まとめ

TypeScript良いよね。

10
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?