😇
Vike + TypeScript + React + MUI での SSR エラー解決方法
🗂️ 背景
Vike、TypeScript、React を使用してサイトを開発中に、ヘッダーで MUI のアイコンを使用した際、以下のようなエラーが発生しました。
TypeError: deepmerge is not a function
at createPalette (node_modules/@mui/material/styles/createPalette.js:244:25)
at createThemeNoVars (node_modules/@mui/material/styles/createThemeNoVars.js:27:19)
at createTheme (node_modules/@mui/material/styles/createTheme.js:53:14)
最初は @mui/material
のコンポーネントが原因かと思い確認を進めましたが、実際には以下のような @mui/icons-material
のアイコン使用部分 が原因でした。
import MenuIcon from "@mui/icons-material/Menu";
<IconButton color="inherit" edge="start" onClick={handleDrawerToggle} sx={{ mr: 2, display: { sm: "none" } }}>
<MenuIcon />
</IconButton>
このコードが SSR(サーバーサイドレンダリング)環境で問題を引き起こしていました。
🚀 解決策
Vite の設定ファイル vite.config.ts
を以下のように修正することで、エラーは解決しました。
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
import vike from "vike/plugin";
import { cjsInterop } from "vite-plugin-cjs-interop";
import { resolve } from "path";
export default defineConfig({
plugins: [
vike(),
react(),
cjsInterop({
dependencies: ["@mui/material/**", "@mui/icons-material/**"],
}),
],
ssr: {
noExternal: [
"@mui/icons-material", // ✅ MUI のアイコンライブラリを内部バンドル
"@mui/utils", // ✅ MUI のユーティリティ関数もバンドル
],
},
build: {
target: "es2022",
},
resolve: {
alias: {
"@": resolve(__dirname),
},
},
});
🔍 エラーの原因と詳細
✅ 原因 1: CommonJS と ES Modules の互換性問題
MUI の内部は ESM(ECMAScript Modules) と CJS(CommonJS) が混在しています。Vite は ESM を標準サポートしているため、CJS のモジュールを正しく処理できない場合があります。
そのため、vite-plugin-cjs-interop
を使用して、CJS モジュールを ESM 環境で適切に扱えるよう変換しています。
cjsInterop({
dependencies: ["@mui/material/**", "@mui/icons-material/**"],
});
-
dependencies
に対象パッケージを指定することで、互換性エラーを回避。 - MUI の内部モジュールすべてに適用するため、
/**
でワイルドカード指定しています。
✅ 原因 2: SSR 環境での依存関係の外部化問題
Vite はデフォルトで node_modules
内のライブラリを 外部依存(external) として処理します。
しかし、MUI では @mui/utils
や @mui/icons-material
などが内部で CommonJS 形式 で書かれており、Vite がこれらを正しくバンドルできずにエラーが発生します。
そのため、ssr.noExternal
に指定することで内部バンドルさせ、エラーを回避します。
ssr: {
noExternal: [
"@mui/icons-material", // ✅ SSR 環境で外部化せず内部でバンドル
"@mui/utils", // ✅ MUI のユーティリティ関数も内部で処理
],
},
-
noExternal
に追加することで、Vite が依存関係を外部化せず、自前で解決します。 - 特に SSR 環境で 「Cannot destructure property」エラー の防止に効果的です。
🚀 最終的なまとめ
問題 | 解決策 | 効果 |
---|---|---|
CJS と ESM の互換性エラー |
vite-plugin-cjs-interop を導入 |
CommonJS のモジュール互換性を確保 |
SSR での依存関係解決エラー |
ssr.noExternal に MUI パッケージを追加 |
SSR 環境でのモジュール解決エラーを防止 |
Vite のデフォルト外部化処理の問題 |
@mui/utils や @mui/icons-material を内部化 |
依存関係の不整合解決 |
🔗 参考資料
- vite-plugin-cjs-interop - npm
- Vite SSR Discussion (GitHub)
- Vite Official Documentation
- Zenn 記事 - Vite と MUI の互換性問題
MUI と Vite の組み合わせは柔軟で強力ですが、依存関係のバンドリングに注意が必要です。今回の設定で、安定した開発環境とパフォーマンスの向上が実現できます! 🚀
Discussion