週刊Railsウォッチ20220228でもお伝えしましたが、つい最近、dartsass-rails gemがRailsのGitHubリポジトリで正式に登場しました。
dartsass-railsは、本家Dart Sassのバイナリ実行ファイルをラップしています。現時点ではLinuxとmacOSでi32版とx64版、Windowsでx64版のバイナリ実行ファイルがあります。今回初めて気づきましたが、Dart Sassは2016年のごく初期からバイナリ実行ファイルをリリースし続けているんですね。
どこかで見たような話ですね。そう、以下の記事にも書いたように、tailwindcss-rails gemもバイナリ版CLIツールをラップしています↓。最近のJSツールチェインはバイナリ版も出すのが流行りなのでしょうか。
DHHがtailwind.cssとDart Sassで立て続けにバイナリをサポートしたのは、Rails 7で「Node.jsなしでできる選択肢を増やすため」だと私は考えています。
以下のDHHブログにこんなことが書かれています。
There's still more work to be done on Propshaft before it's fully able to take over the reins from Sprockets as the default asset pipeline in Rails, but we're fast moving closer. HEY just went into production yesterday with a Propshaft + Dart Sass combination to fit alongside its existing use of import maps. Early Propshaft contributor Breno Gazzola has also already launched production apps on Propshaft.
Introducing Propshaftより
このdartsass-rails gemは、propshaftと組み合わせられるそうです。
これまではRails 7でNode.jsのお世話にならずに使えるCSSフレームワークといえばtailwindだけでしたが、そこにDart Sassも加わったわけです。DHHはこのところ「バイナリ実行ファイルによるNode.jsなし路線」をやんわりと推しているように思えます。
dartsass-railsとpropshaftを使ってみる
dartsass-railsのREADMEを見ると、Rails 7でのインストール方法は以下を順に実行するというものでした。
./bin/bundle add dartsass-rails
./bin/rails dartsass:install
1行目は普通にGemfileに自分で追記しても同じですね。
gem "dartsass-rails", "~> 0.3.0"
rails new . -a propshaft
で生成したRails 7アプリで上を実行した結果が以下です(関連のなさそうなディレクトリ内のファイルははしょりました)。
.
├── Gemfile
├── Gemfile.lock
├── Procfile.dev
├── README.md
├── Rakefile
├── app
│ ├── assets
│ │ ├── builds
│ │ │ └── application.css
│ │ ├── images
│ │ └── stylesheets
│ │ ├── application.css
│ │ └── application.scss
│ ├── channels/
│ ├── controllers/
│ ├── helpers/
│ ├── javascript
│ │ ├── application.js
│ │ └── controllers
│ │ ├── application.js
│ │ ├── hello_controller.js
│ │ └── index.js
│ ├── jobs/
│ ├── mailers/
│ ├── models/
│ └── views/
├── bin
│ ├── dev
│ ├── importmap
│ ├── rails
│ ├── rake
│ └── setup
├── config
│ ├── application.rb
│ ├── boot.rb
│ ├── cable.yml
│ ├── credentials.yml.enc
│ ├── database.yml
│ ├── environment.rb
│ ├── environments/
│ ├── importmap.rb
│ ├── initializers/
│ ├── locales/
│ ├── master.key
│ ├── puma.rb
│ ├── routes.rb
│ └── storage.yml
├── config.ru
├── db/
├── lib/
├── log/
├── public/
├── storage/
├── test/
├── tmp/
└── vendor
└── javascript
通常、Sprocketsまたはpropshaftを使う場合は./bin/rails s
で起動しますが、dartsass-railsをインストールすると./bin/dev
で起動するように組み替えられます。
生成されたProcfile.devを見るとこうなっています。
# Procfile.dev
web: bin/rails server -p 3000
css: bin/rails dartsass:watch
app/assets/stylesheets/にはapplication.cssとapplication.scssが両方できてしまいますが、前者は削除して構いません。
これでSassが動くようになり、SassでおなじみのCSSのネストや@import
も使えることを確かめました。
ここではpropshaftにしましたが、Sprocketsとの組み合わせでもまったく同じようにdartsass-railsが使えることを別途確かめました。Rails 7ではrails new .
のように無指定だと引き続きSprocketsが使われるので、後は上と同じにやれます。
Bootstrapもimportmap-railsで入れてみた
SassがNode.jsなしで動くようになったので、試しにBootstrap 5のJSもimportmap-railsで入れてみました。
./bin/importmap pin popperjs bootstrap
実行後のconfig/importmap.rbは以下のようになりました。
// config/importmap.rb
# Pin npm packages by running ./bin/importmap
pin "application", preload: true
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin_all_from "app/javascript/controllers", under: "controllers"
pin "bootstrap", to: "https://ga.jspm.io/npm:bootstrap@5.1.3/dist/js/bootstrap.esm.js"
pin "@popperjs/core", to: "https://ga.jspm.io/npm:@popperjs/core@2.11.2/lib/index.js"
ただしこれだけでは動きません。import
が必要です。
// 以下を追加
import * as Popper from "@popperjs/core"
import * as Bootstrap from "bootstrap"
自分はとりあえずapp/javascripts/controllers/index.jsに書きましたが、app/javascripts/application.jsに書くのとどちらがよいのでしょう?🤔
まだrails new
のオプションではdartsass-railsをインストールできない
執筆時点のRails 7のrails new
オプションにはまだdartsass-railsは含まれていませんので、上記の方法で追加インストールする必要があります。今のところプルリクにも見当たりません。
現時点では、rails new -c sass -a propshaft
を指定してもpropshaftは無効になり、Node.jsが動き出してyarn add sass
でsassがインストールされます。
しかし最近のRails 7の動向を考えれば、そのうちrails new
でもdartsass-rails+propshaftのセットアップを指定できるようになるのではないかと期待しています。たとえば-c sass
を指定すると、-a propshaft
(または無指定でSprockets)の場合はdartsass-rails gemがインストールされ、-j esbuild
などを指定するとyarnでsassがインストールされる、という具合になるのかもしれません。
最後に
Rails 7でのフロントエンドの選択肢、特にNode.jsを使わない選択肢が少しずつ増えていることを実感します。node_modulesディレクトリが膨れ上がってデプロイ時のサイズが1GB近くなったみたいな話もちらほら聞くので、個人的にこの路線は好きです。
これからの課題だと思いますが、こうしたフロントエンドの選択肢についてRailsガイドにまとまったドキュメントが欲しいです。今は情報が周辺gemに散らばっていて追うのが大変ですが、これらが安定してきたらまとまったドキュメントに着手するだろうと期待しています。