Riot.js/riot_js-railsの手直し の履歴(No.5)
更新- 履歴一覧
- 差分 を表示
- 現在との差分 を表示
- ソース を表示
- プログラミング/Riot.js/riot_js-railsの手直し へ行く。
概要†
rails から riot.js を使うための gem として、 riot_js-rails というのがあるのですが、 環境によってどうもうまく動かないように思えたため、手直しできないか調べてみました。
結果、どうにも手に負える物ではなかった感じです。。。
症状†
$ ruby --version ruby 1.9.3p551 (2014-11-13 revision 48407) [x86_64-linux] $ rails new riot_js-rails_sample -B $ cd riot_js-rails_sample/ $ jed Gemfile gem 'riot_js-rails' $ bundle install $ cat Gemfile.lock ... DEPENDENCIES coffee-rails (~> 4.0.0) jbuilder (~> 1.2) jquery-rails rails (= 4.0.13) riot_js-rails sass-rails (~> 4.0.2) sdoc sqlite3 turbolinks uglifier (>= 1.3.0) BUNDLED WITH 1.11.2 $ rails generate controller main index create app/controllers/main_controller.rb route get "main/index" invoke erb create app/views/main create app/views/main/index.html.erb invoke test_unit create test/controllers/main_controller_test.rb invoke helper create app/helpers/main_helper.rb invoke test_unit create test/helpers/main_helper_test.rb invoke assets invoke coffee create app/assets/javascripts/main.js.coffee invoke scss create app/assets/stylesheets/main.css.scss $ jed config/routes.rb root 'main#index' $ rails s & $ wget -q -O - http://localhost:3000/ ... <h1>Main#index</h1> <p>Find me in app/views/main/index.html.erb</p> ... $ cat > app/assets/javascripts/test-tag.tag <test-tag> Ok! </test-tag> $ jed app/assets/javascripts/application.js + //= require riot + //= require riot-rails //= require_tree . $ wget -q -O - http://localhost:3000/ <script data-turbolinks-track="true" src="/assets/riot.js?body=1"></script> <script data-turbolinks-track="true" src="/assets/riot_rails.js?body=1"></script> <script data-turbolinks-track="true" src="/assets/main.js?body=1"></script> <script data-turbolinks-track="true" src="/assets/application.js?body=1"></script>
require_tree で test-tag.tag が読み込まれていません。
$ mv app/assets/javascripts/test-tag.tag app/assets/javascripts/test-tag.js.tag $ wget -q -O - http://localhost:3000/ <script data-turbolinks-track="true" src="/assets/riot.js?body=1"></script> <script data-turbolinks-track="true" src="/assets/riot_rails.js?body=1"></script> <script data-turbolinks-track="true" src="/assets/main.js?body=1"></script> <script data-turbolinks-track="true" src="/javascripts/test-tag.js.tag.js"></script> <script data-turbolinks-track="true" src="/assets/application.js?body=1"></script> $ wget -q -O - http://localhost:3000/javascripts/test-tag.js.tag.js Started GET "/javascripts/test-tag.js.tag.js" for 127.0.0.1 at 2016-07-01 13:55:32 +0900 ActionController::RoutingError (No route matches [GET] "/javascripts/test-tag.js.tag.js"): $ wget -q -O - http://localhost:3000/assets/test-tag.js.tag.js?body=1 Started GET "/assets/test-tag.js.tag.js?body=1" for 127.0.0.1 at 2016-07-01 13:56:24 +0900 ActionController::RoutingError (No route matches [GET] "/assets/test-tag.js.tag.js"):
test-tag.tag ではなく test-tag.js.tag としたところ、読み込もうとする姿勢は見られましたが、 /assets/ ではなく /javascripts/ が指定されており、なおかつ両方とも RoutingError になってしまいます。
Rails のバージョンを上げると†
$ rvm use ruby-2.2.1 $ ruby --version ruby 2.2.1p85 (2015-02-26 revision 49769) [x86_64-linux] $ rails --version Rails 4.2.6 $ rails new riot_js-rails_sample -B $ cd riot_js-rails_sample/ $ jed Gemfile gem 'riot_js-rails' $ bundle install $ cat Gemfile.lock DEPENDENCIES byebug coffee-rails (~> 4.1.0) jbuilder (~> 2.0) jquery-rails rails (= 4.2.6) riot_js-rails sass-rails (~> 5.0) sdoc (~> 0.4.0) spring sqlite3 turbolinks uglifier (>= 1.3.0) web-console (~> 2.0) $ echo "Sprockets::VERSION" | rails c Loading development environment (Rails 4.2.6) Switch to inspect mode. Sprockets::VERSION "3.6.3"
この環境だと、上と同じ操作で
<script src="/assets/riot.self-d4789eae993b10e05f4694693fa33efe6afd5ccd866d3f6eee21de793efc7f31.js?body=1" data-turbolinks-track="true"></script> <script src="/assets/riot_rails.self-23d22569edc9e83fe5a74dbf647822c59a2fcd08777f496b38cab2507f2d594d.js?body=1" data-turbolinks-track="true"></script> <script src="/assets/main.self-877aef30ae1b040ab8a3aba4e3e309a11d7f2612f44dde450b5c157aa5f95c05.js?body=1" data-turbolinks-track="true"></script> <script src="/assets/test-tag.self-198db509a34ddfb1d978f239761117f57e5680e43ffe43f5524092ecb41ca2b3.js?body=1" data-turbolinks-track="true"></script> <script src="/assets/application.self-7862a8a8b42407b4741a1adeeea35f0d13ddc4f702ec532adb0674491d296495.js?body=1" data-turbolinks-track="true"></script>
のように、"test-tag.self-XXXX.js" が正しくコンパイルされます。
どうやら sprockets のバージョン依存・・・なのでしょうか?
ソースを確認†
$ cd .. $ git clone https://github.com/bjarosze/riot_js-rails.git Cloning into 'riot_js-rails'... remote: Counting objects: 180, done. remote: Total 180 (delta 0), reused 0 (delta 0), pack-reused 180 Receiving objects: 100% (180/180), 79.78 KiB | 90.00 KiB/s, done. Resolving deltas: 100% (61/61), done. Checking connectivity... done. $ cd riot_js-rails $ ls -a . .. .git .gitignore Gemfile README.md Rakefile lib riot_js-rails.gemspec test vendor $ git branch -m fix-asset-path $ git status On branch fix-asset-path Your branch is up-to-date with 'origin/master'. nothing to commit, working directory clean $ cat lib/riot_js/rails/railtie.rb require 'rails/railtie' require 'riot_js/rails/processors/processor' require 'riot_js/rails/helper' module RiotJs module Rails class Railtie < ::Rails::Railtie initializer :setup_sprockets do |app| Processor.register_self config ... $ cat lib/riot_js/rails/processors/processor.rb require 'riot_js/rails/processors/compiler' if Gem::Version.new(Sprockets::VERSION) < Gem::Version.new('3.0.0') require 'riot_js/rails/processors/sprockets_processor_v2' else require 'riot_js/rails/processors/sprockets_processor_v3' end module RiotJs module Rails class Processor < SprocketsProcessor def process compile_tag end private def compile_tag ::RiotJs::Rails::Compiler.compile(@data) end end end end $ echo "Sprockets::VERSION" | rails c Loading development environment (Rails 4.0.13) Switch to inspect mode. Sprockets::VERSION "2.12.4" $ cat lib/riot_js/rails/processors/sprockets_rocessor_v2.rb module RiotJs module Rails class SprocketsProcessor < Tilt::Template self.default_mime_type = 'application/javascript' def self.register_self(app) app.assets.register_engine '.tag', self end def evaluate(context, locals, &block) @context = context process end def prepare @data = data end def process raise 'Not implemented' end end end end
これを直すのは難しそうです。。。
coffee-rails のソースを見る†
特定の拡張子を持ったファイルを .js に変換するという動作は coffee-rails と同様なので、
https://github.com/rails/coffee-rails/
これと同じことをやれば良いはずなのですが、、、
.coffee から .js へのコンパイル部分は
https://github.com/rails/coffee-rails/blob/master/lib/coffee/rails/template_handler.rb
LANG:ruby module Coffee module Rails class TemplateHandler def self.erb_handler @@erb_handler ||= ActionView::Template.registered_template_handler(:erb) end def self.call(template) compiled_source = erb_handler.call(template) "CoffeeScript.compile(begin;#{compiled_source};end)" end end end end ActiveSupport.on_load(:action_view) do ActionView::Template.register_template_handler :coffee, Coffee::Rails::TemplateHandler end
だけだと思われて、なおかつこの部分は上記前者で読まれた v4.0.1 でも、 後者で読まれた v4.1.1 でも変更されていないにも関わらず、 同じことをしてみても、どうもうまくいかず、困ってしまいます。
coffee-rails のまねをする†
$ git clone https://github.com/rails/coffee-rails.git $ mv coffee-rails/ riottag-rails $ (いろいろ直す)
主には、
LANG:ruby module RiotTag module Rails class TemplateHandler def self.erb_handler @@erb_handler ||= ActionView::Template.registered_template_handler(:erb) end def self.call(template) compiled_source = erb_handler.call(template) "'Compiled!'.html_safe" end end end end ActiveSupport.on_load(:action_view) do ActionView::Template.register_template_handler :tag, RiotTag::Rails::TemplateHandler end
全然うまくいきません(涙
というか、coffee-rails の該当部分 ActionView::Template.register_template_handler をコメントアウトしても coffee-rails が動き続けているあたり、見ている場所が全然違うのかもしれません?!
素直に rails のバージョンを上げることを考えるべきなのかも・・・
それにしても黒魔術すぎて、キビシイなあ
それっぽい記事を発見(未検証)†
Supporting All Versions of Sprockets in Processors
https://github.com/rails/sprockets/blob/master/guides/extending_sprockets.md#supporting-all-versions-of-sprockets-in-processors
これによると、
LANG:ruby class SprocketsExtensionBase def initialize(filename, &block) @filename = filename @source = block.call end def render(context, empty_hash_wtf) self.class.run(@filename, @source, context) end def self.run(filename, source, context) /* return the modified source */ end def self.call(input) filename = input[:filename] source = input[:data] context = input[:environment].context_class.new(input) result = run(filename, source, context) context.metadata.merge(data: result) end end
を継承して run を override すれば Extention を作れる。
require 'sprockets/processing' extend Sprockets::Processing register_preprocessor 'text/css', TheSprocketsExtension
で拡張機能を登録して、
def register_sprockets_extention(env, sprockets_extention, mime_type, file_ext, charset=nil) file_ext = [file_ext] unless file_ext.instance_of?(Array) charset = charset.to_sym # Sprockets 2, 3, and 4 if env.respond_to?(:register_transformer) env.register_mime_type mime_type, extensions: file_ext, charset: charset env.register_preprocessor mime_type, sprockets_extention end if env.respond_to?(:register_engine) args = [file_ext, sprockets_extention] args << { mime_type: mime_type, silence_deprecation: true } if Sprockets::VERSION.start_with?("3") env.register_engine(*args) end end
これで良さそう?
あら、ものすごく重要なことがさらっと書いてあった。
prockets 4 will not chain asset extensions so .coffee.erb is explicitly registered in addition to .coffee. If your application introduces a new mime/extension combo it will be responsible for registering all combinations.
だから rails 5 で file.tag.haml が動かなかったのか?
いや、rails 5.0.0.1 でも sprockets は 3.7 だから、そういう問題ではないか。
if Sprockets::VERSION.start_with?("5") register_sprockets_extention env, 'application/javascript', '.tag.haml', nil, Proc.new {|input| TagProcessor.call(HAMLProcessor.call(input)) } end
こんな感じかな?
後で試さねば。