reactjsgithubgithub-actionsgithub-pagestanstack-router

Encountered an issue deploying my website (Vite+React) to GitHub Pages


I'm using TanStack Router to create routes for my website, and everything works well when navigating through the application. However, I'm encountering a 404 error when I refresh a route page or access it directly on GitHub Pages. The error message indicates File not found.

Vite Configuration

//I have set the base URL in my vite.config.ts file to /portfolio:

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
import { TanStackRouterVite } from '@tanstack/router-plugin/vite';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react(), TanStackRouterVite()],
  base: '/portfolio/',
});

File-Based Routes My project structure for routes is as follows:

- portfolio
  - index.lazy.tsx
  - about
    - index.lazy.tsx
  - etc...

GitHub Actions Deployment I deployed my app using the following deploy.yml configuration:

name: Deploy

on:
  push:
    branches:
      - main

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repo
        uses: actions/checkout@v3

      - name: Setup Node
        uses: actions/setup-node@v3

      - name: Install dependencies
        uses: bahmutov/npm-install@v1

      - name: Build project
        run: npm run build

      - name: Upload production-ready build files
        uses: actions/upload-artifact@v3
        with:
          name: production-files
          path: ./dist

  deploy:
    name: Deploy
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'

    steps:
      - name: Download artifact
        uses: actions/download-artifact@v3
        with:
          name: production-files
          path: ./dist

      - name: Deploy to GitHub Pages
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./dist

[https://samir0ps.github.io/portfolio] [https://github.com/samir0ps/portfolio]

You can view my website here and the total code.

I configured my Vite project to use TanStack Router for routing, set the base URL in vite.config.ts, and organized my routes using a file-based structure. Additionally, I created a GitHub Actions workflow (deploy.yml) to automate the build and deployment process to GitHub Pages. I expected the website to function correctly, including seamless routing through TanStack Router, even when refreshing a route page or accessing it directly on GitHub Pages. Specifically, I anticipated that my configuration and deployment setup would prevent 404 errors on page refresh, ensuring that all routes are correctly handled.


Solution

  • I fixed this error by creating 404.html file in the public folder which containes :

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8" />
        <title>React Router</title>
        <script type="text/javascript">
          // Number of path segments to keep in the URL
          var pathSegmentsToKeep = 1;
          
          // Get the current location object
          var l = window.location;
          
          // Rebuild the URL
          var newUrl =
            l.protocol + "//" + l.hostname + (l.port ? ":" + l.port : "") + 
            l.pathname.split("/").slice(0, 1 + pathSegmentsToKeep).join("/") + 
            "/?/" + 
            l.pathname.slice(1).split("/").slice(pathSegmentsToKeep).join("/").replace(/&/g, "~and~") + 
            (l.search ? "&" + l.search.slice(1).replace(/&/g, "~and~") : "") + 
            l.hash;
          
          // Check if the current URL does not already match the new URL to avoid infinite redirect loop
          if (l.href !== newUrl) {
            l.replace(newUrl);
          }
        </script>
      </head>
      <body></body>
    </html>
    

    And I added a script to the index.html file of the application :

    <!doctype html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <link rel="icon" type="image/svg+xml" href="../portfolio/src/assets/logo.svg" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Portfolio</title>
        <script type="text/javascript">
          (function (l) {
            if (l.search[1] === "/") {
              var decoded = l.search
                .slice(1)
                .split("&")
                .map(function (s) {
                  return s.replace(/~and~/g, "&");
                })
                .join("?");
              window.history.replaceState(null, null, l.pathname.slice(0, -1) + decoded + l.hash);
            }
          })(window.location);
        </script>
      </head>
      <body class=" bg-darkmain text-light">
        <div id="root"></div>
        <script type="module" src="/src/main.tsx"></script>
      </body>
    </html>
    

    I hope this is helpful.