koukiblog

たぶんweb系の話題

sprockets-commonerについて

sprocket-commonerというgemがよい感じだったので調べてみました。

sprocket-commonerで何ができるのかは下記qiitaに詳しくかいてあって、僕もこの記事で知りました。
qiita.com

結局のところ
・ES6構文とmoduleのimport/export
・npmモジュール
の2つが使えればよいと思っていたので、ちょうどよい感じです。

sprocket-commonerがなにをやっているのかをざっと眺めてみました。

sprockets-commoner/commoner.rb at master · Shopify/sprockets-commoner · GitHub

module Sprockets
  module Commoner
    def self.sprockets4?
      @@sprockets4 ||= Gem::Version.new(Sprockets::VERSION) >= Gem::Version.new('4.0.0.beta')
    end
  end

  register_postprocessor 'application/javascript', ::Sprockets::Commoner::Processor
  register_transformer 'application/json', 'application/javascript', ::Sprockets::Commoner::JSONProcessor
  register_bundle_metadata_reducer 'application/javascript', :commoner_enabled, false, :|
  register_bundle_metadata_reducer 'application/javascript', :commoner_required, Set.new, :+
  register_bundle_metadata_reducer 'application/javascript', :commoner_used_helpers, Set.new, :+
  register_bundle_processor 'application/javascript', ::Sprockets::Commoner::Bundle
  register_dependency_resolver 'commoner-environment-variable' do |env, str|
    _, variable = str.split(':', 2)
    ENV[variable]
  end
end

Sprockets::Commner::Processor が何かやっていそうです

sprockets-commoner/processor.rb at master · Shopify/sprockets-commoner · GitHub

Schmooze::Baseというクラスを継承しているのですが、
Schmoozeというgemは何をやっているかというと
schmooze/base.rb at master · Shopify/schmooze · GitHub

      def spawn_process
        process_data = Open3.popen3(
          @_schmooze_env,
          'node',
          '-e',
          @_schmooze_code,
          chdir: @_schmooze_root
        )
        ensure_packages_are_initiated(*process_data)
        ObjectSpace.define_finalizer(self, self.class.send(:finalize, *process_data))
        @_schmooze_stdin, @_schmooze_stdout, @_schmooze_stderr, @_schmooze_process_thread = process_data
      end

となっていて、子プロセスでnodeを起動させてそこでJSを実行しているようです。

Sprocketのcompile時に子プロセスでnode.jsを起動して、JSをトランスコンパイルしています。
ExecJSへの依存はありません。

importの辺りはSprocket::Commonerr::Bundleとbabel-plugin-sprockets-commoner-internalで頑張っているみたい。


まとめ

  • Sprocketのcompile時に子プロセスでnode.jsを起動して、JSをトランスコンパイルしてる

 特別なことをせずにnpmモジュールが使える

  • ExecJSへの依存はない

逆にいうと、ExecJSではないので、rubyracerなどは使えない。
  ファイルずつnode起動していくので、パフォーマンスの懸念はあるみたいです。
github.com

  • coffeescriptのimportなど特別な機能を使わなければロックインされることはない

Rails5.1から、SprocketにES6、npmモジュールへの対応が入るし、Webpackerも出るので、5.1が出るまではsprocket-commoner、5.1がリリースされたらRailsデフォルトに戻るのがよいんじゃないかなーと思ってます。