apache2 react vite ページ真っ白 になる原因と解決方法を記載します。
環境
- OS: Debian9
- apache2
- rewriteモジュールインストール済み
- react vite
- ionic react v8
現象
- reactのビルド結果を配置してブラウザでページを閲覧しても画面が真っ白になる
- index.html、各種jsファイルはブラウザで正常に取得できている
- ブラウザコンソールにエラーなし
すでにapache2で以下のようなSPAのindex.htmlへのrewrite設定は実施済み
/etc/apache2/apache2.conf
<IfModule mod_ssl.c>
<VirtualHost *:443>
DocumentRoot /var/www/html
ServerName ドメイン名
ErrorLog ${APACHE_LOG_DIR}/error_blog.log
CustomLog ${APACHE_LOG_DIR}/access_blog.log combined
# ssl設定 省略
# エイリアス設定
Alias /sample /var/www/sample
<Directory /var/www/sample>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
#SPA用のRewrite設定
RewriteEngine On
#RewriteCond %{REQUEST_URI} !^/arsenals/api/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.html [QSA,L]
</Directory>
</VirtualHost>
</IfModule>
Apachereact vite ページ真っ白 原因
結論から言うとhttps://ドメイン名/sampleの`/sample`のようなエイリアス付きでアクセスした場合に、
viteとreactルーティングに追加で設定が必要でした。このページに助けられました。
react vite ページ真っ白 解決方法
vite.config.ts base設定
エイリアス付きでアクセスする場合、ビルド後のindex.htmlがjsファイルの読み込みを行う際にbaseパスの設定が必要です。
この設定が漏れていた場合は、ブラウザのコンソールでjsファイルが取得できないエラーなどが出るはずです。
vite.config.ts
/// <reference types="vitest" />
import legacy from '@vitejs/plugin-legacy'
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'
// https://vitejs.dev/config/
export default defineConfig({
base: "/sample/",
plugins: [
react(),
legacy()
]
})
TypeScript設定ができていた場合、ビルド後のindex.htmlが以下のようになります。(*Ionic reactで作成しているので他フレームワークにはない内容が一部含まれる)
24行目などを見るとファイルの読み込みがエイリアス付きでの指定になっています。
/dist/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Ionic App</title>
<base href="/" />
<meta name="color-scheme" content="light dark" />
<meta name="viewport"
content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="format-detection" content="telephone=no" />
<meta name="msapplication-tap-highlight" content="no" />
<link rel="manifest" href="/sample/manifest.json" />
<link rel="shortcut icon" type="image/png" href="/sample/favicon.png" />
<!-- add to homescreen for ios -->
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-title" content="Ionic App" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<script type="module" crossorigin src="/sample/assets/index-CowCIwGH.js"></script>
<link rel="stylesheet" crossorigin href="/sample/assets/index-jFSyunOD.css">
<script
type="module">import.meta.url; import("_").catch(() => 1); (async function* () { })().next(); if (location.protocol != "file:") { window.__vite_is_modern_browser = true }</script>
<script
type="module">!function () { if (window.__vite_is_modern_browser) return; console.warn("vite: loading legacy chunks, syntax error above and the same error below should be ignored"); var e = document.getElementById("vite-legacy-polyfill"), n = document.createElement("script"); n.src = e.src, n.onload = function () { System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src')) }, document.body.appendChild(n) }();</script>
</head>
<body>
<div id="root"></div>
<script
nomodule>!function () { var e = document, t = e.createElement("script"); if (!("noModule" in t) && "onbeforeload" in t) { var n = !1; e.addEventListener("beforeload", (function (e) { if (e.target === t) n = !0; else if (!e.target.hasAttribute("nomodule") || !n) return; e.preventDefault() }), !0), t.type = "module", t.src = ".", e.head.appendChild(t), t.remove() } }();</script>
<script nomodule crossorigin id="vite-legacy-polyfill" src="assets/polyfills-legacy-BuKq33Og.js"></script>
<script nomodule crossorigin id="vite-legacy-entry"
data-src="assets/index-legacy-DHBEouAT.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
</body>
</html>
HTMLBrowserRouter basename設定漏れ
実は上記だけでは、ブラウザのエラーは消えますが画面は真っ白なままになります。
エイリアス付きの場合は、BrowserRouterにbasename設定を追加してやる必要があります。
この設定が漏れていたせいでルーティングに失敗し常に真っ白な画面が表示されてしまっていました。
src/App.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import App from './App';
import Page1 from './Page1';
import Page2 from './Page2';
// `import.meta.env.BASE_URL` を `basename` に渡す
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<BrowserRouter basename={import.meta.env.BASE_URL}>
<Routes>
<Route path="/" element={<App />} />
<Route path="/page1" element={<Page1 />} />
<Route path="/page2" element={<Page2 />} />
</Routes>
</BrowserRouter>
</React.StrictMode>
);
TSX以上
他のReactの記事はこちら