Dropwizard アプリケーションで、Fat jar の作成前に、
JavaScript、css の圧縮、結合を行いたくなったので、minify-maven-plugin
を使ってみました。
実施したことを記載します。
参考
-
Minify Maven Plugin - Introduction
Minify Maven Plugin の Document ページ
yui-compressor-plugin との機能の違いについて
似たような用途の maven-plugin として、davidB/yuicompressor-maven-plugin: maven’s plugin to compress (Minify / Ofuscate / Aggregate) Javascript files and CSS files using YUI Compressor があります。
yui-compressor-plugin
についても調べる機会があったので、記載します。
-
yui-compressor-plugin
は gzip 作成まで実施できる
minify-maven-plugin
には gzip を作成する機能はありません。gzip feature request · Issue #90 · samaxes/minify-maven-plugin という Issue が作成されていますが、実装はされない雰囲気が漂います。
事前に gzip 化 しておくと、HTTP サーバー側での gzip 化が不要になるため、サーバーのCPU負荷を軽減できます。
HTTPサーバーとして、Apache を使用している場合の HTTPサーバー側での圧縮設定と、事前圧縮での設定方法の比較は以下の記事がわかりやすかったです。
gzip 圧縮によるサイトパフォーマンスを向上させる方法 | murashun.jp -
ファイル結合時の順番指定、ファイル単位での除外指定等 は、
minify-maven-plugin
のほうが設定しやすい
minify-maven-plugin
は json ファイルでファイルの圧縮定義を記載できるので、細かい調整はyui-compressor-plugin
よりもやりやすいです。 -
minify-maven-plugin
は JavaScript の Complessor として Closure Compiler が使える
個人的には、それほどこだわりはありませんが、yui-compressor-plugin
はyui-compressor
一択です。
上記の違いから、細かい指定なしで、gzip 作成まで、一括で実施したい場合は、yui-compressor-plugin
を使う。
gzip 圧縮はしない、または、別途行い、細かいファイル指定を実施したい場合は、minify-maven-plugin
を使うことになるかと思います。
実現したいこと
実現したいことは以下になります。
-
ディレクトリごとに、圧縮、結合の ON/OFF を切り替えたい。
src/main/resource/static ディレクトリ配下 圧縮、結合ともに行う、 src/main/resource/xyz ディレクトリ配下は、圧縮のみ行うようにしたいです。 -
開発時は、圧縮、結合ともに OFF にしたい。 開発時は、デバッグの兼ね合いで、圧縮、結合ともに OFF にしたいです。
-
圧縮、結合対象の、js、css の順序を指定したい。
jquery と、jquery の plugin が圧縮、結合対象になっているため、
定義順序によっては、js エラーになってしまいます。
jquery > 1番目、
jquery の plugin > 2番目
で圧縮したいです。
実施したこと
以下の記述を pom.xml に追記しました。
<profiles>
<profile>
<id>PRODUCTION</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<!-- resources 定義 -->
<resources>
<resource>
<filtering>false</filtering>
<directory>src/main/resources</directory>
<excludes>
<exclude>**/*.css</exclude>
<exclude>**/*.js</exclude>
</excludes>
</resource>
<resource>
<filtering>false</filtering>
<directory>src/main/java</directory>
<includes>
<include>**</include>
</includes>
<excludes>
<exclude>**/*.java</exclude>
<exclude>**/*.css</exclude>
<exclude>**/*.js</exclude>
</excludes>
</resource>
</resources>
<plugins>
<!-- minify js and css -->
<plugin>
<groupId>com.samaxes.maven</groupId>
<artifactId>minify-maven-plugin</artifactId>
<version>1.7.6</version>
<executions>
<execution>
<id>minify-group-static</id>
<phase>prepare-package</phase>
<goals>
<goal>minify</goal>
</goals>
<configuration>
<webappSourceDir>${basedir}/src/main/resources</webappSourceDir>
<webappTargetDir>${project.build.directory}/classes</webappTargetDir>
<cssSourceDir>static</cssSourceDir>
<jsSourceDir>static</jsSourceDir>
<skipMerge>false</skipMerge>
<nosuffix>true</nosuffix>
<bundleConfiguration>${basedir}/src/main/resources/static-bundles.json
</bundleConfiguration>
</configuration>
</execution>
<execution>
<id>minify-group-xyz</id>
<phase>prepare-package</phase>
<goals>
<goal>minify</goal>
</goals>
<configuration>
<webappSourceDir>${basedir}/src/main/resources</webappSourceDir>
<webappTargetDir>${project.build.directory}/classes</webappTargetDir>
<cssSourceDir>xyz</cssSourceDir>
<jsSourceDir>xyz</jsSourceDir>
<skipMerge>true</skipMerge>
<nosuffix>true</nosuffix>
<cssSourceIncludes>
<cssSourceInclude>**/*.css</cssSourceInclude>
</cssSourceIncludes>
<cssSourceExcludes>
<cssSourceExclude>**/*.min.css</cssSourceExclude>
</cssSourceExcludes>
<jsSourceIncludes>
<jsSourceInclude>**/*.js</jsSourceInclude>
</jsSourceIncludes>
<jsSourceExcludes>
<jsSourceExclude>**/*.min.js</jsSourceExclude>
</jsSourceExcludes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
pom.xml の記載について説明します。
-
profile で PRODUCTION を指定
これで、mvn -PPRODUCTION
を指定した際に、
Javascript、css の圧縮、結合が実行されるようになります。 -
resources 定義について
javascript、css のソースディレクトリに対して、<excludes>
設定しています。
これは、minify タスクで、圧縮、結合したファイルが配置されるためです。 -
phase は、prepare-package を指定
Fat jar の作成に使用するmaven-shade-plugin
の phase は package を指定しています。
このタスクよりも前に実行したかったので、prepare-package を指定しました。 -
plugin の execution 定義について
ディレクトリごとに、圧縮、結合の ON/OFF を切り替えたかったので、
minify-group-static
、minify-group-xyz
の 2つ excution 定義を作成しました。 -
bundleConfiguration で、対象ファイルの結合順番を指定
minify-group-static
で、bundleConfiguration
を指定していますが、
この json ファイルで、ファイルの結合順番を指定でき、files
で指定した順番で結合されるようになります。
ちなみに、ファイルパスは、cssSourceDir
、jsSourceDir
で指定したディレクトリからの、
相対パスで記載すればよいようです。
出力対象のファイルは、webappTargetDir
配下にcssSourceDir
で指定したディレクトリができるのですが、
その直下に出力されます。
{
"bundles": [
{
"type": "css",
"name": "static-combined.css",
"files": [
"bootstrap/css/bootstrap.css",
"fonts/font-awesome/css/font-awesome.css",
"css/animations.css",
"css/style.css",
"css/custom.css",
"css/bootstrap-custom.css"
]
},
{
"type": "js",
"name": "static-combined.js",
"files": [
"plugins/jquery.min.js",
"plugins/jquery.tile.min.js",
"bootstrap/js/bootstrap.min.js",
"js/libs/knockout-3.3.0.js",
"plugins/modernizr.js",
"plugins/isotope/isotope.pkgd.min.js",
"plugins/jquery.backstretch.min.js",
"plugins/jquery.appear.js",
"js/libs/d3.js",
"js/libs/d3.layout.cloud.js",
"js/apps/utils.js",
"js/custom.js"
]
}
]
}
使用上の注意点
実際に使用してみて、以下トラブルが発生したので、記載しておきます。
Closure Compiler が 解釈できない JavaScript が圧縮対象となると、エラーが発生する
ECMA2016 構文の JavaScript を圧縮対象としたり、ブラウザが解釈できる JavaScript でも 構文としてトリッキーな書き方をしているものがあると、Closure Compiler が構文を解釈できずに、エラーになります。対象ファイルは圧縮をあきらめて、除外するか Closure Compiler が解釈できる形式に修正する必要があります。
同名ファイルで上書き後、再度圧縮すると、構文エラーが発生する場合がある
圧縮前ファイル と 圧縮後ファイルを同一名称にして、圧縮をリトライすると、圧縮後のファイルを Closure Compiter が解釈できずに、エラーになります。
自分自身で圧縮したものの構文を解釈できないのかという感じがしますが、そもそもそのような使い方は想定してないと思いますので、そのような使い方をした私が悪いです。
Yui Compressor の バグ で 圧縮後のCSS が壊れる場合がある
CSS の書き方によっては、圧縮後の CSS の内容が書き換わります。
既知の問題はissue に挙がっているものもありますので、確認はしたほうがいいです。
-
“em” is missing in compressed file · Issue #108 · yui/yuicompressor
1.0em
と記載すると、圧縮後に1.0
になります。1em
と書けば問題ありません。 -
IE backslash9 (\9) hack is not handled properly · Issue #104 · yui/yuicompressor
IE hack の css 記述が欠落します。 これは、開発 Version では マージされており、Github から clone して build すると解消される問題かもしれません。
pom 依存関係で、download される Version 2.4.8 ではこのバグは発生します。
回避方法は、IE 9 は切り捨てる! かと思います。
TODO
profile を指定することで、圧縮、結合の ON/OFF 切り替えできるようにしましたが、合わせてプログラム側でも、参照する javascript、css を切り替える必要があります。
maven 側での指定で実装も切りわかるように、できればよりよい気がしますので、そのうちそのあたりも設定してみようと思います。
以上です。
コメント