読者です 読者をやめる 読者になる 読者になる

Umi Uyuraのブログ

Titaniumを使ったスマートフォンアプリ開発を中心に、プログラミング関連の作業ログ。

React + BrowserifyプロジェクトでJS/CSS/HTMLを圧縮(Minify)する

ReactとMaterial UIを組み合わせると、それだけでBrowserifyで結合したJavaScriptファイルが1MB超えてしまうので、やっぱり圧縮とかした方が良いのかな―と思い、やり方を調べてみました。

※2015/08/03更新

Licensifyを開発された @t_wada さんから改良の連絡をいただいたので、Licensifyの最新版1.4.0をもとに内容を更新しました。

Licensify - Nodeモジュールのライセンスコメントを生成する

JSファイルを圧縮すると、ライセンスが記載されているコメントが消えてしまうという問題があるということで、本題の前に、Browserifyと組み合わせて、読み込んだNodeモジュールのライセンスコメントを生成してくれる Licensify を試しておくことにしました。

インストールはnpmから。

$ npm install licensify --save-dev

使い方は簡単で、Browserify実行時に -p licensify を加えてあげるだけで、生成されたJSファイルの先頭に、モジュールとライセンスについてのコメントを付与してくれます。

$ $(npm bin)/browserify -t babelify src/app.jsx -p licensify -o build/app.js

生成されるコメントは、以下のようなものでした。

※2015/08/03更新

生成されたコメントをLicensify 1.4.0のものに差し替えました。

各モジュールのホームページURLが出力されるようになった他、最下部に This header is generated by licensify (https://github.com/twada/licensify) というコメントが入るようになりました。この変更の効果については後述するUglifyJSの説明にて。

/**
 * Modules in this bundle
 * 
 * my-react-boilerplate:
 *   license: MIT
 *   author: Umi Uyura
 *   version: 0.0.1
 * 
 * process:
 *   author: Roman Shtylman <shtylman@gmail.com>
 *   maintainers: coolaj86 <coolaj86@gmail.com>, defunctzombie <shtylman@gmail.com>
 *   homepage: https://github.com/shtylman/node-process#readme
 *   version: 0.11.1
 * 
 * react:
 *   license: BSD-3-Clause
 *   maintainers: zpao <paul@oshannessy.com>, jeffmo <jeff@anafx.com>, sebmarkbage <sebastian@calyptus.eu>, spicyj <ben@benalpert.com>
 *   homepage: https://github.com/facebook/react/tree/master/npm-react
 *   version: 0.13.3
 * 
 * This header is generated by licensify (https://github.com/twada/licensify)
 */

UglifyJS/Clean-CSS/HTML Minifier - JS/CSS/HTMLを圧縮する

本題の方ですが、圧縮のためのツールは探すとゾクゾクと出てくるのですが、私は以下のものを使うことにしました。

対象 ツール
JavaScript UglifyJS 2
CSS Clean-CSS
HTML HTML minifier

理由としては、JSの圧縮ではUglifyJSが良く見かけたのと、HTML minifier内でHTMLに含まれるJSとCSSを圧縮するのにUglifyJSとClean-CSSを使っているようだったので、相性が良さそうかなと思ったという程度です。

あと、JSに関しては Uglifyify を使うことでBrowserifyと連携して圧縮することもできそうだったのですが、圧縮が必要なのは主に公開のタイミングだと考えて、CSSやHTML同様、単独のツールの方を入れることにしました。

これらも全てnpmでインストールできます。

$ npm install uglify-js --save-dev
$ npm install clean-css --save-dev
$ npm install html-minifier --save-dev

圧縮が必要になるのはページを公開するタイミングなので、プロジェクト内にそれ用の public フォルダを用意して、そこに諸々出力する感じにしています。

UglifyJS

UglifyJSは、正確にはUglifyJS 2になっているようです。

JavaScriptを圧縮するにあたり1つ問題だったのが、先に生成したライセンスコメントの扱いです。

UglifyJSは、デフォルトではコメントを除去してしまうため、ライセンスコメントは残すようにしたいのです。

そのために --comments というオプションがあるようですが、これは基本的にはJSDocスタイルの @license もしくは @preserve が含まれるコメントを残すという動きのようでした。

--comments all というオプションもありますが、これは全てのコメントを残してしまうため、これはこれでやり過ぎです。

もう一つのオプションとして、 --commentsJavaScript正規表現を渡すことで、それに該当するコメントを残すということができるようでした。

そこで、Licensifyが出力するコメントにある Modules in this bundle を指定することで、それ以外のコメントだけ除去することができました。

$ uglifyjs build/app.js -o public/build/app.js --comments '/Modules in this bundle/'

※2015/08/03更新

@t_wada さんから連絡をいただき、私の当初の方法では今後動かなくなってしまう可能性があるということで、Licensifyの出力に手を加えてくださいました。

先に示した出力例の通り、最後尾に generated by ... というコメントが入るようになったので、UglifyJSへ以下のように指定することで、ライセンスヘッダのみを残して圧縮することができます。

$ uglifyjs build/app.js -o public/build/app.js --comments '/generated by licensify/'

@t_wada さん、ありがとうございました!

Clean-CSS

Clean-CSSに関しては、特に迷わず。

複数のファイルを結合したりいろいろできるようですが、現状はそこまでの規模でもないため、シンプルに済みました。

$ cleancss -o public/style/app.css style/app.css

HTML Minifier

初期状態では、あまり圧縮されないようだったので、いくつかオプションを設定することにしました。

オプションについてはコマンドの引数としても渡すことができますが、種類が豊富なので、別途設定ファイルを用意して、それを利用することもできるようです。

私は以下のオプションを変更しました。

オプション 意味
removeComments false → true コメントを除去する
collapseWhitespace false → true 空白を除去する
minifyJS false → true JavaScriptを圧縮する
minifyCSS false → true CSSを圧縮する

設定ファイルは以下のようになりました。

{
  "removeComments": true,
  "removeCommentsFromCDATA": false,
  "removeCDATASectionsFromCDATA": false,
  "collapseWhitespace": true,
  "conservativeCollapse": false,
  "collapseBooleanAttributes": false,
  "removeAttributeQuotes": false,
  "removeRedundantAttributes": false,
  "useShortDoctype": false,
  "removeEmptyAttributes": false,
  "removeOptionalTags": false,
  "removeEmptyElements": false,
  "lint": false,
  "keepClosingSlash": false,
  "caseSensitive": true,
  "minifyJS": true,
  "minifyCSS": true,
  "ignoreCustomComments": [],
  "processScripts": []
}

設定ファイルは -c で指定します。

$ html-minifier -c html-minifier.conf index.html -o public/index.html

設定ファイルのひな形は HTML minifierのGitHubリポジトリ に含まれています。

まとめ

このあたりをまとめて、 npm script も設定したものをアップ。

umi-uyura/my-react-boilerplate

Reactを使ったちょっとしたツールなどの土台レベルなら、このくらいで良さそうですが、ファイル数が多くなってくると大変になので、そうなってきたらGulpなどのタスク管理系が必要になりそう。

参考

開眼!  JavaScript ―言語仕様から学ぶJavaScriptの本質

開眼! JavaScript ―言語仕様から学ぶJavaScriptの本質