apache2 react vite ページ真っ白

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>
Apache

react 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>
HTML

BrowserRouter 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の記事はこちら

コメントする