PDFJS のサイズが大きすぎて minify が辛い
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
◆ uglifyjs が優秀
◆ TICKER は中で uglifyjs 使った上で packer 的な圧縮かけてる
◆ packer は js 構文を解釈してないみたいでセミコロン補われない
◆ google-closure-compiler はメモリ食いすぎて大きいファイルは無理
◆ ADVANCED はコードが壊れる
◆ TICKER は中で uglifyjs 使った上で packer 的な圧縮かけてる
◆ packer は js 構文を解釈してないみたいでセミコロン補われない
◆ google-closure-compiler はメモリ食いすぎて大きいファイルは無理
◆ ADVANCED はコードが壊れる
前回の続きです
zip ファイルの状態だと
pdf.js → 85KB
pdf.worker.js → 296KB
とまあちょっと大きめなライブラリってくらいです
でも 解凍してみたら
pdf.js → 366KB
pdf.worker.js → 1.37MB
サイズ大きすぎ!
これが原因か pdf.js をロードしてからはページロードが重いなぁと思うようになりました
さすがに pdf.js をデバッグ実行でみることはないでしょうし minify 版をロードするようにしよう としたのですが
そういえば .min.js がないです
だいたいのライブラリにはついてそうなものですけど pdf.js の pre-build 版にはついてません
やっぱり有名なのは Google の closure compiler
YUI は昔はよく聞いたけど最近の日本語の比較ページではほとんど載っていません
海外の minify ツール紹介ページならけっこう見かけました
それと よくも悪くもない普通くらいと思っていた uglifyjs2 はかなり有名なトップクラスぽい感じになってます
昔は定番だった packer は一応まだ比較として出される程度にはあるようです
あと初めて聞いたのですが TICKER というのがあるみたい
http://qiita.com/akira_/items/c47b57de4f338fff95ad
圧縮率が他よりかなり優れてるとか
とりあえず
を使ってみます
と言ってもオープンソースじゃないみたいで公式サイトにファイルをドロップするしか方法がないみたい
http://solufa.io/ticker/
ツールをダウンロードすることもできません
solufa を minify するために作られたもの らしいので solufa の方のリポジトリに混ざってないか調べてみたのですが ヒットなしです
というか solufa と言うもの自体 公式サイトのデザインはいい感じですが リポジトリの Star や Issues がほぼないし README もないし 更新も数ヶ月されてないし かなりマイナーどころみたい
開発者が日本人みたいなので仕方ないかも?
なんにしろ TICKER は web 上でサーバにアップロードするしかないようです
すると
エラーになった!
ファイルサイズが大きすぎるみたい
pdf.js の方は無事成功したのですが pdf.worker.js の方はダメでした
とりあえず minify できた pdf.js のサイズを見てみると 99.47KB
かなり減ってます
packer 系で
:
:
:
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory
メモリ不足!!
タスクマネージャを見てると 最初は 200MB 前後をうろうろしていたのに急に 1GB くらいにすごい勢いで メモリ使用量が上がっていきます
調べてみると v8 オプションの
--max_old_space_size と --max_executable_size がメモリサイズみたい
google-closure-compiler-js に対してこのオプションをつけても不正なオプションと言われます
Error: java.lang.RuntimeException: Unhandled flag: max_old_space_size
なんで Java なんだろう
Java のランタイムをそのまま JavaScript に移植してる?
とりあえず node の方の引数にしないとダメなので内部的に nodejs を呼び出しているところにつけます
私は Windows 環境なので google-closure-compiler-js.cmd ファイルを編集します
このファイルの場所はいろいろありますが
nodejs 通常のもので -g でインストールしていれば AppData\Roaming\npm の中にあるはずです
nodist で -g だと nodist のフォルダの中の bin とかその辺です
-g がないときはカレントディレクトリの node_modules\.bin の中です
ファイルはこんなのでした
こういう感じに設定
node.exe が cmd ファイルと同じところにないのになぜか if 文が true のほうが実行されてました
ググってみると 8192 とか指定していて いかにも 4GB や 8GB が設定できそうだったのですが 2 GiB を超えた指定をすると動きません
もう少しググってるとこんなページが
http://stackoverflow.com/questions/38587346/max-old-space-size-set-to-4gb-actually-limits-to-2gb
V8 のデフォルトでは 32bit 環境だと 512MB で 64bit 環境だと 1GB
--max-old-space-size を指定すれば最大で 32bit 環境は 1GB まで 64bit 環境では 1.7GB まであげられるようです
4GB や 8GB に変更してる人はどうなってるでしょう
nodejs のバージョンは新しいの使ってるはずなのですけど
気になったので 別のパソコンでも試してみると
これまで 使っていたパソコンでは 2GiB 以上を指定すると 実行直後にエラーになっていました
ですが 別のパソコンでは 4000 でも普通に読み込みが行われています
ただタスクマネージャで見る限りでは 4GB どころか 3GB に達する前にメモリ不足で落ちます
気になったので少し調べてみます
これで v8 オプションがでるらしい
:
:
:
ふむふむ
なるほど
全く説明してないですね
ググってみると 2012 年の記事ですがこういうのがありました
http://erikcorry.blogspot.jp/2012/11/memory-management-flags-in-v8.html
いきなりみたことない --max_new_space_size というのがあります
node --v8-options ではみつからないので node では設定できないか 消えたものかな
内容は
通常のオブジェクトが作られる場所で よく GC が回収してくれていい感じに最適化される場所 みたい?
サイズは自動決定で v8 の再コンパイルしないと最大値を増やせないようなので node のオプションにはいらないのかな
--max_old_space_size は 32 bit は 700MB で 64bit は 1400MB とさっきと微妙にサイズが違います
もっと増やせるようで最大値は不明ぽいです
さっきのページとは違っていて結局どうなのかよくわかりません
old ってなんだろうと思ってたのですが new と対応してたようです
new が GC ですぐ消される方みたいなのでこっちはあまり GC されず残り続けるメモリ空間だと思います
たぶん
--max_executable_size はヒープスプレー攻撃から守るためのセキュリティのための制限で この値は基本増やさないほうがいいみたい
といってもクライアントサイドでの問題なので node とかサーバサイドなら気にしなくていいものだとか
結局 max_old_space_size と一緒にこれも設定しないとメモリ使える量は増えないのかはわかりませんでした
上の方に書いた Qiita のページでは packer もそれなりに圧縮効率が高いので 試してみます
といっても ほとんどの minify ツールって スペースや改行を消したり 変数名を短くしたり程度なのに packer は元の形を維持せず暗号化みたいなことになっています
文字数を減らすのを重視していて JavaScript で処理した結果 もともとのソースコードの文字列ができて それを eval で実行するものです
処理と言っても テキスト操作するだけなので一瞬です
昔のネットワーク速度で大きなファイルを通信する時間に比べれば ほんの僅かな処理時間だと思います
npm にあったので
とやってみたらコンパイルエラーになりました
ただダウンロードするだけじゃなくてコンパイル必要なタイプみたいです
Windows 環境だと面倒なので 別の方法を探します
公式サイトには .net のアプリケーションがありました
http://dean.edwards.name/download/
.NET 1.1 向けってすごく古いです
使ってみると ロードしたのをテキストボックスに表示するタイプ
大丈夫なのかなぁ と思いつつやってみると 意外にも問題なく動きました
考えてみると ブラウザならともかく Windows ソフトでなら 1MB 程度で落ちることはそうあるものじゃないですよね
ただ重大な問題がありました
動かない!!
原因はわからないですが よくわからないエラーでした
eval してるので devtools にも詳しいことがでてなかったです
調べるのも面倒なので とりあえず スキップします
2 ですがコマンドは 2 なしです
とりあえず -c -m のオプションをつければいいみたい
いろいろ警告でていますが 問題なく動きました
ちゃんと JavaScript として解析して 使ってない変数を捨てたりしてるんですねー
唯一 pdf.worker.js を動く形で minify できたのは uglifyjs2 だけでした
人気ナンバーワンは伊達ではないですね
まずは pdf.worker.js で minify できたけど動かなかった packer
長くなってます
元が短いときは minify じゃないですね
最終的に eval される文字列はこうなりました
セミコロンがない!
単純にホワイトスペースを除去したテキストを作ってるだけで構文解析とかしてないみたいで minify するときに必要なセミコロンがおぎなわれていません
セミコロンなし派と相性が悪いだけでなく 実際多くのコードが動かないと思います
というのもセミコロン書く派の人でも 書き忘れた箇所があってもほぼ動くので 100% セミコロンが正しく打たれているコードは意外と少ないです
ネットでコード見てても このコードセミコロン抜けてると思うことがそこそこ見かけます
これが今ではほとんど使われない理由のひとつでもありそうです
次は google-closure-compiler
おぉっ
すごくシンプルになりました
さすが SIMPLE
valueOf とか toString 書き換えたり プロキシしたりとか色々やってるとちょっと怖いですが google 製だしその辺はきっと大丈夫だよね
さらに圧縮率の高い ADVANCED もあるので試してみます
関数すら呼び出されません
インライン展開されています
「!0」 は 「!functin(){}()」 の結果が true になるのでそこを合わせるためです
次に TICKER
packer 同様 元よりは長いです
でも packer に比べると 短いです
eval される文字列はこれです
一般的な minify 済みです
packer はこうでした
minify 済みに packer の改良型の圧縮をするので圧縮率が高いようです
最後に uglifyjs
あれ? さっきも見たような……
TICKER と一緒です
もしかして TICKER って内部で uglifyjs 適用してから独自の圧縮してる??
これは短いからたまたまの可能性もあります
なので pdf.js を圧縮したもの比較してみました
すると
になるような違いはあったものの ほぼ完全に一緒でした
この僅かな違いはたぶん uglifyjs のオプションで変更できるものだと思います
もしかして ソース出さずにオンラインのみなのも 圧縮率一番と言いつつもそのほとんどを uglifyjs に任せてるのを隠したいからだったり?
でも公式サイトに minify と TICKER の比較が並んでるので uglifyjs の minify が minify のことで そこから TICKER でさらにこれだけ減らせるよ と言ってるようにも考えられます
まぁ TICKER の圧縮率の謎もわかりましたし アップロードが嫌なら uglifyjs のあとで packer かければ セミコロン問題もないしそこそこ圧縮されて良いんじゃないでしょうか
コードはこれ
まずは closure-compiler の SIMPLE
結果も問題なしです
次に ADVANCED
んん?
abcd が a になってます
なのに同じキーを参照する別のところは abcd のままです
もちろんこれじゃ動きません
ADVANCED は使わない方がよさそう
最後に uglifyjs
こっちも問題なし
closure-compiler よりちょっと長いです
pdf.js のときは uglifyjs のほうが圧縮率よかったので コード次第みたいです
ただ こっちはメモリ消費がそれほどないので こっちのほうがよさそう
uglifyjs2 → google-closure-compiler(SIMPLE)
今回試したものでは その他は問題あるのが多いです
TICKER は内部で uglifyjs を使ってます
zip ファイルの状態だと
pdf.js → 85KB
pdf.worker.js → 296KB
とまあちょっと大きめなライブラリってくらいです
でも 解凍してみたら
pdf.js → 366KB
pdf.worker.js → 1.37MB
サイズ大きすぎ!
これが原因か pdf.js をロードしてからはページロードが重いなぁと思うようになりました
さすがに pdf.js をデバッグ実行でみることはないでしょうし minify 版をロードするようにしよう としたのですが
そういえば .min.js がないです
だいたいのライブラリにはついてそうなものですけど pdf.js の pre-build 版にはついてません
minify ツール
無いなら自分で作るしかないので 適当に minify ツールを調べてみましたやっぱり有名なのは Google の closure compiler
YUI は昔はよく聞いたけど最近の日本語の比較ページではほとんど載っていません
海外の minify ツール紹介ページならけっこう見かけました
それと よくも悪くもない普通くらいと思っていた uglifyjs2 はかなり有名なトップクラスぽい感じになってます
昔は定番だった packer は一応まだ比較として出される程度にはあるようです
あと初めて聞いたのですが TICKER というのがあるみたい
http://qiita.com/akira_/items/c47b57de4f338fff95ad
圧縮率が他よりかなり優れてるとか
とりあえず
- google closure compiler
- uglifyjs2
- packer
- TICKER
を使ってみます
TICKER
1MB 超えてるファイルなので出来る限り小さくしたいのでまずは TICKER を調べてみましたと言ってもオープンソースじゃないみたいで公式サイトにファイルをドロップするしか方法がないみたい
http://solufa.io/ticker/
ツールをダウンロードすることもできません
solufa を minify するために作られたもの らしいので solufa の方のリポジトリに混ざってないか調べてみたのですが ヒットなしです
というか solufa と言うもの自体 公式サイトのデザインはいい感じですが リポジトリの Star や Issues がほぼないし README もないし 更新も数ヶ月されてないし かなりマイナーどころみたい
開発者が日本人みたいなので仕方ないかも?
なんにしろ TICKER は web 上でサーバにアップロードするしかないようです
使ってみる
pdf.js は OSS だし アップロードして困るものでもないので とりあえず使ってみましたすると
エラーになった!
ファイルサイズが大きすぎるみたい
pdf.js の方は無事成功したのですが pdf.worker.js の方はダメでした
とりあえず minify できた pdf.js のサイズを見てみると 99.47KB
かなり減ってます
packer 系で
eval(function(t,i,c,k,e,r){~~
という元の形を維持しないタイプでしたgoogle closure compiler
TICKER がダメなので次は closure compiler を試してみますnpm -g install google-closure-compiler-js
google-closure-compiler-js --compilationLevel=SIMPLE pdf.worker.js > pdf.worker.min.js
google-closure-compiler-js --compilationLevel=SIMPLE pdf.worker.js > pdf.worker.min.js
:
:
:
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory
メモリ不足!!
タスクマネージャを見てると 最初は 200MB 前後をうろうろしていたのに急に 1GB くらいにすごい勢いで メモリ使用量が上がっていきます
設定いじってみる
パソコン的には 4GB くらい使ってくれても全然かまわないので 最大量を調整しようと思います調べてみると v8 オプションの
--max_old_space_size と --max_executable_size がメモリサイズみたい
google-closure-compiler-js に対してこのオプションをつけても不正なオプションと言われます
Error: java.lang.RuntimeException: Unhandled flag: max_old_space_size
なんで Java なんだろう
Java のランタイムをそのまま JavaScript に移植してる?
とりあえず node の方の引数にしないとダメなので内部的に nodejs を呼び出しているところにつけます
私は Windows 環境なので google-closure-compiler-js.cmd ファイルを編集します
このファイルの場所はいろいろありますが
nodejs 通常のもので -g でインストールしていれば AppData\Roaming\npm の中にあるはずです
nodist で -g だと nodist のフォルダの中の bin とかその辺です
-g がないときはカレントディレクトリの node_modules\.bin の中です
ファイルはこんなのでした
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\node_modules\google-closure-compiler-js\cmd.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\node_modules\google-closure-compiler-js\cmd.js" %*
)
"%~dp0\node.exe" "%~dp0\node_modules\google-closure-compiler-js\cmd.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\node_modules\google-closure-compiler-js\cmd.js" %*
)
こういう感じに設定
"%~dp0\node.exe" --max_old_space_size=2000 --max_executable_size=2000 "%~dp0\node_modules\google-closure-compiler-js\cmd.js" %*
node.exe が cmd ファイルと同じところにないのになぜか if 文が true のほうが実行されてました
closure compiler じゃダメみたい
設定はしたのですが 2000 (2GB) ですググってみると 8192 とか指定していて いかにも 4GB や 8GB が設定できそうだったのですが 2 GiB を超えた指定をすると動きません
もう少しググってるとこんなページが
http://stackoverflow.com/questions/38587346/max-old-space-size-set-to-4gb-actually-limits-to-2gb
V8 のデフォルトでは 32bit 環境だと 512MB で 64bit 環境だと 1GB
--max-old-space-size を指定すれば最大で 32bit 環境は 1GB まで 64bit 環境では 1.7GB まであげられるようです
4GB や 8GB に変更してる人はどうなってるでしょう
nodejs のバージョンは新しいの使ってるはずなのですけど
気になったので 別のパソコンでも試してみると
これまで 使っていたパソコンでは 2GiB 以上を指定すると 実行直後にエラーになっていました
ですが 別のパソコンでは 4000 でも普通に読み込みが行われています
ただタスクマネージャで見る限りでは 4GB どころか 3GB に達する前にメモリ不足で落ちます
v8 options
max_old_space_size がメモリ最大量のようなので max_executable_size ってなんだったんだろう気になったので少し調べてみます
node --v8-options
これで v8 オプションがでるらしい
:
:
:
(前略)
--max_old_space_size (max size of the old space (in Mbytes))
type: int default: 0
--initial_old_space_size (initial old space size (in Mbytes))
type: int default: 0
--max_executable_size (max size of executable memory (in Mbytes))
(後略)
--max_old_space_size (max size of the old space (in Mbytes))
type: int default: 0
--initial_old_space_size (initial old space size (in Mbytes))
type: int default: 0
--max_executable_size (max size of executable memory (in Mbytes))
(後略)
ふむふむ
なるほど
全く説明してないですね
ググってみると 2012 年の記事ですがこういうのがありました
http://erikcorry.blogspot.jp/2012/11/memory-management-flags-in-v8.html
--max_new_space_size (in kBytes)
The new space is where objects are normally created. With any luck they die young and GC in this space is very fast for dead objects, so it's a nice optimization. The new space normally sizes itself automatically, and you can't increase the max size without recompiling V8, so there is not much need to tune this one. If you want to keep pauses short you can pass a value of 1024 or less to this flag, and the pauses associated with new-space GCs may be reduced from up to 30ms to more like 0-2ms. Throughput may suffer.
--max_old_space_size (in Mbytes)
This defaults to 700Mbytes on 32 bit and 1400Mbytes on 64 bit. If you want to allow V8 to grow more than this then you can set it higher. The maximum is not known. If you set this very high, then V8 will save some time (it's a space-speed tradeoff) by using more memory. File a bug if you have a use case where
a) memory use rises in an unbounded way with a high value for this flag
and
b) the program runs without out-of-memory when you set the limit lower
--max_executable_size (in Mbytes)
We normally limit this for security reasons. It's a defence-in-depth defence against heap spraying attacks. On the client, don't increase it unless you have truly gargantuan programs. On the server side, heap spraying attacks are not normally feasible so this is not so important.
いきなりみたことない --max_new_space_size というのがあります
node --v8-options ではみつからないので node では設定できないか 消えたものかな
内容は
通常のオブジェクトが作られる場所で よく GC が回収してくれていい感じに最適化される場所 みたい?
サイズは自動決定で v8 の再コンパイルしないと最大値を増やせないようなので node のオプションにはいらないのかな
--max_old_space_size は 32 bit は 700MB で 64bit は 1400MB とさっきと微妙にサイズが違います
もっと増やせるようで最大値は不明ぽいです
さっきのページとは違っていて結局どうなのかよくわかりません
old ってなんだろうと思ってたのですが new と対応してたようです
new が GC ですぐ消される方みたいなのでこっちはあまり GC されず残り続けるメモリ空間だと思います
たぶん
--max_executable_size はヒープスプレー攻撃から守るためのセキュリティのための制限で この値は基本増やさないほうがいいみたい
といってもクライアントサイドでの問題なので node とかサーバサイドなら気にしなくていいものだとか
結局 max_old_space_size と一緒にこれも設定しないとメモリ使える量は増えないのかはわかりませんでした
packer
話がずれてきたので minify に戻ります上の方に書いた Qiita のページでは packer もそれなりに圧縮効率が高いので 試してみます
といっても ほとんどの minify ツールって スペースや改行を消したり 変数名を短くしたり程度なのに packer は元の形を維持せず暗号化みたいなことになっています
文字数を減らすのを重視していて JavaScript で処理した結果 もともとのソースコードの文字列ができて それを eval で実行するものです
処理と言っても テキスト操作するだけなので一瞬です
昔のネットワーク速度で大きなファイルを通信する時間に比べれば ほんの僅かな処理時間だと思います
npm にあったので
npm -g install packer
とやってみたらコンパイルエラーになりました
ただダウンロードするだけじゃなくてコンパイル必要なタイプみたいです
Windows 環境だと面倒なので 別の方法を探します
公式サイトには .net のアプリケーションがありました
http://dean.edwards.name/download/
.NET 1.1 向けってすごく古いです
使ってみると ロードしたのをテキストボックスに表示するタイプ
大丈夫なのかなぁ と思いつつやってみると 意外にも問題なく動きました
考えてみると ブラウザならともかく Windows ソフトでなら 1MB 程度で落ちることはそうあるものじゃないですよね
ただ重大な問題がありました
動かない!!
原因はわからないですが よくわからないエラーでした
eval してるので devtools にも詳しいことがでてなかったです
調べるのも面倒なので とりあえず スキップします
uglifyjs2
1番人気らしい期待の uglifyjs です2 ですがコマンドは 2 なしです
npm -g install uglify-js
uglifyjs -c -m -o pdf.worker.js pdf.worker.min.js
WARN: Side effects in initialization of unused variable pageStripingInformation [_pdf.worker.js:10947,12]
WARN: Side effects in initialization of unused variable segments [_pdf.worker.js:10997,8]
WARN: Dropping unused function parseJbig2 [_pdf.worker.js:10981,11]
WARN: Side effects in initialization of unused variable scanLength [_pdf.worker.js:11936,16]
WARN: Side effects in initialization of unused variable rcon [_pdf.worker.js:23360,6]
WARN: Side effects in initialization of unused variable wy [_pdf.worker.js:26426,18]
WARN: Side effects in initialization of unused variable num [_pdf.worker.js:26754,16]
WARN: Side effects in initialization of unused variable version [_pdf.worker.js:29222,12]
WARN: Side effects in initialization of unused variable length [_pdf.worker.js:29284,12]
WARN: Side effects in initialization of unused variable language [_pdf.worker.js:29285,12]
WARN: Side effects in initialization of unused variable dummy [_pdf.worker.js:42353,12]
WARN: Dropping unused variable pdfjsVersion [_pdf.worker.js:31,4]
WARN: Dropping unused variable pdfjsBuild [_pdf.worker.js:32,4]
WARN: Side effects in initialization of unused variable pdfjsFilePath [_pdf.worker.js:34,6]
WARN: Side effects in initialization of unused variable pageStripingInformation [_pdf.worker.js:10947,12]
WARN: Side effects in initialization of unused variable segments [_pdf.worker.js:10997,8]
WARN: Dropping unused function parseJbig2 [_pdf.worker.js:10981,11]
WARN: Side effects in initialization of unused variable scanLength [_pdf.worker.js:11936,16]
WARN: Side effects in initialization of unused variable rcon [_pdf.worker.js:23360,6]
WARN: Side effects in initialization of unused variable wy [_pdf.worker.js:26426,18]
WARN: Side effects in initialization of unused variable num [_pdf.worker.js:26754,16]
WARN: Side effects in initialization of unused variable version [_pdf.worker.js:29222,12]
WARN: Side effects in initialization of unused variable length [_pdf.worker.js:29284,12]
WARN: Side effects in initialization of unused variable language [_pdf.worker.js:29285,12]
WARN: Side effects in initialization of unused variable dummy [_pdf.worker.js:42353,12]
WARN: Dropping unused variable pdfjsVersion [_pdf.worker.js:31,4]
WARN: Dropping unused variable pdfjsBuild [_pdf.worker.js:32,4]
WARN: Side effects in initialization of unused variable pdfjsFilePath [_pdf.worker.js:34,6]
とりあえず -c -m のオプションをつければいいみたい
いろいろ警告でていますが 問題なく動きました
ちゃんと JavaScript として解析して 使ってない変数を捨てたりしてるんですねー
結果をまとめると
pdf.js (366.42KB)
--(ticker)--> 99.47KB
--(uglifyjs2)--> 144.44KB
--(closure-compiler)--> 150.49KB
pdf.worker.js (1.37MB)
--(uglifyjs2)--> 582.70KB
--(other)--> n/a
--(ticker)--> 99.47KB
--(uglifyjs2)--> 144.44KB
--(closure-compiler)--> 150.49KB
pdf.worker.js (1.37MB)
--(uglifyjs2)--> 582.70KB
--(other)--> n/a
唯一 pdf.worker.js を動く形で minify できたのは uglifyjs2 だけでした
人気ナンバーワンは伊達ではないですね
変換内容を見てみる
ながーい pdf.js のは見たくないので 短いコードを作って minify 書けてみました1
とりあえずこれを minify します!function(){
var obj = {}
obj.abcd = 1
console.log(obj["abcd"])
}()
var obj = {}
obj.abcd = 1
console.log(obj["abcd"])
}()
packer
まずは pdf.worker.js で minify できたけど動かなかった packer
eval(function(p,a,c,k,e,d){e=function(c){return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1;};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p;}('!4(){3 0={}0.2=1 6.5(0["2"])}()',7,7,'obj||abcd|var|function|log|console'.split('|'),0,{}))
長くなってます
元が短いときは minify じゃないですね
最終的に eval される文字列はこうなりました
!function(){var obj={}obj.abcd=1 console.log(obj["abcd"])}()
セミコロンがない!
単純にホワイトスペースを除去したテキストを作ってるだけで構文解析とかしてないみたいで minify するときに必要なセミコロンがおぎなわれていません
セミコロンなし派と相性が悪いだけでなく 実際多くのコードが動かないと思います
というのもセミコロン書く派の人でも 書き忘れた箇所があってもほぼ動くので 100% セミコロンが正しく打たれているコードは意外と少ないです
ネットでコード見てても このコードセミコロン抜けてると思うことがそこそこ見かけます
これが今ではほとんど使われない理由のひとつでもありそうです
google-closure-compiler
次は google-closure-compiler
>google-closure-compiler-js --compilationLevel=SIMPLE test.js
!function(){console.log(1)}();
!function(){console.log(1)}();
おぉっ
すごくシンプルになりました
さすが SIMPLE
valueOf とか toString 書き換えたり プロキシしたりとか色々やってるとちょっと怖いですが google 製だしその辺はきっと大丈夫だよね
さらに圧縮率の高い ADVANCED もあるので試してみます
>google-closure-compiler-js --compilationLevel=ADVANCED test.js
console.log(1);!0;
console.log(1);!0;
関数すら呼び出されません
インライン展開されています
「!0」 は 「!functin(){}()」 の結果が true になるのでそこを合わせるためです
TICKER
次に TICKER
eval(function(t,i,c,k,e,r){e=String;if(!''.replace(/^/,String)){while(c--)r[c]=k[c]||c;k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])t=t.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return t}('!3(){4 0={};0.2=1,5.6(0.2)}();',7,7,'c||abcd|function|var|console|log'.split('|'),0,{}))
packer 同様 元よりは長いです
でも packer に比べると 短いです
eval される文字列はこれです
!function(){var c={};c.abcd=1,console.log(c.abcd)}();
一般的な minify 済みです
packer はこうでした
!function(){var obj={}obj.abcd=1 console.log(obj["abcd"])}()
minify 済みに packer の改良型の圧縮をするので圧縮率が高いようです
uglifyjs
最後に uglifyjs
!function(){var c={};c.abcd=1,console.log(c.abcd)}();
あれ? さっきも見たような……
TICKER と一緒です
もしかして TICKER って内部で uglifyjs 適用してから独自の圧縮してる??
これは短いからたまたまの可能性もあります
なので pdf.js を圧縮したもの比較してみました
すると
Promise.prototype["catch"]
がPromise.prototype.catch
になるような違いはあったものの ほぼ完全に一緒でした
この僅かな違いはたぶん uglifyjs のオプションで変更できるものだと思います
もしかして ソース出さずにオンラインのみなのも 圧縮率一番と言いつつもそのほとんどを uglifyjs に任せてるのを隠したいからだったり?
でも公式サイトに minify と TICKER の比較が並んでるので uglifyjs の minify が minify のことで そこから TICKER でさらにこれだけ減らせるよ と言ってるようにも考えられます
まぁ TICKER の圧縮率の謎もわかりましたし アップロードが嫌なら uglifyjs のあとで packer かければ セミコロン問題もないしそこそこ圧縮されて良いんじゃないでしょうか
2
変数名の圧縮って怖いのでちょっと複雑にしたものを試してみますコードはこれ
var u = function(n){
var obj = {}
obj.t = {abcd: 33}
obj[n]["abcd"]++
return obj
}
console.log(u("t"))
var obj = {}
obj.t = {abcd: 33}
obj[n]["abcd"]++
return obj
}
console.log(u("t"))
まずは closure-compiler の SIMPLE
>google-closure-compiler-js --compilationLevel=SIMPLE test.js
var u=function(b){var a={t:{abcd:33}};a[b].abcd++;return a};console.log(u("t"));
var u=function(b){var a={t:{abcd:33}};a[b].abcd++;return a};console.log(u("t"));
結果も問題なしです
次に ADVANCED
>google-closure-compiler-js --compilationLevel=ADVANCED test.js
console.log(function(b){var a={t:{a:33}};a[b].abcd++;return a}("t"));
console.log(function(b){var a={t:{a:33}};a[b].abcd++;return a}("t"));
んん?
abcd が a になってます
なのに同じキーを参照する別のところは abcd のままです
もちろんこれじゃ動きません
ADVANCED は使わない方がよさそう
最後に uglifyjs
var u=function(a){var c={};return c.t={abcd:33},c[a].abcd++,c};console.log(u("t"));
こっちも問題なし
closure-compiler よりちょっと長いです
pdf.js のときは uglifyjs のほうが圧縮率よかったので コード次第みたいです
ただ こっちはメモリ消費がそれほどないので こっちのほうがよさそう
まとめ
使える順uglifyjs2 → google-closure-compiler(SIMPLE)
今回試したものでは その他は問題あるのが多いです
TICKER は内部で uglifyjs を使ってます