23
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

Organization

Rails で watchify と browserify を使い分けられる gem を作った

弊社は今週はハックウィークといって通常業務止めて周辺ツール作ったりいつもはできないことをやる週として割り振られている。(その割には昨日Contributionの計算の変更とかリリースしてた気がするが)

それで仕事で使ってた browserify_rails が遅すぎて辛かったので、趣味でいつも使ってた watchify をRailsにインテグレーションするgemを作ってみた。

はじめて作ったgemなんで手加減して https://github.com/increments/brwy_rails

brwy は browserify_watchify_rails が長すぎて略したけど意味わからん気がする。

watchify とは

browserifyと違ってコンパイル後もコンパイラプロセスが中間状態を保持したまま常駐して、依存のファイル監視して差分ビルドを行ってくれる。仕組み知ってたら速くなるのわかると思う。

babel使ってたらbabelがモジュール分割されすぎてて初期化が遅いのがボトルネックになるんだが、それもメモリに常駐してるのでスキップできる。

使い方

# config/application.rb
config.assets.precompile = ["application.bundle.js", "application.css"]
config.brwy_rails.targets = [
  "app/assets/javascripts/application.js"
]
Rails.application.config.middleware.use BrwyRails.Middleware
# config.brwy_rails.browserify_opts = "-t babelify" # your browserify compile command
# config.brwy_rails.verbose = true
# config.brwy_rails.target_suffix = ".bundle"
# config.brwy_rails.watch = Rails.env.development?

view から呼び出すときは、名前に .bundle(config.brwy_rails.target_suffix を参照)をつけて呼び出す。

<%= javascript_include_tag 'application.bundle'%>

仕組み

  • tmp/cache/brwy_rails を assets.paths に追加する
  • brwy_rails.targets の数だけ watchify プロセスを spawn する
  • watchify は tmp/cache/brwy_rails/*.js*.bundle.js を吐き出す
  • at_exit で watchify プロセスを全部 kill して終了

事前にプロセスを立ち上げるので、targets で指定した *.bundle.js しかコンパイルしない
プロダクションなら単にbrowserify呼んでasset_path 以下に js 吐いて終了。

これでQiitaのjsに適用すると、コンパイルが 10s が 0.5s になった。

やってないこと

  • browserify_rails みたいな asset_path をよしなにやってパスを解決する
  • //= require ... みたいな sprockets require の解決
    • 全部 commonjs でやれ

TODO

  • brwy_rails:buildassets:precompile の前に流そうと、自分の環境で http://qiita.com/mizchi/items/b802f1853466b1cc54c3 をやってみたのだが、何故か assets:precompile を完全に上書きしてしまって動かなかった。別のRails リポジトリと挙動が違う。 @r7kamura に相談したが不明。たすけて。
  • ドッグフーディング => はまだ
  • 本当はSprockets依存を捨てたい

おまけ: はじめての rails gem

  • rails plugin new hogefuga -t で雛形をつくる
  • lib/hogefuga/railtie.rb で コンフィギュレーションできる部分を作る(後述)
  • lib/hogefuga.rbrequire 'hogefuga/railtie' を追加する
  • test/dummy/ 以下にテスト用の rails があるので rails s して動作確認する
  • OK?
  • https://rubygems.org/ でユーザー登録する
  • https://rubygems.org/profile/edit でローカルとの紐付けスクリプトが与えられてるので、それを実行する
  • github に push する(これ必須じゃない気がするけどまあやっとけって感じ)
  • *.gemspec でTODOになってる部分を自分で埋める
  • Rakefilerequire "bundler/gem_tasks" を追記する
  • bundle exec rake release
  • おわり

おまけの Railtie の書き方

module Hogefuga
  class Railtie < Rails::Engine
    # config/application.rb とかで設定する
    config.hogefuga = ActiveSupport::OrderedOptions.new # なんでも出来るっぽい雑な Hash
    config.hogefuga.verbose = true

    config.after_initialize do
       # 読み込み完了後, config にしたがって何かする 
       puts "Hello hogefuga" if hogefuga.verbose
    end
  end
end

これが最小っぽい。Rails::Railtie と Rails::Engine だと Engine の方だと app/ 以下を自動でパスを指して参照できる、みたいな話だった。

Rails Engine については http://railsguides.jp/engines.html

エンジン (engine) とは、アプリケーションのミニチュアのようなものであり、ホストアプリケーションに機能を提供します。Railsアプリケーションは実際にはエンジンに「ターボをかけた」ようなものにすぎず、Rails::ApplicationクラスはRails::Engineから多くの振る舞いを継承しています。

おまけ: RackMiddleware

Rails より下の Rack層でリクエストな内容を覗いたり、書き換えたかったら middleware 作って use する。

最小のmiddleware

module Hogefuga
  class Middleware
    def initialize(app)
      @app = app
    end

    def call(env)
      @app.call(env)
    end
  end
end

Rails.application.config.middleware.use BrwyRails.Middleware

def call(env) のなかで sleep 1 などと書くとすべての request が1秒遅延する。brwy_rails だとこれを利用して watchify がコンパイル中でファイルが空ならコンパイルを終わるまで待つ という実装をしてみた。

感想

日常であんまりRuby書かないので、雑に r7kamura にやりたいことに対するエントリポイントを聞いたりして色々学習過程をスキップできたけど、Railsの気持ちみたいなもの、まだよくわからなくて、俺Railsのことちゃんとわかってなかった…

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
23
Help us understand the problem. What are the problem?