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

RのパッケージをビルドするときにJavascript/CSSをminifyしようと思ったけど、めんどくさくてやめた

R htmlwidgets JavaScript Gulp

前回(htmlwidgetsでD3.jsを使おうとしたら文字コードの闇に飲まれかけた話 - Technically, technophobic.)、

Rのパッケージビルド時にGulpでconcat+uglifyしてminifyされたJSとCSSを自動生成する方法を無駄に模索中です。

という次回予告をしましたが、その話です。

モチベーション

https://github.com/ramnathv/htmlwidgets/issues/56

での議論は、パッケージが提供しているminify済みのファイルを使おう、という流れです。

Bowerはbower.json"ignore"に書いてあるファイル以外すべてのファイルを対象のレポジトリからダウンロードします。.min.jsはたいがいのライブラリで提供されているので、たいがい使うことができます。でも、"main"フィールドに書いてあるのはminifyされていないファイルなので、bower list --pathみたいなコマンドでminifyされたファイルの一覧を得ることはできません。

そもそもそういうふうになっているのはなぜなんでしょう。--minifiedみたいなオプションをつくりましょう、という提案にこんなレスポンスがついています。

This is a job for your build system, not a package manager.
(https://github.com/bower/bower/issues/368)

ははあ。ご自分でminifyなさってください、と。なるほど。

やりましょうじゃないですか。

Gulpを使ってみる

f:id:yutannihilation:20141230011750p:plain

gulp.js - the streaming build system

GruntじゃなくてGulpを使うとかっこいいいらしいので使ってみます。

Gulpとは

Javascriptのビルドシステムらしいです。よく知りません。

npm install -g gulpとかでインストールできます。

Gulpを動かす

よくはわかりませんがgulpfile.jsという名前のファイルを置いて

gulp

ってやると動くらしいです。

使ったGulpのプラグイン

  • main-bower-files: 必要なJavascript/CSSのファイルの一覧を取得します(bower.jsonmainに書いてあるファイル)
  • gulp-filter: 正規表現とかでフィルターをかけます
  • gulp-concat: ファイルをひとつに結合します
  • gulp-uglify: Javascriptをminifyします(gulp-uglifyjsっていうのもあったんですけどどっちがいいのかよく分かりませんでした)
  • gulp-uglifycss: CSSをminifyします

gulpfile.js

Gulp file to compile JS/CSS for htmlwidgets

結果

まあめでたく動いてminifyされたファイルができます。これをいい感じにパッケージのYAMLに書けばぶじ動きます。

でもこれ、

毎回手で打つのめんどくさくない?

Makevarsを使ってみる

そこでMakevarsの出番です。Makevarsは、Makefileの一種で、src/Makevarsというファイルが置いてあればパッケージインストール時にそれに従ってビルドが走ります。

参考:Writing R Extensions: 1.2.1 Using Makevars

Makevarsの書き方

このあたりが参考になります。

Makevars

こんな感じです。相対パスを書く時は、srcが基準になるので、instに入れたいときは../instと書きます。

PACKAGE := metricsgraphics
TARGETDIR := ../inst/htmlwidgets
LIBDIR := $(TARGETDIR)/lib/$(PACKAGE)/

JSFILES := \
    htmlwidgets/$(PACKAGE).js \
    htmlwidgets/lib/jquery/dist/jquery.js \
    htmlwidgets/lib/d3/d3.min.js \
    htmlwidgets/lib/metrics-graphics/dist/$(PACKAGE).js

CSSFILES := \
    htmlwidgets/lib/metrics-graphics/dist/$(PACKAGE).css

YAMLFILE := htmlwidgets/$(PACKAGE).yaml.tpl

all: $(LIBDIR) $(LIBDIR)/$(PACKAGE).js $(LIBDIR)/$(PACKAGE).css $(TARGETDIR)/$(PACKAGE).yaml

.PHONY: clean all

$(LIBDIR):
    mkdir -p $(LIBDIR)

$(LIBDIR)/$(PACKAGE).js: $(JSFILES)
    @rm -f $@
    cat $^ | uglifyjs > $@

$(LIBDIR)/$(PACKAGE).css: $(CSSFILES)
    @rm -f $@
    cat $^ | uglifycss > $@

$(TARGETDIR)/$(PACKAGE).yaml: $(YAMLFILE)
    sed 's/PACKAGE/$(PACKAGE)/' $< > $@

clean:
    @rm -rf -- $(TARGETDIR)

結果

これがMakefile使ったブランチです。

yutannihilation/metricsgraphics at use-makefile · GitHub

devtools::install_github("yutannihilation/metricsgraphics@use-makefile")

とかするとインストールできます。まあとりあえず動きました。knitしようとするとエラーが出るけど、そこは配置の問題なので調べれば何とかなるはず。

でもこれ、

  • uglifyとかuglifycssがインストールされてるかチェックして、されてる場合とされてない場合で場合分けして、とかめんどくさくない?(uglify使えないとD3.jsが動かないので、そもそもの問題の解決になっていない)
  • 実はあんまりファイルサイズ変わらなくない?(手元で試すと、1.3MBだったのが1MBになる程度だった。たぶん容量のほとんどはデータ)
  • デバッグしづらくない?
    ...

うーん。たしかに。。

感想

労力の割にあんまメリットないっすね。疲れました...。

飽きたので大人しくbowerがダウンロードしてくるminify済みのファイルを使います。