Dropwizard アプリケーションで、Fat jar の作成前に、
JavaScript、css の圧縮、結合を行いたくなったので、minify-maven-plugin使ってみました。
実施したことを記載します。


参考


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-staticminify-group-xyz 2つ excution 定義を作成しました。

  • bundleConfiguration で、対象ファイルの結合順番を指定
    minify-group-static で、bundleConfiguration指定していますが、
    この json ファイルで、ファイルの結合順番を指定でき、 files指定した順番で結合されるようになります。
    ちなみに、ファイルパスは、cssSourceDirjsSourceDir指定したディレクトリからの、
    相対パスで記載すればよいようです。
    出力対象のファイルは、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 に挙がっているものもありますので、確認はしたほうがいいです。


TODO

profile を指定することで、圧縮、結合の ON/OFF 切り替えできるようにしましたが、合わせてプログラム側でも、参照する javascript、css を切り替える必要があります。
maven 側での指定で実装も切りわかるように、できればよりよい気がしますので、そのうちそのあたりも設定してみようと思います。
以上です。

コメント