2018-03-22

UglifyJSでコードの書き換えはいろいろやれるけどちょっと分かりにくい(define, compress, source map編)

今まで UglifyJS は単に圧縮としてしか使ってなくて、あまり細かく設定を見たことがなかったが、いざ触ってみたらいくつか発見があったのでそのメモを残しておく。

UglifyJS — JavaScript parser, compressor, minifier written in JS

まとめ

  • 外部から define で値を埋め込むことができる
  • UglifyJS の基本はコードの圧縮だが、その際に dead code の除去も行える
  • source map の扱いにはややクセがある

define による外部からの設定の埋め込み

UglifyJS 自体は Node.js で動くので Node.js から環境変数を取得することはできるが、UglifyJS は Browserify ではないので、Browserify のように環境変数にアクセスしている部分をいい具合に置換してくれるわけではない。

そこで利用できるのが define.

  • オプション –define でコード内の定数をセットできる
    • literal に展開されるので文字列を埋め込むなどは難しい
    • boolean だけに留めておくのが正解っぽい
  • shell script の機能を呼び出して分岐させることはできる
uglifyjs  --define PRODUCTION=`[ "$NODE_ENV" = "production" ] && echo "true" || echo "false"`

とやると JavaScript のコードの中では

if ( PRODUCTION ) {
  ...
} else {
  ...
}

のように参照して分岐させることができる。

compress

結構細かく制御できるし、default では割と積極的にコードが削除される。

例えばデフォルトの動作で dead_code を remove できるので、上のように if を書いておくと PRODUCTION が true の場合は then の中身だけが出力コードに残り、false の場合は else の中身だけが出力コードに残る。

他の assets や API の JSON を取得する処理はよくあると思うが、その URL は development, staging 環境と production で差し替えたくなるだろう。上のようなコードにしておくと UglifyJS の compress だけでそれが実現できる。(UglifyJS 後には if はなくなって差し替え後のコードだけが残る。)

source map

  • source map オプションは output オプションの後に置かないと機能しない
    • output オプションのパスを絶対に参照するみたい(中身は見てない)
  • option の解釈が自身の生成向けオプションと読み込むソース向けのオプションと両方入っていて分かりにくい。これは UglifyJS がトランスパイルの最終工程に置かれることが多いゆえなのか、設計が古いのか、もうちょっと工夫してほしかった。

例えば uglifyjs 3.2.2 で確認したところ出力先のコードに source map を含めるには以下のようにする必要があり、

uglifyjs -o ./output/application.js \
         --source-map url=inline,includeSources

さらにこの際、./output/application.js.map の生成は抑止できない。(ファイルの生成と inline への埋め込みがトグルするものと思っていたので指定に失敗しているのかと思ってしばらく悩んだ。)

ちなみに uglifyjs の前工程で source map を inline に生成している場合は以下のように content=inline を追加する必要がある。まぁその場合は最終工程の uglifyjs を省略すればいいだけじゃね?と思わなくもない。

uglifyjs -o ./output/application.js \
         --source-map content=inline,url=inline,includeSources

cf. Emit inline source maps with UglifyJS v3 · Issue #2711 · mishoo/UglifyJS2

About

例によって個人のなんちゃらです

Recent Posts

Categories

Tool 日々 Web Biz Net Apple MS ことば News Unix howto Food PHP Movie Edu Community Book Security Text TV Perl Ruby Music Pdoc 生き方 RDoc ViewCVS CVS Rsync Disk Mail FreeBSD Cygwin PDF Photo Zebedee Debian OSX Comic Cron Sysadmin Font Analog iCal Sunbird DNS Linux Wiki Emacs Thunderbird Sitecopy Terminal Drawing tDiary AppleScript Life Money Omni PukiWiki Xen XREA Zsh Screen CASL Firefox Fink zsh haXe Ecmascript PATH_INFO SQLite PEAR Lighttpd FastCGI Subversion au prototype.js jsUnit Apache Trac Template Java Rhino Mochikit Feed Bloglines CSS del.icio.us SBS qwikWeb gettext Ajax JSDoc Rails HTML CHM EPWING NDTP EB IE CLI ck ThinkPad Toy WSH RFC readline rlwrap ImageMagick epeg Frenzy sysprep Ubuntu MeCab DTP ERD DBMS eclipse Eclipse Awk RD Diigo XAMPP RubyGems PHPDoc iCab DOM YAML Camino Geekmonkey w3m Scheme Gauche Lisp JSAN Google VMware DSL SLAX Safari Markdown Textile IRC Jabber Fastladder MacPorts LLSpirit CPAN Mozilla Twitter OpenFL Rswatch ITS NTP GUI Pragger Yapra XML Mobile Git Study JSON VirtualBox Samba Pear Growl Mercurial Rack Capistrano Rake Win RSS Mechanize Sitemaps Android JavaScript Python RTM OOo iPod Yahoo Unicode Github iTunes God SBM friendfeed Friendfeed HokuUn Sinatra TDD Test Project Evernote iPad Geohash Location Map Search Simplenote Image WebKit RSpec Phone CSV WiMAX USB Chrome RubyKaigi RubyKaigi2011 Space CoffeeScript Nokogiri Hpricot Rubygems jQuery Node GTD CI UX Design VCS Kanazawa.rb Kindle Amazon Agile Vagrant Chef Windows Composer Dotenv PaaS Itamae SaaS Docker Swagger Grape WebAPI Microservices OmniAuth HTTP 分析基盤 CDN Terraform IaaS HCL Webpack Vue.js BigQuery Middleman CMS AWS PNG Laravel Selenium OAuth OpenAPI GitHub UML GCP TypeScript SQL Hanami Document SVG AsciiDoc Pandoc DocBook Develop Jekyll macOS Node.js Vite Heroku Transformer AI Data Cloud Wasm