Search code examples
javascriptreactjstypescriptreact-router-domgithub-pages

React App shows blank screen on gh-pages after deployment - existing suggestions from SO is implemented already


I am trying to deploy my react app using React-Router-DOM for client redirection using Github pages.

After deployment I get an empty page - none of the component content is loaded in DOM except the one which outside the routing context.

As part of debugging I have gone through the Stack Overflow discussions already discussing the issue.

I followed the changes suggested in React Router not working with Github Pages but it doesn't resolve the issue.

I did the following changes as per suggestion from other stack overflow discussion and the one present on the react app Deployment:

  1. replaced createBrowserRouter with createHashRouter

  2. provide the basename of my createHashRouter as the repo name.

  3. checked the homepage of package.json and its correct as per the documentation.

  4. set the 'private' property in package.json to false.

After doing the above changes when deployed the build, the index.html of build shows the following:

<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <link rel="icon" href="/FrontEndQuizApp/favicon.ico" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta name="description" content="Web site created using create-react-app" />
    <link rel="apple-touch-icon" href="/FrontEndQuizApp/logo192.png" />
    <link rel="manifest" href="/FrontEndQuizApp/manifest.json" />
    <title>React App</title>
    <script defer="defer" src="/FrontEndQuizApp/static/js/main.ea628bb2.js"></script>
    <link href="/FrontEndQuizApp/static/css/main.2f2eb39d.css" rel="stylesheet">
</head>

<body><noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
</body>

</html>

But my javascript is enabled for the site and browser.

code snippet from my app is as:

Index.tsx - where the routing is implemented -

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import QuestionComp from "./components/QuestionComp";
import {
  createHashRouter,
  FutureConfig,
  RouterProvider,
} from "react-router-dom";

import { store } from "./store";
import { Provider } from "react-redux";
import { ToggleProvider } from "./components/ThemeToggleContext";
import ThemeToggle from "./components/ThemeToggel";
import GlobalBackground from "./components/GlobalBackground";

const router = createHashRouter(
  [
    {
      path: "/*",
      element: <App />,
    },
    {
      path: "/Question",
      element: <QuestionComp />,
    },
  ],
  { basename: "/FrontEndQuizApp" }
);

// declare function RouterProvider(props: RouterProviderProps): React.ReactElement;

interface RouterProviderProps {
  fallbackElement?: React.ReactNode;
  router: any;
  future?: FutureConfig;
}

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);

root.render(
  <React.StrictMode>
    <ToggleProvider>
      <GlobalBackground>
        <ThemeToggle></ThemeToggle>
        <Provider store={store}>
          <RouterProvider router={router} />
        </Provider>
      </GlobalBackground>
    </ToggleProvider>
  </React.StrictMode>
);

reportWebVitals();

Package.json - where the homepage has been set for the project -

{
  "name": "quizreactapp",
  "version": "0.1.0",
  "private": false,
  "homepage": "https://ayushi186.github.io/FrontEndQuizApp",
  "dependencies": {
    "@redux-devtools/extension": "^3.3.0",
    "@reduxjs/toolkit": "^2.2.7",
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "@types/jest": "^27.5.2",
    "@types/node": "^16.18.101",
    "@types/react": "^18.3.3",
    "@types/react-dom": "^18.3.0",
    "i": "^0.3.7",
    "npm": "^10.8.3",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-js-switch": "^1.1.6",
    "react-redux": "^9.1.2",
    "react-router-dom": "^6.24.1",
    "react-scripts": "5.0.1",
    "react-switch": "^7.1.0",
    "redux-devtools-extension": "^2.13.9",
    "sass": "^1.80.3",
    "styled-components": "^6.1.11",
    "typescript": "^4.9.5",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "predeploy": "npm run build",
    "deploy": "gh-pages -d build"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "gh-pages": "^6.2.0"
  }
}

Output of the app after deployment to gh-pages -

my app output after deployment to gh-pages


Solution

  • Issue

    You have incorrectly added a basename property to your router configuration. If you manually navigate to "/FrontEndQuizApp", e.g. "https://ayushi186.github.io/FrontEndQuizApp/#/FrontEndQuizApp" then you will correctly see your app content rendered into the DOM.

    app page

    Solution

    The basename prop is primarily used when you are hosting/serving your React app from a sub-directory on the server somewhere and you need to let the router know where it is so it can correctly use the URL path, but the HashRouter eliminates this as a problem since it uses the URL hash for routing and navigation. In other words, it doesn't matter what directory the app is served from.

    The problem when you specify a basename property with the HashRouter is that it still does the same thing as if you weren't using hash routing, e.g. it informs the router, routes, links, etc, to all work and function relative to the specific basename, so instead of working relative from "#/" they work relative from "#/FrontEndQuizApp".

    To resolve this discrepancy remove the basename from the router configuration:

    const router = createHashRouter(
      [
        {
          path: "/*",
          element: <App />,
        },
        {
          path: "/Question",
          element: <QuestionComp />,
        },
      ],
    );
    

    This allows the app routes/links/etc to all work and operate from "https://ayushi186.github.io/FrontEndQuizApp/#/".