Madogiwa Blog

主に技術系の学習メモに使っていきます。

Ruby on Rails: cssの管理をAssets PipelineからWebpakerに移行するときのメモ

個人のアプリケーションを今まではデフォルトのアセットまわり(CSS等)をSprocketsJavaScriptWebpackerでビルドするような形にしてたのですが、 今回はstylesheetをWebpackerで管理するようにしたので、そのへんの手順をメモしておきます📝

対応したアプリケーションのRailsのバージョンは6.0.3.2、Webpackerのバージョンは5.1.1です。

.cssファイルをWebpackerで管理する

今回は.css(.scss)ファイルをWebpackerで管理するための手順をまとめていきます。

assets配下の.cssファイルをjavascript配下に移動

まずはSproketsで管理しているapp/assets配下の.cssファイルをWebpackerで管理するためにapp/javascript配下に移動します。 ※webpacker.ymlでentryまわりの変更している場合は、その設定に従って移動先を指定してください。

今回はWebpackerの公式のドキュメントがapp/javascript/stylesheets配下においてそうだったので、そこに移動するようにしました🙋

# https://github.com/rails/webpacker/blob/master/docs/css.md
app/  
  javascript/  
    stylesheets/  
      application.scss  
      posts.scss  
      comments.scss

entryの.js.cssファイルをimportしてWebapckerのビルド対象にする

Webpacker(Webpack)はentryでimportされたファイルをビルド対象とするので必要な.cssファイルを entryの.js(デフォルトだとapp/javascript/packs配下のjs)でimportしてあげます。 ※Webpackerはデフォルトでsass-loadercss-loader等がinstallされて設定もよしなにしてくれるようです。

// app/javascript/application.js
import '../stylesheets/application.scss'

Webpacker v5からはpacks配下にentryのjsと同名のcssを配置すると自動でimportしてくれるようになったようです、便利✨

By Webpacker convention (as of Webpacker v5), this will bundle application.js and application.scss as part of the same entry point (also described as a multi-file entry point in the webpack docs). https://github.com/rails/webpacker/blob/master/docs/css.md#importing-css-as-a-multi-file-pack-webpacker-v5

これでbin/webpack時にimportしたcssファイルがビルドされて読み込まれるようになりました🙌

しかしデフォルトだとhead内に直接ビルドされたstyleが記述されてしまいます。 styleが比較的軽量な場合は問題ないのですが、S3から.cssファイルを配信するため別ファイルで出力したいケースは多いかと思います。

.cssファイルを個別のファイルとしてビルドするようにする

Webpackerにはmini-css-extract-pluginを使用してimportしたファイルを個別ファイルで出力する機能が提供されています。

使用するためにはwebapcker.ymlextract_csstrueに設定することで.cssファイルを個別のファイルとして出力することができます。

default: &default
  # Extract and emit a css file
  extract_css: true

development: &default
  # Extract and emit a css file
  extract_css: true

// その他環境でも必要に応じて同様に設定

Viewでビルドされた.cssファイルを読み込む

個別に出力された.cssファイルはjavascript_pack_tagと同様にView側の読み込む必要があります。

cssの場合はstylesheet_pack_tagを使って読み込みを行います。

<%= stylesheet_pack_tag 'application' %>

これで.cssファイルをWebapckerでビルドして個別ファイルに出力し、それをView側で読み込むことができるようになりました🎉

おまけ:eslintの対象からCSSまわりを除外する

package.jsonのlintまわりの設定を下記のような形にしていたのですが、javascript配下のcssがeslintの対象となってしまい。。。🤔

  "scripts": {
    "lint": "eslint app/javascript/**/* --ext .vue,.js,.ts",
    "lint-fix": "eslint app/javascript/**/* --ext .vue,.js,.ts --fix",

色々調べてみたところ--extオプションがファイル指定の場合に効かないようで、、、eslintignoreで指定するようにしたのですが、

app/javascript/stylesheets

Note: --ext is only used when the arguments are directories. If you use glob patterns or file names, then --ext is ignored. https://eslint.org/docs/user-guide/command-line-interface#ext

これでは、eslintがeslintignoreと実行時の指定のどちらを優先すればいいかわからず、warning File ignored because of a matching ignore pattern. Use "--no-ignore" to override.の警告が発生してしまいます😢

If you pass a specific file to ESLint, then you will see a warning indicating that the file was skipped. https://eslint.org/docs/user-guide/configuring#ignored-file-warnings

最終的には下記のようなディレクトリ指定にして--extオプションが効くようにして対応しました🙇‍♂️

  "scripts": {
    "lint": "eslint app/javascript --ext .vue,.js,.ts",
    "lint-fix": "eslint app/javascript --ext .vue,.js,.ts --fix",

おまけ: Sproketsの無効化

アセットまわりもWebpackerでビルドするようにするとSproketsはもう必要ないので無効化してあげると依存gemも減らせていい感じです。

※ちなみに新規にアプリケーションを作る場合は--skip-sproketsを指定してrails newすればOKなので楽です👌

Sproketsのrequireをやめる

application.rbrequire 'rails/all'をしているとsprockets/railtierequireされてしまうので、

 %w(
   #...
   sprockets/railtie
 ).each do |railtie|
   begin
     require railtie
# https://github.com/rails/rails/blob/6-0-stable/railties/lib/rails/all.rb#L18

sprockets/railtieを除いて個別にrequireするようにします。

require 'active_record/railtie'
require 'active_storage/engine'
require 'action_controller/railtie'
require 'action_view/railtie'
require 'action_mailer/railtie'
require 'active_job/railtie'
require 'action_cable/engine'
require 'action_mailbox/engine'
require 'action_text/engine'
require 'rails/test_unit/railtie'

config系のファイルからassetsまわりの設定値を削除する

その後config/enviroments配下の各ファイルからconfig.assets関係の設定を削除していきます。

各設定値の詳細はこちら

railsguides.jp

(config.assets.enabledfalseにしといた方がいいのかな?🤔)

私の個人アプリだとこの辺の設定を削除しました。

# config/environments/development.rb
config.assets.debug = true # 削除
config.assets.quiet = true # 削除

# config/environments/production.rb
config.assets.compile = false # 削除

そして、config/initializers/assets.rbも削除します。

sass-railsをGemfileから削除する

最後にGemfileからsass-railsを削除してbundle installします。※uglifier等も残っていたら削除します。

gem 'sass-rails', '>= 6' # 削除

これでSproketsも無効化できました🎉

おわりに

今回はstyleまわりを例にAssets PipelineからWebpakerに移行する手順をちょっと整理してみました。(今回行ったのは.cssだけだったのでシンプルでしたが、実際の案件ではこんなにすんなりはいかなさそう。。。)

Webpack移行の前段としてSproketsとの併用をやめて、Webpacker単体の環境に移行しておくと移行対象が減るので、いいかもですね👀

参考資料

webpacker/css.md at master · rails/webpacker · GitHub

stackoverflow.com