細かすぎて伝わらない Sails.js v0.9.3 のtipsまとめ

Sails.jsは0.8系から0.9系にバージョンアップした際、仕様が大きく変わったので少しまとめてみました。

ちなみにSails.jsは もう v0.9.4のリリース終わって v0.9.7です。。。(2013/10/17現在)

grunt 依存

sails lift(node app.js) 実行時、内部的にgrunt を実行しています。
これはv0.9系の一番大きい変更であり、一番やっかいな仕様変更です。
これにより、grunt[default]を実行し、そこからSails(Express)でサーバを起動するタイプの処理(grunt-express-serverなど)が動作しません。

また、これに付随するのか node-supervisor での起動も出来ません。再起動を延々繰り返します。

(2014/4/1追記)
ignoreファイルを設定することで動作します

(2014/4/1追記終わり)

公式にはforever を使うことを推奨しているようです。

本番・非本番環境の切り替え

内部で実行されるgruntコマンドが、本番系と非本番系で切り替わります。
`sails.config.environment == "production"` であれば 本番環境と判定します。
`config.environment` はNODE_ENV設定を再優先し、次にsails.config で割り当てられた値を採用します。
(NODE_ENV指定例: NODE_ENV='production' sails lift など )

私の場合、以前のsails.jsの習慣から 「local.js が有るか無いか」 で本番・非本番の切り替えとしています。

/config/application.js ファイルを作成し、

 module.exports.environment = process.env.NODE_ENV || 'production'

と記述して次の関係としています。

local.js が存在しない場合
application.js の module.exports.environment ( = sails.config.environment ) が採用され、設定値 'production' を使用
local.js が存在する場合
application.js の module.exports.environment を上書きし、初期設定値の 'development'を使用

つまり

  • application.js << local.js <<<<<< NODE_ENV

の関係となります。

これにより 本番環境下では 必ず/config/local.js を除外(※)し、NODE_ENVの設定変更は行わなくて済むようにしています。

(※ gitignoreによる、git pull もしくは git server へのpush でのファイルデプロイが前提)

更に書くと 個人的には npm start が基本的な動作になるようになる。という個人的な統一性をもたせているというのもあります。

.tmp フォルダへのコンパイル出力

先程の項目で 本番と非本番でgrunt 実行コマンドが切り替わると書きました。

詳細はこのようになります。

sails.config.environment: 'development'
grunt [default]
assets フォルダファイルを .tmp フォルダに展開、また、less,coffeescript ファイルなどはコンパイルしたファイルを出力
grunt のconnect.static により、.tmp/public フォルダはドメイントップディレクトリとなります。
sails.config.environment: 'production'
grunt prod
.tmp フォルダへ出力されたファイルを minフォルダに concat,uglify展開(.tmp/min/production.js)

開発環境時(grunt[default])は圧縮などを行わず、処理時間を短縮しています。

圧縮ファイルへのパス参照問題

concat,uglify されたファイルを参照するために <style>や<script> のパスの変更するのが大きな手間となります。
(みなさんは他のフレームワークなどでどうされているか、少し気になるところでは有りますが)

sails.js ではこれを解消するために --linker オプションを用意しています。

--linkerオプション

初期フォルダ構成生成コマンド、sails new に --linker オプションを付与します。

すでにsails new でフォルダを生成してしまった場合でも移行は出来ますが、ここでは説明を省きます。

構成上の大きな違いは assetsフォルダに展開されたlinker フォルダと /view/layout.ejs へ出力されたファイル内の <!--SCRIPTS-->などのコメント群です。

linkerフォルダ内の js/styles/templates ファイルはそれぞれ js/css/jst-template の構成です。

開発時は、linker オプション無しでの動作とそう変わりません。

違うのは 本番(environment: 'production') 実行時です。

例えば、/assets/linker/js フォルダのファイルは、/.tmp/public/linker/js へコンパイル処理されたあと、/.tmp/min/production.js へ出力されます。

さらに(ここ重要)、/view/layout.ejs 内の <!--SCRIPTS--><!--SCRIPTS END-->で囲われている個所が自動で書き換えられます。

environment: 'development'
<!--SCRIPTS-->
<script src="/linker/js/socket.io.js"></script>
<script src="/linker/js/sails.io.js"></script>
<script src="/linker/js/app.js"></script>
<!--SCRIPTS END-->
environment: 'production'
<!--SCRIPTS-->
<script src="/min/production.js"></script>
<!--SCRIPTS END-->

css は、 <!--STYLES--><!--STYLES END--> で記述されたブロックが書き換えれれます。

grunt における sails-linker によって、 grunt ⇔ grunt prod(本番系・非本番系)でパスが自動的に変更される事になります。

ここで問題となるconcat による結合順序ですが、その設定は Gruntfile.js内で記述されています。
(ちなみにdevelopment時の呼び出し順も同様)

var cssFilesToInject = [
   'linker/**/*.css'
];

/**
* Javascript files to inject in order
* (uses Grunt-style wildcard/glob/splat expressions)
*
* To use client-side CoffeeScript, TypeScript, etc., edit the
* `sails-linker:devJs` task below for more options.
*/

var jsFilesToInject = [
  // Below, as a demonstration, you'll see the built-in dependencies
  // linked in the proper order order
  
  // Bring in the socket.io client
  'linker/js/socket.io.js',
  
  // then beef it up with some convenience logic for talking to Sails.js
  'linker/js/sails.io.js',
  
  // A simpler boilerplate library for getting you up and running w/ an
  // automatic listener for incoming messages from Socket.io.
  'linker/js/app.js',
  
  // *-<    put other dependencies here   >-*
  
  // All of the rest of your app scripts imported here
  'linker/**/*.js'
];

/**
 * Client-side HTML templates are injected using the sources below
 * The ordering of these templates shouldn't matter.
 * (uses Grunt-style wildcard/glob/splat expressions)
 *
 * By default, Sails uses JST templates and precompiles them into
 * functions for you.  If you want to use jade, handlebars, dust, etc.,
 * edit the relevant sections below.
 */

var templateFilesToInject = [
   'linker/**/*.html'
];

'/assets' フォルダ と '/assets/linker' の使い分けは、ライセンス付きでの使用が前提かどうかで良いと思っています。

'linker' 以下のファイルは、結合・圧縮され 'production.xx' へと出力されるので、単体での使用が望ましいものは 'assets' フォルダ直下で良いのではないでしょうか?

https 起動

v0.9.3 では sails.config.ssl で設定できませんでした

module.exports.express = {
  ssl: {
    key: require("fs").readFileSync( require("path").resolve( "ssl/server.key" )).toString(),
    cert: require("fs").readFileSync( require("path").resolve( "ssl/server.crt")).toString()
  }
}

どうやらsails.js側(express wrapper)で設定出来ず、express のserverOptionで直接設定するしかないようです。

(v0.9.4ではおそらく解決済み Issue #844 )

module.exports.express = {
   serverOptions:{
      key: require("fs").readFileSync( require("path").resolve( "ssl/server.key" )).toString(),
      cert: require("fs").readFileSync( require("path").resolve( "ssl/server.crt")).toString()
   }
}