Search code examples
reactjsnext.jsroutesnext-router

Routing resets to home on refresh for Next.js Site Deployed to Firebase Hosting


I have created a static website using Next.js and Tailwind CSS with several pages, including Home, Services, and Contact. Each route correctly navigates to its respective page. Everything works fine on localhost, but when I deploy the build to Firebase Hosting, the routes work only if I don't refresh the page. If I refresh the page, the site defaults to the Home page and I can't navigate to other pages. For example, if I navigate to the Services page and then refresh the page, it shows the Home page while the URL still indicates the Services page.

Here is my code -

import { memo, useEffect, useState } from 'react'; 
import Link from "next/link";
import Banner from "./Banner";
import Button from './Buttons';
import Image from "next/image"; 
import { AppRoutes } from '@/constants/appRoutes'; 
import BrandLogo from '@/assets/yume-logo.svg'
import BrandLogoText from '@/assets/yume-logo-text.svg'  
import { usePathname } from 'next/navigation';
 

const Header = () =>{ 

    // Get the current pathname from the router.
    const router = usePathname()  

    // State to manage the active navigation item and menu open/close status.
    const [activeNav, setActiveNav] = useState('');
    const [menuOpen, setMenuOpen] = useState(false);

    // Update the activeNav state when the pathname changes.
    useEffect(() => {
        setActiveNav(router);
    }, [router]);

    // Toggle the menu open/close status.
    const toggleMenu = () => {
        setMenuOpen(!menuOpen);
    };

    // Close the menu when a navigation item is clicked.
    const closeMenu = () => {
        setMenuOpen(false);
    };

    return(
        <>
            <Banner/> 
            <header className="sticky top-0 w-full z-40 md:py-1 py-0 bg-white drop-shadow-sm"> 
                <nav className='container md:max-w-screen-xl mx-auto flex flex-col md:justify-between md:flex-row md:px-0'>
                    <div className='flex justify-between w-full px-8 py-4'>
                        <Link
                            className='flex gap-4 items-center max-w-fit'
                            onClick={closeMenu}
                            href={AppRoutes.HOME_PAGE}>
                        <Image 
                                className='h-7 max-w-fit'
                                src={BrandLogo}
                                alt="yume labs logo" />
                            <Image
                                className='h-3 max-w-fit' 
                                src={BrandLogoText}
                                alt="yume labs logo" />
                        </Link>

                        <div className="w-8 h-8 flex flex-col align-middle justify-center gap-1 md:hidden" onClick={toggleMenu} aria-hidden>
                            <div className='w-full h-1 bg-gray-600'></div>
                            <div className='w-full h-1 bg-gray-600'></div>
                            <div className='w-full h-1 bg-gray-600'></div>
                        </div>
                    </div>

                    <div className='flex md:flex-row flex-col md:items-center gap-4 md:w-fit py-8 md:py-0'>
                        <div className='px-8 py-4 flex'>
                            <Link
                                className='w-full h-full whitespace-nowrap'
                                href={AppRoutes.SERVICES}>
                                Our Services
                            </Link> 
                        </div>
                        <div className='px-8 md:px-0'>
                            <Link 
                                href={AppRoutes.CONTACT_US}>
                                <Button
                                    label='Contact Us'
                                    btnsize='sm'
                                    type='button'
                                />
                            </Link>  
                        </div> 
                    </div> 
                </nav>
            </header>
        </>
    )
}

export default memo(Header)

Solution

  • I have finally found the answer. It is the problem related with firebase and how it handles client side routing for single-page applications.

    Basically, firebase hosting serves the index.html file whenever a request does not match a file in the public directory, which results in the app being unable to handle the routing correctly upon refresh.

    I had to add cleanURLs in firebase Json

    {
      "hosting": {
        "public": "out",
        "cleanUrls": true,
        "rewrites": [
          {
            "source": "**",
            "destination": "/index.html"
          }
        ]
      }
    }