osxにnodeでgulpなフロントエンド開発環境を作ってみる
「父ちゃん、js嫌いな俺だけどさ、nodeは使ってみたいんだよ」みたいな横浜銀蝿的な囁きが聞こえてくるぐらいにnodeを使ってみたくなったので、とりあえず定番的なnodeを使ったフロントエンドの開発環境を整えてみたいと思います。
node.jsのインストール
brewから一発。
~ 13:49:53 zow$ brew install node ==> Downloading https://homebrew.bintray.com/bottles/node-0.12.7.yosemite.bottle ######################################################################## 100.0% ==> Pouring node-0.12.7.yosemite.bottle.tar.gz ==> Caveats Bash completion has been installed to: /usr/local/etc/bash_completion.d ==> Summary 🍺 /usr/local/Cellar/node/0.12.7: 2726 files, 31M ~ 13:51:54 zow$
brewでnodeをインストールするとnpmも同時に入れてくれるらしい。npmってのはnodeで利用されているパッケージマネージャで、pythonで言うpipみたいなもんらしい。
gulpのインストール
gulpってのはなんて言えばいいんだろ。世間ではタスクランナーって呼ばれてるらしい。要するにタスクを実行してくれる。どっかのディレクトリを監視して、変化があったら何かを実行、みたいな使い方が出来るらしい。今回はフロントエンド開発環境を作る訳だけど、静的ファイル(html)が置いてあるディレクトリを監視して、変化があったらhttpサーバを再起動させる?みたいな使い方が出来るらしい。つまりhtmlファイルをガンガン書いて保存すると、自動でhttpサーバを起動してブラウザで変化を確認したり出来るようになる。いちいちリロードとかしなくていいみたいだ。emmetなんかでhtmlを書く様な人の場合結構重宝するだろう。
gulpはnpmコマンドでインストールする。
~ 14:03:30 zow$ npm install -g gulp /usr/local/bin/gulp -> /usr/local/lib/node_modules/gulp/bin/gulp.js gulp@3.9.0 /usr/local/lib/node_modules/gulp ├── pretty-hrtime@1.0.0 ├── interpret@0.6.4 ├── deprecated@0.0.1 ├── archy@1.0.0 ├── minimist@1.1.1 ├── tildify@1.1.0 (os-homedir@1.0.0) ├── v8flags@2.0.9 (user-home@1.1.1) ├── semver@4.3.6 ├── chalk@1.1.0 (escape-string-regexp@1.0.3, supports-color@2.0.0, ansi-styles@2.1.0, strip-ansi@3.0.0, has-ansi@2.0.0) ├── orchestrator@0.3.7 (sequencify@0.0.7, stream-consume@0.1.0, end-of-stream@0.1.5) ├── liftoff@2.1.0 (extend@2.0.1, rechoir@0.6.1, flagged-respawn@0.3.1, resolve@1.1.6, findup-sync@0.2.1) ├── gulp-util@3.0.6 (array-differ@1.0.0, array-uniq@1.0.2, beeper@1.1.0, lodash._reescape@3.0.0, lodash._reinterpolate@3.0.0, lodash._reevaluate@3.0.0, object-assign@3.0.0, replace-ext@0.0.1, vinyl@0.5.0, lodash.template@3.6.2, multipipe@0.1.2, through2@2.0.0, dateformat@1.0.11) └── vinyl-fs@0.3.13 (graceful-fs@3.0.8, strip-bom@1.0.0, defaults@1.0.2, vinyl@0.4.6, mkdirp@0.5.1, through2@0.6.5, glob-stream@3.1.18, glob-watcher@0.0.6) ~ 14:03:48 zow$
これで終わり。楽ちん。
gulpに監視させる
gulpのインストール(プロジェクトディレクトリ)
とりあえずなんか開発するとして、ホームディレクトリの配下に「work/gulp_test」を作成する。
~ 14:19:48 zow$ mkdir -p ~/work/gulp_test ~ 14:20:06 zow$ cd work/gulp_test/ gulp_test 14:20:45 zow$
ここを開発ディレクトリと想定してgulpを使ってみる。
まず、このプロジェクトディレクトリにgulpをインストールする。
gulp_test 14:22:34 zow$ npm install --save-dev gulp gulp@3.9.0 node_modules/gulp ├── pretty-hrtime@1.0.0 ├── interpret@0.6.4 ├── deprecated@0.0.1 ├── archy@1.0.0 ├── tildify@1.1.0 (os-homedir@1.0.0) ├── minimist@1.1.1 ├── v8flags@2.0.9 (user-home@1.1.1) ├── chalk@1.1.0 (supports-color@2.0.0, escape-string-regexp@1.0.3, ansi-styles@2.1.0, strip-ansi@3.0.0, has-ansi@2.0.0) ├── semver@4.3.6 ├── orchestrator@0.3.7 (stream-consume@0.1.0, sequencify@0.0.7, end-of-stream@0.1.5) ├── gulp-util@3.0.6 (array-differ@1.0.0, array-uniq@1.0.2, beeper@1.1.0, lodash._reescape@3.0.0, lodash._reevaluate@3.0.0, lodash._reinterpolate@3.0.0, object-assign@3.0.0, replace-ext@0.0.1, vinyl@0.5.0, lodash.template@3.6.2, through2@2.0.0, multipipe@0.1.2, dateformat@1.0.11) ├── liftoff@2.1.0 (extend@2.0.1, rechoir@0.6.1, flagged-respawn@0.3.1, resolve@1.1.6, findup-sync@0.2.1) └── vinyl-fs@0.3.13 (graceful-fs@3.0.8, strip-bom@1.0.0, defaults@1.0.2, vinyl@0.4.6, mkdirp@0.5.1, through2@0.6.5, glob-stream@3.1.18, glob-watcher@0.0.6) gulp_test 14:22:48 zow$ ls -l total 0 drwxr-xr-x 4 zow staff 136 7 10 14:22 node_modules gulp_test 14:22:54 zow$
プロジェクトディレクトリ直下に「node_modules」ってディレクトリが出来た。gulpはこの中にインストールされているらしい。
browser-syncのインストール
次に「browser-sync」をインストールする。こちらもnpmコマンドで行う。
gulp_test 14:38:00 zow$ npm install browser-sync --save-dev > fsevents@0.3.6 install /Users/zow/work/gulp_test/node_modules/browser-sync/node_modules/chokidar/node_modules/fsevents > node-gyp rebuild gyp ERR! configure error gyp ERR! stack Error: Python executable "python" is v3.4.0, which is not supported by gyp. gyp ERR! stack You can pass the --python switch to point to Python >= v2.5.0 & < 3.0.0. gyp ERR! stack at failPythonVersion (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/configure.js:119:14) gyp ERR! stack at /usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/configure.js:108:9 gyp ERR! stack at ChildProcess.exithandler (child_process.js:742:7) gyp ERR! stack at ChildProcess.emit (events.js:110:17) gyp ERR! stack at maybeClose (child_process.js:1015:16) gyp ERR! stack at Socket.<anonymous> (child_process.js:1183:11) gyp ERR! stack at Socket.emit (events.js:107:17) gyp ERR! stack at Pipe.close (net.js:485:12) gyp ERR! System Darwin 14.4.0 gyp ERR! command "node" "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild" gyp ERR! cwd /Users/zow/work/gulp_test/node_modules/browser-sync/node_modules/chokidar/node_modules/fsevents gyp ERR! node -v v0.12.7 gyp ERR! node-gyp -v v2.0.1 gyp ERR! not ok npm WARN optional dep failed, continuing fsevents@0.3.6 > ws@0.5.0 install /Users/zow/work/gulp_test/node_modules/browser-sync/node_modules/socket.io/node_modules/engine.io/node_modules/ws > (node-gyp rebuild 2> builderror.log) || (exit 0) > ws@0.4.31 install /Users/zow/work/gulp_test/node_modules/browser-sync/node_modules/socket.io/node_modules/socket.io-client/node_modules/engine.io-client/node_modules/ws > (node-gyp rebuild 2> builderror.log) || (exit 0) browser-sync@2.7.13 node_modules/browser-sync ├── async-each-series@0.1.1 ├── longest@1.0.1 ├── query-string@2.3.0 ├── emitter-steward@0.0.1 ├── ucfirst@0.0.1 ├── opn@2.0.1 ├── dev-ip@1.0.1 ├── pad-left@1.0.2 (repeat-string@1.5.2) ├── ua-parser-js@0.7.7 ├── meow@3.3.0 (object-assign@3.0.0, camelcase-keys@1.0.0, minimist@1.1.1, indent-string@1.2.1) ├── browser-sync-client@2.2.1 (etag@1.7.0, fresh@0.3.0) ├── portscanner@1.0.0 (async@0.1.15) ├── immutable@3.7.4 ├── resp-modifier@4.0.2 (minimatch@2.0.8) ├── foxy@11.0.4 (cookie@0.1.3, http-proxy@1.11.1, lodash.merge@3.3.2) ├── connect@3.4.0 (utils-merge@1.0.0, parseurl@1.3.0, debug@2.2.0, finalhandler@0.4.0) ├── serve-static@1.10.0 (escape-html@1.0.2, parseurl@1.3.0, send@0.13.0) ├── anymatch@1.3.0 (arrify@1.0.0, micromatch@2.1.6) ├── chokidar@1.0.3 (arrify@1.0.0, path-is-absolute@1.0.0, is-glob@1.1.3, glob-parent@1.2.0, async-each@0.1.6, is-binary-path@1.0.1, readdirp@1.3.0) ├── serve-index@1.7.1 (escape-html@1.0.2, parseurl@1.3.0, batch@0.5.2, http-errors@1.3.1, debug@2.2.0, accepts@1.2.10, mime-types@2.1.2) ├── easy-extender@2.3.1 (lodash@2.4.2) ├── eazy-logger@2.1.2 (tfunk@3.0.1, opt-merger@1.1.0) ├── localtunnel@1.5.1 (debug@0.7.4, optimist@0.3.4, request@2.11.4) ├── lodash@3.10.0 ├── socket.io@1.3.5 (has-binary-data@0.1.3, debug@2.1.0, socket.io-adapter@0.3.1, engine.io@1.5.1, socket.io-parser@2.2.4, socket.io-client@1.3.5) └── browser-sync-ui@0.5.12 (connect-history-api-fallback@0.0.5, angular-touch@1.4.2, angular-sanitize@1.4.2, angular-route@1.4.2, angular@1.4.2, stream-throttle@0.1.3, weinre@2.0.0-pre-I0Z7U9OV) gulp_test 14:38:32 zow$
なんとエラー発生。pythonが3.4.0だからサポートしてないって文句を言ってる。そりゃnodeでpython使ってると思わないから普段の環境のままさ。先に言っといてくれ。
とりあえずPythonをSystemに戻す。
gulp_test 14:42:20 zow$ pyenv versions system 3.4.0 * 3.4.0-spider (set by /Users/zow/.pyenv/version) 3.4.2 gulp_test 14:42:28 zow$ pyenv global system gulp_test 14:42:41 zow$ pyenv rehash gulp_test 14:42:49 zow$ pyenv versions * system (set by /Users/zow/.pyenv/version) 3.4.0 3.4.0-spider 3.4.2 gulp_test 14:42:55 zow$ python -V Python 2.7.6 gulp_test 14:43:02 zow$
Python環境をシステムに戻した所で再度入れなおす。
gulp_test 14:43:02 zow$ npm install browser-sync --save-dev / > fsevents@0.3.6 install /Users/zow/work/gulp_test/node_modules/browser-sync/node_modules/chokidar/node_modules/fsevents > node-gyp rebuild SOLINK_MODULE(target) Release/.node CXX(target) Release/obj.target/fse/fsevents.o SOLINK_MODULE(target) Release/fse.node > ws@0.5.0 install /Users/zow/work/gulp_test/node_modules/browser-sync/node_modules/socket.io/node_modules/engine.io/node_modules/ws > (node-gyp rebuild 2> builderror.log) || (exit 0) CXX(target) Release/obj.target/bufferutil/src/bufferutil.o SOLINK_MODULE(target) Release/bufferutil.node CXX(target) Release/obj.target/validation/src/validation.o SOLINK_MODULE(target) Release/validation.node > ws@0.4.31 install /Users/zow/work/gulp_test/node_modules/browser-sync/node_modules/socket.io/node_modules/socket.io-client/node_modules/engine.io-client/node_modules/ws > (node-gyp rebuild 2> builderror.log) || (exit 0) CXX(target) Release/obj.target/bufferutil/src/bufferutil.o browser-sync@2.7.13 node_modules/browser-sync ├── async-each-series@0.1.1 ├── longest@1.0.1 ├── query-string@2.3.0 ├── emitter-steward@0.0.1 ├── ucfirst@0.0.1 ├── opn@2.0.1 ├── dev-ip@1.0.1 ├── pad-left@1.0.2 (repeat-string@1.5.2) ├── ua-parser-js@0.7.7 ├── serve-static@1.10.0 (escape-html@1.0.2, parseurl@1.3.0, send@0.13.0) ├── portscanner@1.0.0 (async@0.1.15) ├── foxy@11.0.4 (cookie@0.1.3, http-proxy@1.11.1, lodash.merge@3.3.2) ├── meow@3.3.0 (object-assign@3.0.0, camelcase-keys@1.0.0, minimist@1.1.1, indent-string@1.2.1) ├── browser-sync-client@2.2.1 (fresh@0.3.0, etag@1.7.0) ├── connect@3.4.0 (utils-merge@1.0.0, parseurl@1.3.0, debug@2.2.0, finalhandler@0.4.0) ├── immutable@3.7.4 ├── resp-modifier@4.0.2 (minimatch@2.0.8) ├── anymatch@1.3.0 (arrify@1.0.0, micromatch@2.1.6) ├── serve-index@1.7.1 (escape-html@1.0.2, parseurl@1.3.0, batch@0.5.2, http-errors@1.3.1, debug@2.2.0, accepts@1.2.10, mime-types@2.1.2) ├── easy-extender@2.3.1 (lodash@2.4.2) ├── eazy-logger@2.1.2 (tfunk@3.0.1, opt-merger@1.1.0) ├── localtunnel@1.5.1 (debug@0.7.4, optimist@0.3.4, request@2.11.4) ├── lodash@3.10.0 ├── browser-sync-ui@0.5.12 (connect-history-api-fallback@0.0.5, angular-touch@1.4.2, angular-sanitize@1.4.2, angular-route@1.4.2, stream-throttle@0.1.3, angular@1.4.2, weinre@2.0.0-pre-I0Z7U9OV) ├── chokidar@1.0.3 (arrify@1.0.0, path-is-absolute@1.0.0, is-glob@1.1.3, glob-parent@1.2.0, async-each@0.1.6, is-binary-path@1.0.1, readdirp@1.3.0, fsevents@0.3.6) └── socket.io@1.3.5 (debug@2.1.0, has-binary-data@0.1.3, socket.io-adapter@0.3.1, socket.io-parser@2.2.4, engine.io@1.5.1, socket.io-client@1.3.5) gulp_test 14:46:12 zow$
無事にインストール出来たっぽい。
gulpfile.jsの作成
必要なパッケージは用意できたので、gulpの設定を記述する「gulpfile.js」を作成する。
var gulp = require('gulp'); var browserSync = require('browser-sync'); gulp.task('browser-sync', function(){ browserSync({ server: { baseDir: "./html" } }); }); gulp.task('default', ['browser-sync']);
requireでnodeパッケージをインスタンス化して、gulp.taskでタスクの定義をしている感じ。gulp.taskの中で「default」が標準で起動するタスクになる。今回は「browser-sync」のタスクを作って、defaultでbrowser-syncを起動する形にしている。
次にhtmlを置く「html」ディレクトリを作成する。
gulp_test 15:06:16 zow$ mkdir html gulp_test 15:06:20 zow$
htmlディレクトリを作成したらその中に適当なhtmlファイルを作成しておく。で、この状態でgulpを起動するとブラウザが勝手に起動する。
ディレクトリを監視する
gulpfile.jsを以下の様に変更
var gulp = require('gulp'); var browserSync = require('browser-sync'); gulp.task('browser-sync', function(){ browserSync({ server: { baseDir: "./html" } }); }); gulp.task('default', ['browser-sync'], function(){ gulp.watch(['./html/*.html'], function(){ browserSync.reload(); }); });
デフォルトの動作部分に「gulp.watch」で監視ディレクトリを追加してやる。今回は「html」ディレクトリの中を監視して、変更があった場合はリロードするようになっている。
この状態でhtmlファイルを変更すると自動でブラウザにリロードがかかる。なかなか楽しい感じになる。
今回はブラウザののリロード自動化だけだが、他にもscssとかlessとか使ってればコンパイルをさせる事ができたり、jsのminifyなんかをさせたりといろいろ出来る。基本的にファイル監視してそれをトリガに何かをさせる形になるのだが、かなりプラグインが用意されてるので、開発環境として思いつく限りの事は大体出来そうだ。
jsが嫌いと言うことで、今まであまりnodeなんかを触ることはなかったのだけど、それだけで随分と時代から遅れているんだなー、なんて事を今更ながらに実感した。好き嫌いしちゃダメだよねー。ホントに。