Next.js with Material-UIでスタイルが崩れる


Next.jsMaterial-UIの組み合わせでビルドすると予期せぬ表示ずれがあった。

現象としてはnext.jsのPHASE_PRODUCTION_BUILDgetInitialProps()のあるページで初回読み込みをするとmakeStylesによるスタイルが崩れる。

ErrorやWarningはないし上記以外のアクセスではスタイル崩れもない。

結構複雑な問題だったので要点をまとめながら解決を図ります。

環境:next: 9.1.7material-ui: 4.8.3react: 16.12.0カスタムサーバー express: ^4.17.1

推察

next.jsとMaterial UIによる問題で以前クラス名が合わないエラーがあった。

初期アクセスで問題が起きるのでライフサイクルも考えると_documentが怪しい。

ビルドの有無で変わることからコンパイルの処理も見る必要がありそう。

該当箇所の確認

Appbar、Toolbarの独自スタイルがちゃんと効いていない。

この書き方以外でclassesrootなどを書き換える方法も試したが同じだった。

上記コードで出来るのは.makeStyles-appBar-4だったが、そのクラス自体はちゃんと定義されている。

ただそれより上位に.MuiAppBar-colorPrimaryなどがあることでおかしくなってる。

原因の深堀

  • 1.PHASE_DEVELOPMENT_SERVERでは期待通り
  • 2.PHASE_PRODUCTION_BUILDgetInitialPropsのないページを表示後、内部遷移でgetInitialPropsのあるページに移動すると期待通り
  • 3.PHASE_PRODUCTION_BUILDgetInitialPropsのあるページを初回表示時、makeStylesが適応されない状態になる

2と3のページソースを見ても変化はない。

ディベロッパーツールで要素を見てみる。

  • MuiPaper-root MuiAppBar-root MuiAppBar-positionFixed makeStyles-appBar-4 MuiAppBar-colorPrimary mui-fixed MuiPaper-elevation4
  • MuiPaper-root MuiAppBar-root MuiAppBar-positionFixed jss4 MuiAppBar-colorPrimary mui-fixed MuiPaper-elevation4
  • MuiPaper-root MuiAppBar-root MuiAppBar-positionFixed makeStyles-appBar-4 MuiAppBar-colorPrimary mui-fixed MuiPaper-elevation4

buildするとmakeStylesによるクラスが.jssとして再定義されるが3の状態だと元のままになっているのが問題だと考えられる。

またgetInitialProps内で非同期処理をしない(return {}するだけ)場合でも解決しなかったのでSSR(サーバーサイドレンダリング)の有無が問題に見える。

解決案

ここまで問題を見てきて解決方法は2つ思いつきます。

  • makeStyles-appBar-4は存在するんだから上位に設定する
  • SSRするページのクラスもjssになるようにコンパイラをいじる

1はスタイルがdevと同じように設定されるように微調整を行うことになります。

一番簡単な方法はmakeStyles内の値に!importantを付けること。

2はこのサンプルwith-react-jssを見るとJssProviderでどうにかしようとしていますが、material uiのバージョンとreact-jssのバージョンの違いでうまくいかない感じになります(generateClassNameの再定義が出来ない)。

うーん。

そもそもの原因は?

対処療法に傾きつつあったのでnextかreactかmaterial ui(jss)か何が悪いのか。

色々探索する中でMaterial UIのソースを見てるとif (process.env.NODE_ENV !== 'production')が所々にあることに気づいた。

試しにNODE_ENVproductionにするとSSRするページでも.jssクラスが付与されることを確認できた。

複数環境での動作のためにNODE_ENV=production1とかにしていたのが裏目だったか。

まさかこんなことでこんなに悩むとは。

しかしNODE_ENVで動作が変わるのってどうなんだろう…。

実際に処理でNODE_ENV分岐をしてるのが誰(どこ)なのかはわかりませんが、疲れたのでとりあえずbuild&startするときはNODE_ENVproductionに。


コメントを残す

メールアドレスが公開されることはありません。