プロジェクトの都合上どうしてもantになってしまう場合の対処法です〜
さて、今日は旧石器時代のビルドのお話です。
最近私はソースコード全般が非常に古いプロジェクトを担当しており、そのプロジェクトのビルドがantで行われています。
このantは非常に歴史が古く、xml地獄の冗長なビルドシステムで、当然そう簡単にjsのminify等は行えません。今回は化石のようなantを使って、意地でもjsとcssのminifyを行ってみたいと思います。
- 大前提
- ライブラリの選定
- mercurialでソースをcloneする
- eclipseでjavaプロジェクトを用意する
- yui-compressor-ant-taskをカスタマイズする
- yuicompressor-taskdef-1.0.jarでminifyする!
- 雑感
大前提
前提は以下の通りです。
- antからjsとcssのminifyが行える事。
- ライブラリを使ってもよい。但しant taskの実装があること。
- combineはせず、再帰的にファイル毎にminifyする。
この中で、combineしない件が実は曲者で、標準で行えるものはほとんどありません。
ライブラリの選定
候補は以下があります。
- Google Code Archive - Long-term storage for Google Code Project Hosting.
- Google Code Archive - Long-term storage for Google Code Project Hosting.
- Google Code Archive - Long-term storage for Google Code Project Hosting.
googleのは再帰的に行なえないのと、antタスクがUnsupported化されてしまったので却下。
JSMinは一体いつの時代のライブラリだよ!!という事で却下。
YUIは全ての要件を満たしているので、YUIに決定です。
yui-compressor-ant-taskでminifyを行う!
yui-compressor-ant-taskはバイナリが提供されていないので、ソースをDLして自分でコンパイルする必要があります。
mercurialでソースをcloneする
いきなりハードルが高いですね。gitではなくmercurialです。
macのMavericksなら最初からmercurialがインストールされています。
作者のブログにチェックアウト方法が書いてあります。
hg clone https://yui-compressor-ant-task.googlecode.com/hg/ yui-compressor-ant-task
http://www.simonbuckle.com/2011/02/20/yui-compressor-ant-task/
このコマンドをそのまま実行するわけですが、一旦eclipseにjavaプロジェクトして取り込むので、以下のようにしてください。
# eclipseのワークスペースに移動する treemacpro:workspace tree$ cd /Applications/eclipse/eclipse_treetips/workspace # hg cloneしてソースを取得する treemacpro:workspace tree$ hg clone https://yui-compressor-ant-task.googlecode.com/hg/ yui-compressor-ant-task warning: yui-compressor-ant-task.googlecode.com certificate with fingerprint df:37:c3:23:b3:c1:3c:19:72:36:f2:90:93:1a:b1:9f:53:94:dc:84 not verified (check hostfingerprints or web.cacerts config setting) requesting all changes adding changesets adding manifests adding file changes added 4 changesets with 11 changes to 7 files updating to branch default 7 files updated, 0 files merged, 0 files removed, 0 files unresolved
eclipseでjavaプロジェクトを用意する
先ほどのワークスペース「/Applications/eclipse/eclipse_treetips/workspace」に「yui-compressor-ant-task」というプロジェクト名でjavaプロジェクトを作成して下さい。
当然先ほどcloneしたフォルダ名と競合しますが、構わず作成し、F5でリフレッシュします。
こんな感じになります。
どうやらant.jarに依存しているようなので、apache-antのサイトから最新のバイナリをDLします。
Apache Ant - Binary Distributions
圧縮ファイルを解凍し、「ant.jar」をlibにコピーし、ビルドパスに追加します。
yui-compressor-ant-taskをカスタマイズする
yui-compressor-ant-taskは実は再帰的にminifyできません。
再帰的に処理をしようとして、フォルダが存在しないエラーが発生してしまいます。。。
更に、例外エラーを握りつぶしてantのログを出力されるので、エラー内容が解らないので、これも合わせて修正します。
まず、以下を開きます。といってもこの1ファイルしかjavaファイルはないんですけどね。
/yui-compressor-ant-task/src/java/com/simonbuckle/ant/tasks/CompressTask.java
例外を握りつぶさずStackTraceを出力する
executeメソッドの以下のcatchを、
} catch (IOException io) { log("Failed to compress file: " + fileName); }
以下のようにして下さい。
} catch (IOException io) { log("Failed to compress file: " + fileName); io.printStackTrace(); }
これでIOExceptionの内容(フォルダが存在しない等)が解るようになります。
再帰的にminifyできるようにする
executeメソッドの
if (fileName.endsWith("css")) { compressCss(new File(dir, fileName), new File(todir, output[0])); } else { compress(new File(dir, fileName), new File(todir, output[0])); }
を以下のように書き換えます。
File destPath = new File(todir, output[0]); File destDir = new File(destPath.getParent()); if (!destDir.exists()) destDir.mkdirs(); if (fileName.endsWith("css")) { compressCss(new File(dir, fileName), destPath); } else { compress(new File(dir, fileName), destPath); }
これで出力先フォルダが存在しない場合にフォルダを生成してくれます。
例えば、
js ├── 1.js ├── 2.js └── child ├── 3.js └── 4.js
という構成で、resultフォルダにフォルダ構成を保ったままminifyしたいのですが、result/child/3.js を出力しようとして、result/childフォルダが存在しないエラーになってしまいます。
これを回避するため、前述のフォルダ生成処理を入れました。
ビルドしてjarを生成する
/yui-compressor-ant-task/build.xml
を実行します。targetのdefaultが「compile」になってますがこれは罠で、「pachage」を指定して下さい。
これで「dist/yuicompressor-taskdef-1.0.jar」が生成されます。
yuicompressor-taskdef-1.0.jarでminifyする!
ビルドパスの整理
minifyしたいプロジェクトをcompressとし、
まずは /yui-compressor-ant-task/lib/*.jar を /compress/lib にコピーします。
続いて /yui-compressor-ant-task/dist/yuicompressor-taskdef-1.0.jar を /compress/lib にコピーします。
js・cssのフォルダ構成
続いてフォルダ構成を確認します。
上図のように、htdocs以下にjsとcssフォルダがあり、それぞれ子フォルダに複数ファイル存在します。
minifyしたファイル・フォルダはresultフォルダに出力します。
build.xml
続いてcompress直下にbuild.xmlを作成します。
内容は以下にして下さい。
<project name="js/css minify" default="minify-js" basedir="."> <!-- classpath --> <path id="project.classpath"> <fileset dir="${basedir}/lib"> <include name="*.jar" /> </fileset> </path> <taskdef resource="yuicompressor.tasks" classpathref="project.classpath" /> <!-- jsの圧縮 --> <target name="minify-js"> <yuicompressor todir="${basedir}/result/js" verbose="true" munge="true" preserveAllSemiColons="false" disableOptimizations="false" linebreak="-1"> <fileset dir="${basedir}/htdocs/js"> <include name="**/*.js" /> </fileset> <mapper type="glob" from="*.js" to="*-min.js" /> </yuicompressor> </target> <!-- cssの圧縮 --> <target name="minify-css"> <yuicompressor todir="${basedir}/result/css" verbose="true" munge="true" preserveAllSemiColons="false" disableOptimizations="false" linebreak="-1"> <fileset dir="${basedir}/htdocs/css"> <include name="**/*.css" /> </fileset> <mapper type="glob" from="*.css" to="*-min.css" /> </yuicompressor> </target> </project>
jsの圧縮とcssの圧縮でtargetを分けています。
先ほどの「CompressTask.java」を見ると解りますが、jsかcssかの判定は単純に拡張子で判定しています。
jsをminifyしてみる
minify前のjsは以下の通りです。
// commnet function fun1desyoadsfhl() { // comment alert(1); // comment var array = {}; /* array.push[1]; */ asdfasdgasdfsd // }
色々なところにコメントを差し込み、明らかにコンパイルエラーするコードを混ぜてみました。
ではtargetにminify-jsを指定してbuildしてみます。
Buildfile: /Applications/eclipse/eclipse_treetips/workspace/compress/build.xml minify-js: [yuicompressor] Compressing: 1.js [yuicompressor] Warning: The symbol array is declared but is apparently never used. [yuicompressor] This code can probably be written in a more compact way. [yuicompressor] (){alert(1);var ---> array <--- ={};asdfasdgasdfsd;} [yuicompressor] Compressing: 2.js [yuicompressor] Compressing: 3.js [yuicompressor] Compressing: 4.js BUILD SUCCESSFUL Total time: 834 milliseconds
お、未使用コードを警告してくれました。
コンパイルエラーがあってもSUCCESSFULなんですね・・・ここはエラーにできないのかな。
minify後のjsは以下の通りです。
function fun1desyoadsfhl(){alert(1);var a={};asdfasdgasdfsd};
cssをminifyしてみる
minify前のcssは以下の通りです。
html { /* コメント */ margin-top: 50px; /* padding-top: 50px; */ }
ではtargetにminify-cssを指定してbuildしてみます。
Buildfile: /Applications/eclipse/eclipse_treetips/workspace/compress/build.xml minify-css: [yuicompressor] Compressing: 1.css [yuicompressor] Compressing: 2.css [yuicompressor] Compressing: 3.css [yuicompressor] Compressing: 4.css BUILD SUCCESSFUL Total time: 448 milliseconds
こんな感じです。
minify後のcssは以下の通りです。
html{margin-top:50px;}
ふむ。しっかりjsもcssもminifyできてますね!!!
最終的なフォルダ構成
minifyの出力先も含め、最終的なフォルダ構成は以下のようになっています。
雑感
( #^ω^)antを使うのをやめなさい!
マジでやめましょう。あまりにも原始的なので、記述量が多すぎです。
mavenは黒魔術的な面を持ち、処理が遅いのでオススメしません。
私はGradleをオススメします。
Gradleは最も先進的なjavaのビルドツールで、高速でxmlベースでなくgroovyベースで、
開発も活発に行われているので、それなりの頻度でバージョンアップをしています。
以前Gradleについて沢山記事を書いたので、合わせてご覧下さい!
javaのビルドをgradleで行う:調査編1:maven・SBTとの違い - 文系プログラマによるTIPSブログ
javaのビルドをgradleで行う:調査編2:依存から1行で特定jarを除外! - 文系プログラマによるTIPSブログ
javaのビルドをgradleで行う:調査編3:seasar系の依存の注意点 - 文系プログラマによるTIPSブログ
javaのビルドをgradleで行う:調査編4:Groovy Librariesの罠 - 文系プログラマによるTIPSブログ
javaのビルドをgradleで行う:実践編1:jsとcssのcombineとminify - 文系プログラマによるTIPSブログ
javaのビルドをgradleで行う:実践編2:静的ファイルの圧縮 - 文系プログラマによるTIPSブログ
javaのビルドをgradleで行う:実践編3:jspの文字列置換(ReplaceTokens) - 文系プログラマによるTIPSブログ
javaのビルドをgradleで行う:実践編4:あれどうやるの?の疑問と自己解決 - 文系プログラマによるTIPSブログ
javaのビルドをgradleで行う:実践編5:マルチプロジェクト時のprovidedCompileについて - 文系プログラマによるTIPSブログ
javaのビルドをgradleで行う:実践編6:高速に実用的な実行可能jarを生成する - 文系プログラマによるTIPSブログ