Rails+Webpacker+Reactにbabel-plugin-react-css-modulesを入れる

RailsのWebpacker+Reactでフロントエンドを作っているのですが、コンポーネントへのスタイルの当て方にも色々あるんですね。
今回はCSS Modulesという設計に基づいたbabel-plugin-react-css-modulesというパッケージを入れてCSSのローカルスコープ化をしたのですが、使い方がよくわからず

Warning: React does not recognize the `styleName` prop on a DOM element.

というWarningが出続けてかなりハマったのでメモを残します。

注意

自分はwebpack/Babelともにそんなに詳しくないので、以下の内容は一部必要のない設定や誤解もあるかもしれません。何か気になったらコメントで指摘頂けるとありがたいです。

その前に:Webpackerのキャッシュを消す方法

/public/packsディレクトリにはWebpackerが作成したファイルが大量に作成されています。これは最新のもの以外必要ないですし、消せば作り直されます。
プラグイン等の設定を変更しても開発サーバがファイルをキャッシュして反映されない場合があるので、設定変更したのに何も変わらないと思ったときはpacks以下を全部消してしまうといいです。

パッケージインストール

config/webpack/environment.js

CSS ModulesをWebpackerに入れる方法については公式ドキュメントに解説がありました。
webpacker/webpack.md at master · rails/webpacker
Webpackerでは素のWebpackの設定ファイルであるwebpack.config.jsではなくconfig/webpack/以下にあるjsを使うようです。environment.jsがベースの設定、test/development/productionはそれぞれの環境固有の設定だと思います。上のリンクにあるとおりenvironment.jsを編集します。

その前にwebpack-mergeを使ってるのでインストール。

config/webpack/environment.js

ただここには2つの注意点がありました。

localIdentName

CSS ModulesではCSSのローカルスコープ化のため、クラス名が改変されます。その際HTML側のclass名とCSSのclass名の改変後のローカルスコープ名が一致しないとスタイルが当然反映されないのですが、Webpackerドキュメントの例にあるlocalIdentNameだとbabel-plugin-react-css-modulesの出力するDOM側のスコープ化クラス名と食い違いが発生していました。

現在のbabel-plugin-react-css-modulesのデフォルトに合わせるには

とする必要がありました。

babel-plugin-react-css-modulesのスコープ名のデフォルト形式は公式のOption一覧のgenerateScopedNameで確認できます。

CSS/SCSS

environment.loaders.get(‘sass’)の部分はCSSしか使わない場合(‘css’)に変える必要があるみたいです。SCSSを使う場合は’sass’。
ただどっちにしろ同じcss-loaderがインスタンス化されて使われるせいか、混在する場合片方書くだけで動いた何故か両方動いたのですが、順序などで問題が起こるかもしれません。よくわかりません。

Babel設定

PostCSSプラグイン追加

SCSSを使うには追加のPostCSSがSCSSを読み込むためのプラグインが必要みたいです。(後述:必要ないかも?)

.babelrc

.babelrcにのpluginsにreact-css-modulesを追加します。

こんな感じになります。配列なので追加する際1個上のプラグインにカンマを足すのを忘れずに。他のプラグインはプロジェクト作成初期から含まれてたものです。
SCSSを使わない場合はオプションを書く必要ありません。[“react-css-modules”]または”react-css-modules”で大丈夫です。

stylesheet_pack_tag

これも公式ドキュメントに書いてあるんですが、コンポーネントからのimportとは別にReactを使用するerb内でstylesheet_pack_tagでCSSを読み込む必要が何故かあります…。
ちなみにpublic/packs/manifest.jsonを見るとわかりますが、cssはどこに置いてもimportした側のjsと同じパスにマッピングされるようです。

例えば
javascript/packs/components/hoge.js
から相対パスで
javascript/src/hoge_style.css
をimportしていても、読み込み時は

となります。
スタイルをコンポーネントに対してローカル化するという思想上コンポーネントのパスになるということかと思います。

補足:postcss-scssは必要ないかも?

postcss-sccsはPostCSSにscssをパースさせるための構文プラグイン(実際にSCSSをCSSにコンパイルするわけではない)なんですが、これを入れずに.babelrcを

としたところ普通にscss使えてるような気がします。filetypesは書かないとscss拡張子が反応されないので必要です。
なぜドキュメントに反してこれが大丈夫だと思ったかというと、webpackerはデフォルトでcss-loaderの前にscssに対してsass-loaderを通してるはずで、sass-loaderはSCSSをCSSにコンパイルしているはずなんです。なのでcss-loaderに渡った時点でSCSSはCSSになってると思います。
ただ最初に言ったとおりwebpackもBabelも入門中なので理解が正しいかはわかりません。

補足2:CSSが出力されないとき

importを行っているのにCSSが出力されないと思ったら、コンポーネントのwebpackコンパイル自体が失敗している(jsxのタグ不整合など)せいだったということもあったのでそれも確認してみてください。

スポンサーリンク

シェアする

  • このエントリーをはてなブックマークに追加

フォローする