RemixでMUIを使う
MUIのドキュメントの通りにRemix上で使おうとするとサーバービルドでエラーとなります。その対処案の一つのメモです。
エラー
MUIのコンポーネントを導入してみると、npm run dev(もしくはbuild)を実行で以下のようなエラーとなります。
11:41:02 [vite] Internal server error: Cannot use import statement outside a module
at wrapSafe (node:internal/modules/cjs/loader:1378:20)
at Module._compile (node:internal/modules/cjs/loader:1428:41)
at Module._extensions..js (node:internal/modules/cjs/loader:1548:10)
at Module.load (node:internal/modules/cjs/loader:1288:32)
at Module._load (node:internal/modules/cjs/loader:1104:12)
at cjsLoader (node:internal/modules/esm/translators:346:17)
at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:286:7)
at ModuleJob.run (node:internal/modules/esm/module_job:234:25)
at async ModuleLoader.import (node:internal/modules/esm/loader:473:24)
at async nodeImport (file:///path/to/project/node_modules/vite/dist/node/chunks/dep-CDnG8rE7.js:52999:15)
「Remix MUI」などで検索すると、対処方法が見つかります。
他ではあまり見かけなかった方法をメモしておきます。
環境
2024.9.26時点で試したバージョンです。
Node: 20.17.0
Remix: 2.12.1
MUI: 6.1.1
以下でセットアップした状態です。
% npx create-remix@latest
% npm i @mui/material @mui/icons-material @emotion/react @emotion/styled
対処方法
2段階の対処を行います。
クライアントのレンダリング時にコンポーネントが読み込まれるようにする
サーバービルドにMUIコンポーネントを含めないようにする
クライアントのレンダリング時にコンポーネントが読み込まれるようにする
app/root.tsx で useEffect を使い、クライアントのレンダリング時にコンポーネントが読み込まれるようにします。
export default function App() {
const [outlet, setOutlet] = useState<ReactElement | null>(null);
useEffect(() => {
setOutlet(<Outlet />);
}, []);
return outlet;
}
サーバービルドにMUIコンポーネントを含めないようにする
Remixのドキュメントにあるように *.client.tsx のファイルを作成します。viteを使っている場合は .client ディレクトリも使えるようです。
app/routes/components/buttons.client.tsx にMUIコンポーネントを記述します。
import DownloadIcon from "@mui/icons-material/Download";
export { DownloadIcon };
app/routes/_index.tsx で buttons.client.tsx を読み込みます。
import { DownloadIcon } from "./components/buttons.client";
export default function Index() {
return (
<div className="flex h-screen items-center justify-center">
<DownloadIcon />
TEST
</div>
);
}
以上で、エラーとならずにMUIコンポーネントが使えました。