Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Rails 7: dartsass-rails gemはNode.jsなしで使える

rails/dartsass-rails - GitHub

週刊Railsウォッチ20220228でもお伝えしましたが、つい最近、dartsass-rails gemがRailsのGitHubリポジトリで正式に登場しました。

dartsass-railsは、本家Dart Sassのバイナリ実行ファイルをラップしています。現時点ではLinuxとmacOSでi32版とx64版、Windowsでx64版のバイナリ実行ファイルがあります。今回初めて気づきましたが、Dart Sassは2016年のごく初期からバイナリ実行ファイルをリリースし続けているんですね。

sass/dart-sass - GitHub

参考: Releases · sass/dart-sass

どこかで見たような話ですね。そう、以下の記事にも書いたように、tailwindcss-rails gemもバイナリ版CLIツールをラップしています↓。最近のJSツールチェインはバイナリ版も出すのが流行りなのでしょうか。

Rails 7: importmap-rails + tailwindcss-railsでnode.jsが不要な理由

DHHがtailwind.cssとDart Sassで立て続けにバイナリをサポートしたのは、Rails 7で「Node.jsなしでできる選択肢を増やすため」だと私は考えています。

以下のDHHブログにこんなことが書かれています。

参考: Introducing Propshaft

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に散らばっていて追うのが大変ですが、これらが安定してきたらまとまったドキュメントに着手するだろうと期待しています。

関連記事

Propshaft gem README(翻訳)

Rails 7: importmap-rails gem README(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。