本番環境で assets:precompile を実行した瞬間、SassC::SyntaxError: Error: Invalid CSS after "…": expected expression (e.g. 1px, bold), was ".png);" というエラーで真っ赤になった——そんな経験はありませんか?ローカルの開発環境では何ごともなく動いていたのに、いざデプロイという場面で出ると焦りますよね。この記事では、このエラーの原因といちばん手っ取り早い解決方法、そしてRails 7・8 では状況がどう変わったのかまでまとめて解説します。
まず出たエラーを再現する
今回のエラーは、CSS で背景画像を指定している箇所で発生していました。ローカルでプリコンパイルを試すと、同じエラーを手元で再現できます。
$ RAILS_ENV=production rails assets:precompile問題になっていたのは、次のような1行です。見た目には何もおかしくないように見えますよね。
background-image: image-url('hoge.png');原因を切り分けるときは、app/assets/stylesheets 配下のファイルを一度すべてコメントアウトし、ローカルで assets:precompile が通る状態から少しずつ戻していくのが確実です。そうやって特定していくと、この image-url() を使った行でエラーが起きていました。
原因:image-url は「SCSS用」のヘルパーだから
結論から言うと、image-url(や asset-url / asset-path)は素の CSS では使えません。これらは sass-rails が提供する Sass 用の関数で、Sass コンパイラ(SassC)を通る .scss / .sass ファイルの中でしか展開されないからです。
つまり、拡張子が .css のファイルに image-url('hoge.png') と書くと、SassC は image-url(...) を「知らない関数呼び出し」として解釈しようとして構文エラーになります。これがエラーメッセージ末尾の was ".png);" の正体です。ファイル自体は正しい CSS のつもりでも、Sass の世界では未定義の関数を呼んでいる、という状態なんですね。
解決方法:拡張子を .css → .scss に変える
いちばん手っ取り早い対処は、該当ファイルの拡張子を .css から .scss に変えることです。
# 例:hoge.css を hoge.scss にリネームする
$ git mv app/assets/stylesheets/hoge.css app/assets/stylesheets/hoge.scssこれで、このファイルが Sass コンパイラを通るようになり、image-url() が正しく展開されてプリコンパイルが成功します。今回のケースはこれだけで解決しました。sass-rails(sassc-rails)を使っている Rails 6 世代のアプリなら、この対処がそのまま効きます。
もう一つの選択肢として、拡張子はそのままにして image-url() を素の url() に書き換える方法もあります。ただしこの場合、後述のとおり画像パスにフィンガープリント(ダイジェスト)が付くかどうかは、使っているアセットパイプラインしだいになります。
Rails 7・8 ではそもそも image-url を使わない
ここが、この記事でいちばんお伝えしたいポイントです。上記は Sprockets + sass-rails 前提の話ですが、Rails 7・8 では前提が大きく変わっています。新しいアプリでこのエラーに出会ったら、対処の方向性も変わってきます。
- Rails 8 の標準アセットパイプラインは Propshaft になりました(従来の Sprockets を置き換え)。Propshaft は CSS 内の
url(...)を自動でダイジェスト付きパスに書き換えてくれます。 - LibSass ベースの sassc / sassc-rails は開発終了(deprecated)です。今 Sass を使うなら Dart Sass 版の dartsass-rails が標準的な選択肢です。
そして重要なのが、Propshaft や dartsass-rails では image-url() / asset-url() のような Rails 独自の Sass ヘルパーは使えないという点です。これらは sass-rails 固有の機能だったため、Dart Sass に移行すると存在しません。
では今どきはどう書くのか。答えはシンプルで、素の url() を使うだけです。
// 昔(sass-rails): SCSS でしか使えないヘルパー
background-image: image-url("hoge.png");
// 今(Propshaft / dartsass-rails): 素の url() でOK
background-image: url("hoge.png");Propshaft を使っていれば、url("hoge.png") は本番ビルド時に url("/assets/hoge-2169cbef.png") のようにダイジェスト付きへ自動変換されます。image-url を使わなくてもキャッシュ対策(フィンガープリント)はきちんと効くので安心してください。逆に言うと、Rails 7・8 の新規アプリで image-url() を書くと「そんな関数はない」とエラーになるので、素の url() に統一するのが正解です。
まとめ:Railsのバージョンで対処が変わる
同じ SassC::SyntaxError でも、使っているアセットパイプラインによって正しい直し方が変わります。整理すると次のとおりです。
- Sprockets + sass-rails(Rails 6 世代):
image-url()は SCSS 専用。拡張子を.css→.scssに変えれば解決。 - Propshaft + dartsass-rails(Rails 7・8):
image-url()は使えない。素のurl("hoge.png")で書けば、Propshaft がダイジェスト付きパスに自動変換してくれる。
エラーメッセージの見た目に惑わされず、「今このアプリは何でアセットを処理しているのか」を確認するのが解決の近道です。原因が特定できないときの調べ方は、エンジニアの仕事は「知っていること」より「調べられること」も参考にしてみてください。Rails のフロントエンド周りをもう少し整えたい方は、RailsにTailwind CSS v4を導入する方法もあわせてどうぞ。
スポンサーリンク
