フロントエンドのビルドツール、Grunt以外の選択肢
フロントエンドのビルドツールというとGruntが
デファクトスタンダードになっている感ありますが、
それ以外の選択肢って何があるかなという話です。
Gulp
Gulpはストリーミング式のビルドツールです。
設定はgulpfileに記述します。
gulp = require 'gulp' coffee = require 'gulp-coffee' concat = require 'gulp-concat' uglify = require 'gulp-uglify' gulp.task 'compile', -> gulp.src('./src/*.coffee') .pipe(coffee()) .pipe(concat('all.js')) .pipe(uglify()) .pipe(gulp.dest('./dist/'))
記述方法はGruntと違い、このようにgulp.src()
が返すstreamオブジェクトから
処理をメソッドチェインで繋げていきます。
上の例だと
# ファイル読み込んで gulp.src('./src/*.coffee') # coffeeからコンパイルして .pipe(coffee()) # concatして .pipe(concat('all.js')) # 圧縮して .pipe(uglify()) # ./dist/以下に出力 .pipe(gulp.dest('./dist/'))
といった感じの流れになります。
pipe
で生成物をそのまま次の処理に渡して行くため、
このようなケースではGruntよりシンプルにタスクを定義する事ができます。
またwatchタスクは標準機能として備えているためその為のプラグイン等は不要です。
gulp.task 'watch', -> gulp.watch './src/*.coffee', (event) -> console.log "#{event.path}: #{event.type}" gulp.run 'compile'
複数のタスクを実行するタスクはGruntと同じような書き方で定義できますが、
gulp.task 'default', ['coffee', 'concat', 'uglify']
Gruntと違いこの順番に同期的に実行される訳ではなく、
順序が保証されてないため注意が必要です。
そうしたい場合はcallbackやdeferred等で
ごにょごにょやらないといけないのが少し面倒ですね。
プラグインは現在約180ほどの登録があり、
各種コンパイラやlint、テストランナーは一通り揃っているようです。
Brunch
Brunchは
Brunch is an ultra-fast HTML5 build tool
とされていますが、ビルド以外にも
scaffoldやローカルサーバの立ち上げといった機能があり
Grunt + yoと言った方が近いかもしれません。
# 指定したBrunch skeltonからプロジェクトの雛形を作成 $ brunch new skelton-url # wach + ローカルサーバの立ち上げ $ brunch w -s # ビルド $ brunch build
多くのskeltonは一緒にテスト環境も用意してくれるので、
例えばBrunch with Marionetteならlocalhost:3333/test
にアクセスすれば
そのままブラウザ上でmochaによるテストを実行する事ができます。
Gulp同様、プラグインやボイラープレートとなるskeltonは一通り揃っています。
skeltonはやはりChaplinやAngularなどMVCフレームワークのものが人気なようです。
まとめ
プラグインの充実度やコミュニティの活発さでは
Gruntがまだまだ強いと思いますが、
SPAなんかでフロントとサーバが疎結合になっていたりする場合は
ローカルサーバの立ち上げからビルドまでやってくれるBrunch、
小規模なプロジェクトで設定ファイルをシンプルに書きたいなら
Gulpと、それぞれビルドツールの選択肢に加えてみるのも良いんじゃないでしょうか。
2013年読んで良かった本
たのしいRuby 第4版
Rubyを始めたので、まずは定番と言われているものを。
章立てで非常に解りやすく、入門書としても最適だと思います。
Ruby2.0にも対応しています。
- 作者: 高橋征義,後藤裕蔵,まつもとゆきひろ
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2013/06/04
- メディア: 単行本
- この商品を含むブログ (22件) を見る
ジェネラティブ・アート -Processingによる実践ガイド
ジェネラティブ・アートとはプログラムによって生成されるアートであり、
そのパラダイムやアルゴリズムの解説+Processingの入門的な本です。
フラクタルの生成は再帰処理の練習にもなります。
ジェネラティブ・アート -Processingによる実践ガイド
- 作者: Matt Pearson,久保田晃弘,沖啓介
- 出版社/メーカー: ビー・エヌ・エヌ新社
- 発売日: 2012/12/21
- メディア: 単行本(ソフトカバー)
- クリック: 9回
- この商品を含むブログ (5件) を見る
思考する機械コンピュータ (サイエンス・マスターズ)
コンピュータサイエンスの知識が全くない事に危機感を感じて、
その入門として古本屋で見つけて読みました。
チューリングの万能機械、NP完全問題などコンピュータとアルゴリズムの
基礎的な概念を解りやすく学ぶ事ができます。
- 作者: ダニエルヒリス,W.Daniel Hillis,倉骨彰
- 出版社/メーカー: 草思社
- 発売日: 2000/10
- メディア: 単行本
- 購入: 5人 クリック: 62回
- この商品を含むブログ (28件) を見る
コーディングを支える技術 ~成り立ちから学ぶプログラミング作法 (WEB+DB PRESS plus)
プログラミング言語の歴史、
なぜその機能が生まれたのかといった事を解説しています。
各言語の特色や独自のパラダイムをざっくりとつかむには非常に良い読み物であると思います。
コーディングを支える技術 ~成り立ちから学ぶプログラミング作法 (WEB+DB PRESS plus)
- 作者: 西尾泰和
- 出版社/メーカー: 技術評論社
- 発売日: 2013/04/24
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (26件) を見る
97 Things Every Programmer Should Know: Collective Wisdom From The Experts
超定番ですが、kindle英語版がセールだったときに買ってみました。
読み物として面白いのはもちろん、どこからでも読める上に1章が短いので
ちょっとした空き時間に英語の学習をするのにも具合が良かったです。
(といいつつまだ半分しか読んでない)
97 Things Every Programmer Should Know: Collective Wisdom From The Experts
- 作者: Kevlin Henney
- 出版社/メーカー: O'Reilly Media
- 発売日: 2010/02/05
- メディア: Kindle版
- この商品を含むブログを見る
Marionette.jsについてあれこれ
Marionette.jsはBackbone.jsのラッパー的なライブラリです。
Backbone.jsの問題点
Backbone.jsは割と自由度が高いフレームワークなのですが、
それ故に中規模以上のプロジェクトで使おうとすると
- 設計が難しい(ベストプラクティスがわからずオレオレ実装になる)
- 初期化やインスタンスの管理が面倒
- Viewは同じような処理が増える(で基底クラスにまとめたりする)
といったデメリットがあります。
実際僕もよくわからないまま初期設計をした結果
大きな技術的負債を作ってしまった事がありました。
Marionette.js
Marionette.jsはBackbone.jsと比べて抽象度が高く、
モジュール機構、CollectionView、Viewのデストラクタなど
独自実装になりがちな機能を提供してくれます。
これらを使う事で上に挙げたようなデメリットを回避し
Backbone.jsだけを使用した場合と比較して
シンプルで明確な実装を行うことができます。
機能とかAPIとか
まとめてみました
- Marionette.jsまとめ その1 Application, Controller, AppRouter
- Marionette.jsまとめ その2 View, ItemView, CollectionView
- Marionette.jsまとめ その3 CompositeView, Layout, Region
Backbone.jsは最近Angular.jsに押され気味な感もありますが、
こうしたライブラリと合わせて使ってみるとまた印象が違ってくるかと思います。
似たような感じの
全部試した訳じゃないんですが、色々あるようです。
後から書くフロントエンドのテスト
今業務でやってるプロジェクト、ジョインした時点では
フロントはこんな感じでした。
これはヤバいと思い開発の合間合間にテストを書いていったのですが、
その時にやったことの記録です。
使ったもの
- Mocha
- chai
- Sinon.js
- testem
- PhantomJS
- CasperJS
DOMのテストもしたかったので実行環境はブラウザにしています。
Jasmineでも良かったのですがアサーションも自分で選びたかったので
Mochaを使いました。
どのくらい書いたか
結論から言うと共通のメソッドやコンポーネントだけしか書いてません。
そもそもテストを書く事を全く考慮されていないコードで、
DOMと密結合しまくりだったり
if (result) { resultDom += '<div class="result"...'; } wrapper.innerHTML = resultDom;
長過ぎる関数だったり
function buildHogeList = function() { // 200行くらいの処理 }
外部から完全に遮断されていたり
(function() { var HogeController = function() {... })();
といった有様でした。
最初は頑張ってこれらに合わせて書いていたのですが、
- 「
.hogeButton
という要素をクリックするとhogeController.hogeClickHandler
が呼び出される」 - 「buildHogeTitleは
<div class="hoge">massage</div>
というDOMを生成する」
みたいなテストケースをひたすら書いているのはあまりにも効率が悪いと感じたので
それらを補完する意味でも後述のCasperJSなどを使用したテストに注力しました。
CasperJSが便利
単体テストに加えて、CasperJSでスクレイピングをするようにしました。
CasperJSはテストやスクレイピング用のユーティリティを備えたPhantomJSのラッパーです。
動作としては
- 全ページのチェック
- チュートリアルの進行
- 基本ゲームループ
合わせてjsエラーのチェック、DOMの状態などのアサーション、
スクリーンショットを取ってレイアウトをざっくり確認、といった事をしています。
Jenkinsとの連携
Jenkins上に専用のジョブを作成して、ビルド後にトリガーで実行されるようにしました。
ビルド前に単体テスト、ビルド後にそのサーバー上でCasperJSでのテストを実行しています。
これはまだやってないんですが、 HARファイルや画面キャプチャなどの成果物を
アップロードしてどこかで確認できるようになるとかなり捗りそうだなーと考えています。
思ったこと
テストファーストとかカバレッジとか完全に無視してしまってますが
仕様やDOMが頻繁に変わるソーシャルゲームの場合
このくらいが落としどころなのかもしれません。
とはいえ、ここまでやってきて結構つらい感じはあったし
最初からテスト書きながら開発するのに越した事は無いと思います。
最近の○○.jsをざっくりまとめてみた
一口に○○.jsと言っても、単純にクライアント側で読み込むライブラリではないものが増えてきています。
有名なものをいくつかまとめてみました。
Node.js
JavaScriptの実行環境です。実行にはGoogleのV8エンジンが使われています。
主にサーバーサイドの実装に使われることが多いですが
後述するGrunt.jsなどのツールが普及するにつれ、フロントエンドの開発でも重要性を増してきています。
Grunt.js
Node.js上で動くタスク実行ツールです。
プラグインをインストールすることで
- ファイルのコンパイル
- 変更の監視
- テストの実行
- サーバーを立てる
- 画像のサイズ最適化
など様々なタスクを実行することができます。
CommonJS
ブラウザ上だけではなく、サーバーサイドやGUIアプリケーションでも
使用されるようになってきたJavaScriptの実装に
汎用性を持たせるために策定されたAPIの標準仕様です。
CommonJSという名前のライブラリが存在するわけではありませんが
例えばNode.jsの一部、モジュール機構などはこのCommonJSに準拠しています
CreateJS
JavaScriptでのインタラクティブコンテンツ開発をサポートするライブラリ群です。
Easel.js, Tween.js, Preload.js, Sound.jsの4つのライブラリから成ります。
Flash CS6以降はこれを使用したToolkit for CreateJSという拡張機能により
HTML5へコンテンツをエクスポートすることが可能となっています。
altJS
JavaScriptに変換される言語の総称です。
有名なものにCoffeeScript, TypeScript, JSX, Haxeなどがあります。
それぞれの言語ごとに特色があり、いずれも
クラスの実装や型付けの強化、実行パフォーマンスの向上など
素のJavaScriptを補完するようなものとなっています。
PhantomJS
ヘッドレスなWebkitブラウザです。
操作にはJavaScriptを使用し、スクレイピングや画面キャプチャをとるといったことが可能です。
似たものにSlimerJSがあり、こちらはGeckoベースとなっています。
CasperJS
スクレイピングやテストに便利なユーティリティを揃えたPhantomJS(or SlimerJS)のラッパーです。
Node.js上で動かすための更なるラッパーであるSpookyJSもあります。
VanilaJS
高速で軽量かつクロスプラットフォームなフレームワークです。
非常に高いシェアを誇り、これを使用していないJavaScriptのコードは存在しないとまで言われています。
と、ざっくりした感じですがまとめてみました。
実際にここに列挙したものは全て僕がやっているプロジェクトでも使っていたりします。
どれもデファクトスタンダードになりつつある感じなので、一度触っておいて損は無いかと思います。
Vagrant + chef + Berkshelfでフロントエンドの環境構築を自動化
最近のフロントエンド
GitやNode.jsやSassやaltJSのコンパイラなど、使うものが増えて
環境構築の手順も複雑になってきています。
そこでVagrantとchef、それからcookbookの依存関係を管理するBerkshelfを使って
環境構築の手順を自動化かつ共有できるようにしました。
開発環境の中身
最近自分がよく使っているものを入れてみます。
- Git
- Node.js
- grunt-cli
- Bower
- testem
- PhantomJS
- CasperJS
セットアップ
Berksfileの編集
使用するサードパーティのcookbookを記述します。
要するにGemfileとかpackage.jsonのようなものです。
Berksfile
site :opscode metadata # Git, Node.js, PhantomJSはOpscodeにホスティングされているcookbookを使用してインストール cookbook 'git' cookbook 'nodejs' cookbook 'phantomjs'
自前recipeの編集
サードパーティのcookbookを使わずにセットアップするものは
こちらに記述していきます。
recipe/default.rb
extract_path = "/usr/local/bin" # githubからCasperJSのリポジトリをクローン git "/vagrant/casperjs" do repository "git://github.com/n1k0/casperjs.git" user "root" revision "1.1-beta1" action :checkout end # シンボリックリンクを作成 bash "install casperjs" do cwd "/vagrant/casperjs" user "root" code <<-EOH ln -sf `pwd`/bin/casperjs #{extract_path}/casperjs EOH end # Node.jsのパッケージで必要なものをグローバルインストール bash "install npm packages" do cwd "/home/vagrant" user "root" code <<-EOH npm install -g grunt-cli bower testem EOH end
Vagrantfileの編集
使用するBoxの設定*1
# 今回はUbuntuを使用 # Every Vagrant virtual environment requires a box to build off of. config.vm.box = "Ubuntu precise 64 VirtualBox" # The url from where the 'config.vm.box' box will be fetched if it # doesn't already exist on the user's system. config.vm.box_url = "http://files.vagrantup.com/precise64.box"
起動時に実行するレシピを追記
chef.run_list = [ "recipe[git]", "recipe[nodejs]", "recipe[phantomjs]", "recipe[chef-frontend::default]" ]
実行してみる
# cookbookのインストール berks install --path=cookbooks # Vagrantマシンの起動、レシピの実行 vagrant up
これだけで環境構築完了です。
仮想マシンにログインして各コマンドが使用できることを確認してみます。
vagrant ssh
# -> git, node, grunt, bower, testem, phantomjs, casperjsコマンドが使える!
NodeListのイテレーション比較
document.querySelectorAllなどで取得するNodeListはArrayのインスタンスではないため
forEachやmapといったメソッドを持っていません。
そのためループで展開したいときは普通にfor文使うとか、
Array.prototype.forEachをcallで呼び出すとか
ライブラリの関数を利用するといった選択肢がありますが
それらのパフォーマンスを計測・比較してみました。
結果はこんな感じ、平均して遅いのはfor inや$.each、
速いのは通常のfor文やwhileでした。
NodeList Iteration · jsPerf
通常のArrayだとこのように、極端なパフォーマンスの差は見られません。
Array Iteration · jsPerf
結論としては、普通にfor文にしましょうとなるんですが、
lodashはfor, whileに次ぐ実行速度で、記述量も少なくて済むので
既にlodashを入れているor他にも使いたいメソッドがあるのであれば
選択肢としては十分にありではないかと思います。
内部的には渡されたリストがArrayのインスタンスでなければ
while文を使ったイテレータ関数の文字列を生成して、
Functionコンストラクタに突っ込んで実行するという、結構泥臭いことをしているようです。
やはりパフォーマンスを最優先にしている印象ですね。
あと、for文書くときに
for (var i = 0, len = list.length; i < len; i++) {
のようにlengthをキャッシュした方が速い、というのは割と定説になっている思うのですが、
最近のJavaScriptエンジンでは自動的に最適化されるので必要ないという話も
耳に挟んでいたのでその比較も先ほどのjsperfに入っています。
for (var i = 0; i < list.length; i++) {
lengthをキャッシュした場合と比較してもほぼ遜色ないどころか、
Firefoxではむしろ速くなっています。
モダンブラウザ・スマートフォン向けの開発なら、lengthのキャッシュはもう必要ないですね。
※この他にインクリメントの前置・後置も比較してみましたが、特に差は確認できませんでした。