LESS を Maven プラグインでコンパイル - lesscss-maven-plugin を使ってみる

最近になって LESS なる CSS 拡張メタ言語 があることを知った。

LESS に関する細かい話は省略するとして、LESS はブラウザで動的にコンパイルしてスタイルに反映することができる。
ただ、あまりブラウザであれこれやり過ぎるとレンダリングが遅延して UX が損なわれてしまう可能性もあるので、サーバでできる部分(コンパイル)は極力サーバでやっておくべきだと思う。

Node.js なんかだとサーバサイドでの動的コンパイルも可能*1なようだけど、どうせなら静的コンテンツとして扱えるように事前にコンパイルしたいところ。

ということで、Maven 大好きな自分としては「Maven でやってしまえば開発者もいちいち LESS のコンパイルのこと意識しなくてもいいよね!」と考えるわけですね。

プラグインを探してみる

Google 先生に聞いてみたところ、なんかいろいろと似たようなのが湧いて出てきた。
その中でも、Central Repository にも上がっていて、「公式」と謳われている org.lesscss:lesscss-maven-plugin を使うのが一番確実っぽい。
lesscss-maven-plugin は、元々 Codehaus のプロジェクトだったものが lesscss.org の公式 Maven プラグインとして採用されたプロジェクトのよう。

ただ、この lesscss-maven-plugin、せっかく「公式」と謳われているのに検索順位が低い。残念…。

lesscss-maven-plugin を使ってみる

基本的な使い方は 公式の GitHub を見ればいいと思う。

公式の書き方だとちょっとイケてないので自分なりに記述することにする。

lesscss-maven-plugin の設定
<project>
  ...
  <build>
    ...
    <plugins>
      ...
      <plugin>
        <groupId>org.lesscss</groupId>
        <artifactId>lesscss-maven-plugin</artifactId>
        <version>1.3.0</version>
        <executions>
          <execution>
            <goals>
              <goal>compile</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <outputDirectory>${project.build.directory}/.generated/webapp/css</outputDirectory>
        </configuration>
      </plugin>
      ...

コンパイルされた LESS (=css) は自動生成ファイル用のディレクトリに出力。
compile ゴールはデフォルトでは process-sources フェーズにマッピングされている。

maven-war-plugin の設定

lesscss-maven-plugin の設定だけでは war に含めることができないので、maven-war-plugin の設定も合わせて行う。

      ...
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.1.1</version>
        <configuration>
          <webResources>
            <resource>
              <directory>${project.build.directory}/.generated/webapp</directory>
            </resource>
          </webResources>
        </configuration>
      </plugin>
      ...

webResources で、自動生成ファイルも war に含めるように設定。

less ファイルを適当に用意

less ファイルの所定のディレクトリは src/main/less となってる。
src/main/less/sample.less を適当に作成。

@color: #ffffff;
@bgcolor: #000000;
@bordercolor: #7f7f7f;
@precolor: #404040;
.rounded-corners (@radius: 8px) {
	border-radius: @radius;
	-webkit-border-radius: @radius;
	-moz-border-radius: @radius;
}
body {
	color: @color;
	background-color: @bgcolor;
}
pre {
	.rounded-corners();
	background-color: @precolor;
	border-style: dotted;
	border-width: medium;
	border-color: @bordercolor;
	padding: 7px;
	margin: 5px;
}
コンパイルしてみる
$ mvn lesscss:compile
  ...
  [INFO] ------------------------------------------------------------------------
  [INFO] Building lesscss-maven-plugin-sample Maven Webapp 1.0-SNAPSHOT
  [INFO] ------------------------------------------------------------------------
  [INFO]
  [INFO] --- lesscss-maven-plugin:1.3.0:compile (default-cli) @ lesscss-maven-plugin-sample ---
  [INFO] Compiling LESS source: sample.less...
  [  Envjs/1.6 (Rhino; U; Windows 7 x86 6.1; en-US; rv:1.7.0.rc2) Resig/20070309 PilotFish/1.2.13  ]
  [INFO] Compilation finished in 1782 ms
  ...
$ cat target/.generated/webapp/css/sample.css
body {
  color: #ffffff;
  background-color: #000000;
}
pre {
  border-radius: 8px;
  -webkit-border-radius: 8px;
  -moz-border-radius: 8px;
  background-color: #404040;
  border-style: dotted;
  border-width: medium;
  border-color: #7f7f7f;
  padding: 7px;
  margin: 5px;
}

ちゃんと CSS ができる。

war を作ってみる
$ mvn package
  ...
$ unzip -l target/lesscss-maven-plugin-sample.war *.css
  Archive:  target/lesscss-maven-plugin-sample.war
    Length      Date    Time    Name
  ---------  ---------- -----   ----
        276  xx-xx-xxxx xx:xx   css/sample.css
  ---------                     -------
        276                     1 file

ちゃんと war にも含まれまる。

サンプル置き場

今回作成しているサンプルの完全なコードは GitHub に上げてみた。
動かす場合は、

git clone https://github.com/tm-senda/lesscss-maven-plugin-sample.git
cd lesscss-maven-plugin-sample
mvn package run:jetty

として*2http://localhost:9080/index.jsp にアクセスするだけ。
Eclipse でも m2e と m2e-wtp が入っていればビルドして WTP で起動するだけで、特に意識することなく実行できるようになっている。と思う。

lesscss-maven-plugin における現状 (version:1.3.0) の問題点

こんな感じで便利な lesscss-maven-plugin だけど、一部使い勝手に支障のある部分がある。

m2e-wtp が自動生成されたファイルの更新を検知してくれない

less ファイルを保存してビルドすると、less ファイルのコンパイルはちゃんと走ってくれるのだけど、m2e-wtp がそれを検知できていないようで、コンパイルされた css ファイルを ${project.build.directory}/m2e-wtp/web-resources 以下にコピーしてくれない…。
対応としては、

  • 自動生成ファイルを別ディレクトリにするのをあきらめて、src/main/webapp 以下にコンパイルされるようにする
  • pom.xml を 空編集 -> 保存 するなどしてプロジェクトを刺激する

など。釈然としない…。

LESS コンパイル時のファイル排他ロックが残念

前記の問題点があったので Eclipse でのホット・リロードをあきらめて、jetty で実行するようにしてみたところ発覚。
jetty は静的ファイルを read-only で開いたままにしているのに対し、lesscss-maven-plugin で LESS をコンパイルする時に書き込み対象ファイルの完全なロックを取得しようとするため、

[ERROR] C:\Users\tm-senda\git\lesscss-maven-plugin-sample\src\main\less\sample.less [0:0]: Error compiling LESS source
java.io.FileNotFoundException: C:\Users\tm-senda\git\lesscss-maven-plugin-sample\target\.generated\webapp\css\sample.css (要求された操作はユーザー マップ セクションで開いたファイルでは実行できません。)
        at java.io.FileOutputStream.open(Native Method)
        at java.io.FileOutputStream.(FileOutputStream.java:212)
        ...

と、残念なことになってしまう。
これはプラグイン側の対応が必要…。

ファイルのエンコーディング・サポートが残念

出力時のエンコーディング指定はサポートされているのだけど、入力ファイル (less ファイル) のエンコーディング指定がサポートされていない*3
なので、出力エンコーディングがシステム・デフォルトのエンコーディングと異なる場合、日本語などが含まれていれば文字化けしてしまう。
これもプラグインの修正が必要…。

まとめ

ということで、Maven を使っているならば、*4意外なほど簡単に、特別なツールや環境を用意する必要もなく、LESS のサーバサイド・コンパイルを実現することができます。
こういったプラグインを利用していくことで、クライアントサイド・コンパイルが嫌われるような開発でも LESS を採用しやすくなってくるのではないでしょうか。

*1:5509.me

*2:mvn に指定するライフサイクルは package じゃなくても process-sources フェーズが実行されればなんでも OK

*3:入力ファイルのエンコーディンはシステム・デフォルトとなる

*4:Gradle でも同様のプラグインがあるっぽいけど今回は割愛