gruntをWindows XP+shift_jis環境で使う
OSは未だにWindows XPだし、文字コードはShift_Jisのがあったりするし
そんなレガシーな環境でも少しづつモダンなツールを導入して効率化を計っていきたい!
ということでgruntを導入してみました。
node.js上で動く、主にHTML/CSS/JavaScript を対象としたタスクランナーで、
ファイル更新を感知してミニファイ、結合、ライブリロードなどの処理を自動でやってくれるツールです。
公式
http://gruntjs.com/
このあたりの記事が詳しいです。
http://kojika17.com/2013/03/grunt.js-memo.html
shift_jis対応はこの記事を参考にさせていただきました。
http://www.mamoida.com/2012/10/gruntconvert/
以下、gruntについての基礎知識があることを前提で、標記の環境に導入するにあたって
つまづいたところと対応をメモします。
- grunt-contribのインストール
grunt-cli、grunt本体の次にインストールされるであろう、gruntの基本タスクパッケージである
grunt-contribですが、インストール時に早速こけます。
理由は、XPのファイルパス長制限。255バイトまでしか認識しません。
grunt-contribにはそれだけで240バイトを超えるパスがあるので、親ディレクトリに許されるパスはせいぜい数バイトという…。
xpにはもちろんシンボリックリンクのような仕組みはないので、ネットワークドライブを作ることで対処しました。
親ディレクトリを右クリックから共有し、コマンドプロンプトからネットワークドライブとして認識させます。
net use z: \\自分のホスト名\親ディレクトリの共有名
以降、このz:ドライブ(任意で変更してください)にてインストールおよびその他の作業を行います。
gruntは基本的にUTF-8しか対応していません。さすが今時のツール……。
とはいえ、やっぱりShift_Jis環境で開発する場合もあるわけで、いったんUTF-8に変更後、ミニファイや結合等の処理を行い、Shift_Jisに戻す、という処理を行おうとしたのですが、今度は文字コード変換に一苦労させられました。
冒頭の参考記事にもあるとおり、nodeでの文字コード変換は、node-iconvというモジュールで行うのが主流らしいのですが、Windowsにはそのままではインストールできません。
インストール時、内部でnode-gypというモジュールを使っているのですが、なんとこれ、動作にVisualStudioや、.net frameworkが必要なんですね。
おいおい、なんのためのnpm…と思いつつ、Visual C++ Expressをインストールするも、またもやエラー。
"C:¥Documents"に何か作ろうとしているけど…あーはいはい、出ました
Documents And Settings 問題
WindowsXPはあらゆる標準パスにスペース使いまくっているせいで、オープンソースソフトがこけまくります。
これの対処はちょっと大変なので、諦めて普通のlibiconvをインストールし、外部プロセスとしてキックすることにしました。
libiconvのダウンロードはこちらから
http://gnuwin32.sourceforge.net/packages/libiconv.htm
このlibiconvを使って、文字コードを変換するgrantタスクを作ります。
フォルダ構造は、以下のような形を想定。
. ├── Gruntfile.js ├── build //実行結果の出力先 │ ├── *.htm │ ├── css │ ├── image │ ├── js ├── src //実際に編集するファイル(入力元) │ ├── css │ ├── image │ ├── js ├── tasks //今回作成するタスク │ ├── convertsjis.js │ ├── convertutf8.js │ └── lib │ └── grunt-iconv-convertchar.js └── tmp //文字コード変換に使う一時ファイル ├── js
上図内におけるtaskフォルダを作成し、文字コード変換処理を実装していきます。
lib/grunt-iconv-convertchar.js
/* Usage: * convert(grunt, this, 'SHIFT_JIS', 'UTF_8'); //Convert charcode from Shift_jis to UTF-8. */ exports.convert = function(grunt, self, fromCode, toCode){ var fs = require('fs'); var exec = require('child_process').exec; function toArray(obj){ return (obj instanceof Array) ? obj : [obj]; } function renameToUniq(orgName){ var destName = orgName; i = 0; while (fs.existsSync(destName)){ destName = destName + '_' + i; i++; } fs.renameSync(orgName, destName); return destName; } var files = toArray(grunt.config(self.name)[self.target].src); var dests = toArray(grunt.config(self.name)[self.target].dest); var done = self.async(); var doneCount = 0; for(var i=0, max=files.length; i<max; i++){ (function(){ var src = files[i]; var dest = dests[i]; var isRenameSrc = false; if (src === dest){ src = renameToUniq(src); isRenameSrc = true; } var cmd = 'iconv -f ' + fromCode + ' -t ' + toCode + ' ' + src + '>' + dest; var child = exec(cmd, function (error, stdout, stderr) { if (error !== null) { grunt.log.writeln('exec error: ' + error); } grunt.log.writeln('File '+ dest + ' created.'); if (isRenameSrc){ fs.unlinkSync(src); } doneCount++; if (doneCount === max){ done(); } }); })(); } };
convertsjis.js
module.exports = function(grunt) { var iconv = require('./lib/grunt-iconv-convertchar.js'); grunt.registerMultiTask('convertsjis', 'Convert charcode from UTF-8 to Shift_Jis.', function() { iconv.convert(grunt, this, 'UTF-8', 'SHIFT_JIS'); }); };
convertutf8.js
module.exports = function(grunt) { var iconv = require('./lib/grunt-iconv-convertchar.js'); grunt.registerMultiTask('convertutf8', 'Convert charcode from Shift_Jis to UTF-8.', function() { iconv.convert(grunt, this, 'SHIFT_JIS', 'UTF-8'); }); };
最後に、Gruntfile.jsに上記のタスクを挿入します。
ミニファイ+結合ならこんな感じ
module.exports = function(grunt) { var path = require('path'); var js = { src: [ 'src/js/hoge.js', 'src/js/fuga.js', 'src/js/piyo.js' ], temp: [ 'tmp/js/hoge.js', 'tmp/js/fuga.js', 'tmp/js/piyo.js' ], dest: 'build/js/<%= pkg.name %>.js' }; grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), //sjis => utf8変換 convertutf8 : { dist : { src : js.src, dest : js.temp } }, // ファイル結合 concat: { dist: { src: js.temp, dest: js.dest } }, // ミニファイ uglify: { options: { banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n' }, build: { src: js.dest, dest: js.dest } }, //utf8 => sjis変換 convertsjis : { dist : { src : js.dest, dest : js.dest } } }); grunt.loadNpmTasks('grunt-contrib'); grunt.loadTasks('tasks'); grunt.registerTask('default', ['convertutf8', 'concat', 'uglify', 'convertsjis']); };
実行
z:¥ grunt
以上!長くなりましたが、無事Windows XPで、Shift_Jisのファイルをgruntで管理できました。
自動監視やライブリロードなんかも導入すると、非常にいい感じです。おすすめ。
…書いた後に気づいたのですが、cygwinなんかを使うともっと簡単に導入できたかも。