SiNBLOG

140文字に入らないことを、極稀に書くBlog

grunt-contrib-requirejsを試してみた

ちょっと前から、JS力を上げようと足掻いてます

今回はその中でも以下の内容を模索してみました


1.package管理

2.ミニファイ&ファイル連結
3.ファイル監視して、自動で2をやる


1をやりたいのは、以下の様な理由から

  • そのページに必要なJSだけを読み込みたかった
  • 他にも依存関係をぱっと見で分かるようにしたかった
  • global領域を汚染しないようにしたかった

2をやりたいのは、以下の様な理由から

  • 役割毎にファイルを分けたいが、jsファイルを読み込むオーバーヘッドは極力少なくしたい

そして、RequireJSがそれを解決してくれそう


3をやりたいのは、以下の様な理由から

  • 開発時にjsファイルを修正する度に、commandやらを打つのは面倒・・・


ClosureLibraryでも上記は満たせるのだけど、流石に仕事に使うにはマニアックな気もするので、
一般的?にはどうやるのか調べてみることに

そして、Grunt: The JavaScript Task Runnerがそれを解決してくれそう


gruntjsはtwitterのTLでちらほら見かけていたので、気になっていました
この2つを組み合わせればいけるか!?などと思っていたら、grunt-contrib-requirejs - npmがあることに気付きました
因みにこいつはGrunt0.4系でないと動かないみたいです
ちょっと前にgrunt.js試した時に、0.3系入れていたので、今回VersionUp


というわけで、上記を満たすために、挑戦してみました
挑戦した結果はGithubに置いてます
GitHub - sinmetal/webproject-template at develop


まず、grunt.jsを動かすためにはNode.jsが必要なので、適当に入れます
Macだと公式ページから一発でInstallできるけど、他のOSだとどうなのかな?
以下の手順も全てMacでやったことなので、他OSだと動くのかは分かりません


次にgruntを入れます
Getting started - Grunt: The JavaScript Task Runner
公式に書いてある通り、


npm install -g grunt-cli
でいれます
Macだとsudoが必要になると思います


grunt.jsの設定ファイルをプロジェクトの直下に置きます。
Gruntfile.js
webproject-template/Gruntfile.js at develop · sinmetal/webproject-template · GitHub


module.exports = function(grunt) {

grunt.initConfig({
// 監視用の設定
watch: {
files: './src/**',
tasks: ['requirejs']
},

// requirejs用の設定
requirejs: {
compile_top: {
options: {
name : 'main', // mainで読み込むjsのpath
baseUrl: "./src/js",
mainConfigFile: './src/js/main.js',
out: "./build/toppage.js"
}
},

compile_page1: {
options: {
name : 'page1/main', // mainで読み込むjsのpath
baseUrl: "./src/js",
mainConfigFile: './src/js/page1/main.js',
out: "./build/page1.js"
}
}
},
});

//matchdepでpackage.jsonから"grunt-*"で始まる設定を読み込む
require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
//grunt.loadNpmTasks('grunt-contrib-watch');
//grunt.loadNpmTasks('grunt-contrib-requirejs');
}

いくつかの設定を書いているので、ちょっとずつ説明していきます
まずは、先頭のwatch

watch: {
files: './src/**',
tasks: ['requirejs']
}
これは、ファイル監視用の設定です
grunt-watch
'./src/**'src以下のファイルに変更があった場合、'requirejs'を実行しろ!となります
僕がjsファイルをsrcの下に置いていて、requirejsのビルドのタスク名が'requirejs'なので、こうなります
これで、jsファイル修正時に、自動でビルドが走るように設定できました


次のrequirejs


// requirejs用の設定
requirejs: {
compile_top: {
options: {
name : 'main', // mainで読み込むjsのpath
baseUrl: "./src/js",
mainConfigFile: './src/js/main.js',
out: "./build/toppage.js"
}
},

compile_page1: {
options: {
name : 'page1/main', // mainで読み込むjsのpath
baseUrl: "./src/js",
mainConfigFile: './src/js/page1/main.js',
out: "./build/page1.js"
}
}
},
});

これは、grunt-contrib-requirejs - npmのための設定です
'compile_top', 'compile_page1'の2つのページ用の設定を書いています
各ページのメインとなるjsのPathをnameで指定します
name:'page1/main'で、baseUrl:'./src/js'なので、'./src/js/page1/main.js'を見に行きます
mainConfigFileが同じファイルを指しているのは、依存関係をそのファイルに書いているからです
これについては、そのファイルが出た時に説明します
out: './build/page1.js'はミニファイ&ファイル連結されたファイルが出力されるPathです
これで設定は完了です


最後にnpm installで入れる設定の一覧


//matchdepでpackage.jsonから"grunt-*"で始まる設定を読み込む
require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
//grunt.loadNpmTasks('grunt-contrib-watch');
//grunt.loadNpmTasks('grunt-contrib-requirejs');
4行あるけど、実際に動いているのは1行だけ
ここの部分は、matchdepを使ってGrunt.jsのプラグインを自動ロードするを参考にさせてもらいました
npm installの設定をGruntfile.jsとpackage.jsonの両方に書くのが面倒だから、
package.jsonを見に行くようにするってのが、metchdepです
入れ方なんかは、上記のリンク先を参照してください


これで、Gruntfile.jsの設定はおしまいです。
次は、package.jsonです


{
"name": "webproject-template",
"version": "0.1.0",
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-watch": "~0.3.1",
"grunt-contrib-requirejs": "~0.4.0",
"matchdep": "~0.1.1"
}
}
ここに書いてある"grunt-*"が利用しているgruntのpluginの一覧です
Projectの直下で

npm install
すると、node_modulesというディレクトリの下にインストールされます


これで準備は完了です
ここからは実際にどんな感じで作っていくかというのを書いていきます
まず、途中で少し出てきたけど、ディレクトリ構成は以下の様な感じ


build // buildされた結果のjs
+-page1.js
-toppage.js
page1
+-index.html
src
+-js
+-lib // OSSのLibraryとか
+-jquery.js // jQuery公式からDLしてきた
-require.js // requirejs公式からDLしてきた
-module // 自分で作ったutilとか置く場所
+-fuga.js
-hoge.js
-page1 // page1固有
+-main.js
-main.js // toppageのmain.js
Gruntfile.js
index.hml
package.json


まずは、moduleの中にあるhoge.jsです


define([
'lib/jquery'
], function($) {
var Hoge = function() {};
Hoge.prototype.awesomeThod = function() {
console.log('Hellow RequireJS!');
};

Hoge.prototype.outputLog = function(text) {
console.log(text);
};

return Hoge;
});

defineで依存しているjsのpathを書きます
ここではjQueryを指定しています
・・・使ってはいませんけど
後は、定義したいメソッドやらを作っていけば、OKです


次に、moduleを呼び出しているmain.jsです


//main.js
require.config({
baseUrl: 'js',
paths: {
'jquery': 'lib/jquery.js'
}
});

require([
'module/hoge',
'module/fuga'
], function(Hoge, Fuga) {
// Hogeにはhoge.jsで定義されたコンストラクタが渡る
var hoge = new Hoge();
hoge.awesomeThod();
});

require.configが上の方に書いたmainConfigFileに指定した設定です
設定できる項目についてはhttp://d.hatena.ne.jp/maneater_rhythm/20130219/1361282887で詳しく書いてくれてます

require〜〜の部分が、処理の内容を書くところです
'module/hoge'でmodule/hoge.jsを読み込んでます
こいつの読み込みが終わると、Hogeに入れてくれます
後は使うだけ!

最後にindex.htmlです

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>Web Project Template for Sinmetal</title>
</head>
<body>
	<p>Used Libraries</p>
	<ul>
		<li><a href="http://jquery.com/">jQuery</a></li>
		<li><a href="http://requirejs.org/">RequireJS</a></li>
	</ul>
	<p>Other Page</p>
	<ul>
		<li><a href="page1/index.html">page1</a></li>
	</ul>
	<script src="src/js/lib/require.js"></script>
	<script src='build/toppage.js'></script>
</body>
</html>

require.jsと、buildされたtoppage.jsを読み込んでいます
html側は特出することはないので、これだけです


後は、commandについても紹介しておきます
上記のプロジェクトをビルドするには


grunt requirejs
でできます
これは、Gruntfile.jsに書いてある設定の名前が、requirejsだからです
デフォルトを指定しておけば、引数無しで行けるとだと思うのだけど、デフォルト設定してないので・・・

後、ファイル監視


grunt watch
こいつもGruntfile.jsに書いてある設定の名前が、watchだから
これを起動しておけば、jsに修正が入った時に、自動でrequirejsを実行してくれます


以上でgrunt-contrib-requirejsを試してみた!は終わりです
そして、ここまで読んだ聡明な方なら、気付いてしまったと思うのですが・・・テストの設定が無い
まだ、JSのテストをいまいちどうやれば良いのか分かってないので、設定できてないorz