Next.jsでMaterial UIのコンポーネントを使うために次のようにインポートしてみる。
import { Paper, Typography } from "@mui/material";
これでビルドすると生成されたバンドルファイルのサイズが大きくなり、ビルド時間も長くなってしまう。
bundle-analyzerでファイルを可視化してみると、使われていないMUIコンポーネントまでもバンドルされて巨大なファイルが生成されていた。
コンポーネントごとに個別にインポートする。
import Paper from "@mui/material/Paper";import Typography from "@mui/material/Typography";
これにより必要なモジュールだけがバンドルされ、ファイルサイズもだいぶ小さくなった。
でも、これだとひとつひとつimportを書くのは面倒だし、VSCodeの自動でまとめてimportしてくれる機能を使うと
import { Paper, Typography } from "@mui/material"
のような書き方になってしまう。
大量のimportが並ぶのも可読性が低くなるしなにかと不便。
next.config.jsにmodularizeImportsを設定する。
const nextConfig = { ... modularizeImports: { '@mui/material': { transform: '@mui/material/{{member}}', }, '@mui/icons-material': { transform: '@mui/icons-material/{{member}}', }, }};
これにより、
import { Paper, Typography } from "@mui/material";
と書いたものが、ビルド時に
import Paper from "@mui/material/Paper";import Typography from "@mui/material/Typography";
へと自動で変換してくれる。
生成されたファイルサイズも上記と同じだった。
注意点としては、まとめてインポートできるのは基本的にコンポーネントとアイコンだけである。
たとえば次のようなimportをしたとする。
import { css } from "@mui/material";
これは、
import css from "@mui/material/css";
と変換されるがそんなモジュールは存在しないのでエラーとなる。
この場合は個別にimportしなければならない。
import { css } from "@mui/material/styles";
Next.jsのバージョンを14.0.4にアップグレードして解決策その2を使ったところ、次のエラーが出てビルドできない問題が発生した。
Error: Element type is invalid. Received a promise that resolves to: undefined. Lazy element type must resolve to a class or function.
issuesにも同様の問題があがっていた。
[material-ui] Not working after upgrading Next.js to 14.0.4. Error: Element type is invalid.
Next.js 14.0.3にダウングレードするか、解決策その1に変更すればエラーは出なくなる。