などを見て、軽いのいいなーと思って試してみました。
が、使うのは簡単だったのですけれどいろいろつまずいたので、それも含めたメモなどを。
インストール
- grunt
- grunt-contrib-conenct
- grunt-este-watch
をインストールします。ついでに
- grunt-contrib-jade
- grunt-contrib-stylus
をインストールしてJadeとStylusのファイルを自動でコンパイル・LiveReloadしてみます。
$ npm install grunt grunt-contrib-jade grunt-contrib-stylus \
> grunt-contrib-connect grunt-este-watch
Gruntfile
Gruntfile
を以下のように書きます。
module.exports = (grunt) ->
grunt.initConfig
connect:
server:
options:
# LiveReloadに必要なスクリプトを</body>直前に挿入してくれる
# 多分grunt-contrib-connect ver.0.4.0から
# HTML5などでbodyタグを書いていないと挿入してくれないみたい……
livereload: true
esteWatch:
options:
# 監視対象のディレクトリ
# ['./**']などとするとサブディレクトリを含むようになる
dirs: ['.']
livereload:
enabled: true
# 監視対象とするファイルの拡張子
extensions: ['jade', 'styl', 'stylus']
port: 35729
# *.jadeのハンドラ
jade: (filepath) ->
# お好みでタスクのオプションなどを設定をする
grunt.config 'jade.options.pretty', true
# 更新されたファイルだけコンパイルするように指定する
grunt.config 'jade.compile.files', [
expand: true
ext: '.html'
src: filepath
]
# 実行するタスク名を返す
# 複数実行する場合は['jade', 'stylus']のように配列で返す
'jade'
# *.stylのハンドラ
styl: '<%= esteWatch.stylus %>'
# *.stylusのハンドラ
stylus: (filepath) ->
grunt.config 'stylus.options.compress', false
grunt.config 'stylus.compile.files', [
expand: true
ext: '.css'
src: filepath
]
'stylus'
grunt.loadNpmTasks 'grunt-contrib-connect'
grunt.loadNpmTasks 'grunt-contrib-jade'
grunt.loadNpmTasks 'grunt-contrib-stylus'
grunt.loadNpmTasks 'grunt-este-watch'
grunt.registerTask 'default', ['connect', 'esteWatch']
return
二重拡張子の場合
二重拡張子のファイルをコンパイルする(grunt-contrib-coffeeで.coffee.md
をコンパイルするなど)際に、
esteWatch:
options:
livereload:
extensions: ['coffee.md']
と書いても反応しない模様…… なので
esteWatch:
options:
livereload:
extensions: ['md']
# ...
md: (filepath) ->
# 拡張子が.coffee.mdでなかったらタスクを実行しない
return unless /\.coffee\.md$/.test filepath
grunt.config 'coffee.options.bare', true
grunt.config 'coffee.compile.files', [
expand: true
ext: '.js'
src: filepath
]
'coffee'
などど書くと良いのではないかなーと。
実行
あとはgrunt
コマンドを実行して、
$ grunt
localhost:8000
にブラウザでアクセスしたあとに、.jade
や.styl
や.stylus
のファイルを更新すればLiveReloadで快適なコーディングが出来ると思います。面倒だなー、ただJade, Stylus/Less, CoffeeScriptのコンパイルとLiveReloadしたいんだけど、というときはgenerator-prototypingを使うとラクチンです。(宣伝)
つまずいたところ
grunt-este-watchを使っていてつまずいたところなど。
お気に入りのテキストエディタで保存しても更新が検知されない
監視対象となっているファイルに対してtouch
やecho
などを使うと更新が検知され、LiveReloadで再読み込みされるが、テキストエディタで保存するとなぜか最初の1回目以降は更新が検知されない、という問題に直面したりしました。
SublimeText2の場合は設定ファイルのatomic_save
をfalse
にすると良いみたいです。
https://github.com/steida/grunt-este-watch/#note-about-editors-atomic-save
MacVimの場合は
set nobackup
set nowritebackup
で良いみたいです。
どうもテキストエディタが素直にファイルに対して上書き保存しているわけではないようで、別のファイル名で保存したあとに元のファイル名にリネームしていることにより発生しているようです。(たぶん)これをatomic saveというのかな?
これによりgrunt-este-watchが内部的に使用しているfs.watch
のevent
がchange
でなくrename
になり、それ以降検知されないのではないかなーと。
以下は調べた方法など。
require('fs').watch(process.argv[2], function(event, filename) {
console.log(Date.now(), arguments);
});
$ touch temp.txt
$ node watch.js temp.txt
1384501599596 { '0': 'change', '1': null }
1384501600478 { '0': 'change', '1': null }
1384501601110 { '0': 'change', '1': null }
# ここまで $ touch temp.txt
1384501604980 { '0': 'change', '1': null }
1384501606445 { '0': 'change', '1': null }
1384501607053 { '0': 'change', '1': null }
# ここまで $ echo > temp.txt
1384501612293 { '0': 'rename', '1': null }
1384501612295 { '0': 'rename', '1': null }
# ここまでMacVimで:wしたもの、以降反応なし
ただ、Mac OS X Snow Leopard + MacVim, OS X Mountain Lion + MacVimでは上記の設定をしないと更新が検知されないのだけど、OS X Marverics + MacVimだと設定をしなくてもちゃんと動作してくれています。謎だ……
監視ファイル数の上限
grunt-este-watchで監視するファイル数がファイルディスクリプタの最大値より多くなると、esteWatch
のタスクが失敗し、監視ができずにタスクが失敗します。grunt-contrib-watchでは発生しなかったと思います。
解決策としては、なんとか監視対象とするファイルを減らすか、ファイルディスクリプタの上限を変更するか、でしょうか。
ちなみにOS Xのデフォルト値は
$ ulimit -n
256
でした。