はじめに
Railsが用意しているjavascript, css, 画像などのアセットを管理するGemに、SprocketsとWebpackerがあります。
この2つを軽く説明すると、
| 名称 | 説明 |
|---|---|
| Sprockets | Rails3.1から導入されたアセットパイプライン。app/assetsディレクトリでアセットを管理する |
| Webpacker | Rails6から導入された、WebpackというモジュールバンドラをRails用にラップしたgem |
WebpackerはSprocketsとの共存を考えて設計されており、Sprockets, Webpackerどちらも使うことを想定しています。
ただまあどちらもアセットを管理するgemなわけで、ややこしくなるしどちらか1つだけ使えばいいのでは?と僕は考えています。
以前作成したAsobiというWebアプリでも、Webpackerでアセットを管理したので、最終的にSprocketsが管理するapp/assetsディレクトリを丸ごと削除しました。
次のWebアプリでもWebpackerを使う予定だったので、app/assetsを削除したのですが…
環境
- Ruby 2.7.0
- Rails 6.0.2
起きたこと
Sprocketsを使わないようにするための手順はいくつかありますが、最終的にapp/assetsというディレクトリは完全にいらなくなります。
なので最初にapp/assetsを削除しました。
$ rm -rf app/assets
試しにここでrails sでRailsを起動しました。
ここでは正常にRailsサーバが起動すると思ったのですが…
WARNING: Nokogiri was built against LibXML version 2.9.10, but has dynamically loaded 2.9.4
=> Booting Puma
=> Rails 6.0.2.1 application starting in development
=> Run `rails server --help` for more startup options
Exiting
Traceback (most recent call last):
# 中略...
/Users/user/rails_test/vendor/bundle/ruby/2.7.0/gems/sprockets-rails-3.2.1/lib/sprockets/railtie.rb:105:in `block in <class:Railtie>': Expected to find a manifest file in `app/assets/config/manifest.js` (Sprockets::Railtie::ManifestNeededError)
But did not, please create this file and use it to link any assets that need
to be rendered by your app:
Example:
//= link_tree ../images
//= link_directory ../javascripts .js
//= link_directory ../stylesheets .css
and restart your server
どうやらapp/assets/config/manifest.jsが無いためSprockets::Railtie::ManifestNeededErrorというエラー出てrails sが終了したようです。
だが待ってほしい。これまでこんなエラー出てこなかったぞ?
原因
こちらのページによると、どうやらSprocketsのバージョンが4.0.0になってから起きるようになったエラーのようです。
Redmine doesn't start with Sprockets::Railtie::ManifestNeededError if sprockets 4.0.0 is installed.
$ bin/rails c
Traceback (most recent call last):
28: from bin/rails:4:in<main>' 27: from bin/rails:4:inrequire'
.
.
.
/Users/maeda/redmines/gems/ruby/2.6.0/gems/sprockets-rails-3.2.1/lib/sprockets/railtie.rb:105:inblock in <class:Railtie>': Expected to find a manifest file inapp/assets/config/manifest.js` (Sprockets::Railtie::ManifestNeededError)
But did not, please create this file and use it to link any assets that need
to be rendered by your app:Example:
//= link_tree ../images
//= link_directory ../javascripts .js
//= link_directory ../stylesheets .css
and restart your server
Redmine doesn't start with Sprockets::Railtie::ManifestNeededError if sprockets 4.0.0 is installed.と書いてありますね。
Sprocketsのissueにも同様のエラー報告がありました。
Actual behavior
An error is thrown since 4.0, this didn't occur on 3.7.2:rake aborted!
Sprockets::Railtie::ManifestNeededError: Expected to find a manifest file inapp/assets/config/manifest.js
But did not, please create this file and use it to link any assets that need
to be rendered by your app:Example:
//= link_tree ../images
//= link_directory ../javascripts .js
//= link_directory ../stylesheets .css
and restart your server
3.7.2では起きなかったエラーとのことで、やはりSprockets 4.0.0から起きているエラーのようです。
対処法
Sprocketsのバージョンを3.7.2に下げる
バージョン4.0.0から起きているのであれば、バージョンを3.7.2に下げれはエラーが解消されるはず!
まずはGemfileに以下のコードを追記します。
# Sprockets4.0だと、app/assetsディレクトリを削除するとSprockets::Railtie::ManifestNeededErrorが発生する
gem 'sprockets', '~> 3.7.2'
そしてbundle updateを実行します。(bundle installじゃないよ)
改めてrails sを実行すると、無事エラーが解消されました。
$ rails s
WARNING: Nokogiri was built against LibXML version 2.9.10, but has dynamically loaded 2.9.4
=> Booting Puma
=> Rails 6.0.2.1 application starting in development
=> Run `rails server --help` for more startup options
/Users/user/rails_test/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.2.1/lib/action_dispatch/middleware/stack.rb:37: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
/Users/user/rails_test/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.2.1/lib/action_dispatch/middleware/static.rb:110: warning: The called method `initialize' is defined here
Puma starting in single mode...
* Version 4.3.1 (ruby 2.7.0-p0), codename: Mysterious Traveller
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://127.0.0.1:3000
* Listening on tcp://[::1]:3000
Use Ctrl-C to stop
rails newのオプションの--skip-sprocketsを指定する
rails newのオプションに--skip-sprocketsというものがあります。
これを指定してRailsアプリを作成すると、config/application.rbのrequireが一部変化します。
# --skip-sprocketsを指定した場合
require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
require "active_record/railtie"
require "active_storage/engine"
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_mailbox/engine"
require "action_text/engine"
require "action_view/railtie"
require "action_cable/engine"
# require "sprockets/railtie"
require "rails/test_unit/railtie"
# 指定しない場合、この1文のみ記述される
require 'rails/all'
require "sprockets/railtie"がコメントアウトされています。
この状態であれば、app/assetsディレクトリを削除してもSprockets::Railtie::ManifestNeededErrorは発生しません。
余談 : --skip-sprocketsを指定してもSprocketsはインストールされる
Railsガイドに書いてありますが、この--skip-sprocketsはapplication.rbの変更と一部のgemを除外してくれるだけです。
# Railsガイドで説明されている、除外されるgem
gem 'sass-rails'
gem 'uglifier'
gem 'coffee-rails'
上記の除外されるgemのリストにSprocketsはありません。
そう、--skip-sprocketsオプションでSprocketsを使わないRailsアプリを作成しても、Sprocketsはインストールされます。更にapp/assetsも生成されます。
これに関しては、GitHubのRailsにも以下のissueが投げられています。
The
app/assetsfolder, and its underlying structure, is created, despite the fact that dropping stylesheets intoapp/assets/stylesheetsno longer causes them to be loaded. This is misleading, at best.
つまり、「--skip-sprocketsを指定したらapp/assetsを作らないようにした方が誤解がないのでは?」というissueが3年前に投げられています。
でも3年経っても変化はないので、恐らくこの状況を変えるつもりはないのでしょう。
まとめ
Sprocketsを使わないのであれば、Sprocketsのバージョンを3.7.2に落としましょう。
もしくはrails newのオプションで--skip-sprocketsを指定しましょう。
参考文献
https://www.redmine.org/issues/32223
https://github.com/rails/sprockets/issues/643
https://github.com/rails/rails/issues/29749
https://railsguides.jp/asset_pipeline.html