文系プログラマによるTIPSブログ

文系プログラマ脳の私が開発現場で学んだ事やプログラミングのTIPSをまとめています。

【化石】antでjsとcssのminifyを再帰的にファイル毎に行う【原始的】

プロジェクトの都合上どうしてもantになってしまう場合の対処法です〜


f:id:treeapps:20180426142529p:plain

さて、今日は旧石器時代のビルドのお話です。
最近私はソースコード全般が非常に古いプロジェクトを担当しており、そのプロジェクトのビルドがantで行われています。

このantは非常に歴史が古く、xml地獄の冗長なビルドシステムで、当然そう簡単にjsのminify等は行えません。今回は化石のようなantを使って、意地でもjsとcssのminifyを行ってみたいと思います。

大前提

前提は以下の通りです。

  • antからjsとcssのminifyが行える事。
  • ライブラリを使ってもよい。但しant taskの実装があること。
  • combineはせず、再帰的にファイル毎にminifyする。

この中で、combineしない件が実は曲者で、標準で行えるものはほとんどありません。

ライブラリの選定

候補は以下があります。

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でリフレッシュします。
f:id:treeapps:20140128000058p:plain
こんな感じになります。

どうやら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」が生成されます。
f:id:treeapps:20140128001805p:plain

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のフォルダ構成

続いてフォルダ構成を確認します。
f:id:treeapps:20140128003425p:plain
上図のように、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の出力先も含め、最終的なフォルダ構成は以下のようになっています。
f:id:treeapps:20140128005714p:plain

雑感

( #^ω^)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ブログ