Timing can be funny, but it this case, it was perfect. I discovered I was having a problem with 404s on Netlify last night. Before I got the time to look into it, the lecture we had today was on deploying a React site on Netlify and the steps to make React Router work in production.
If only all my bugs could be solved that way.
Why Netlify Returns a 404 on React Router URLs
This is a React site and I'm using React Router to define the URLs for individual pages, such as /blog and each of the blog posts. It works great for navigating around the site using links and the nav bar.
But I was forgetting one key thing.
With React Router links, we stay in the context of the BrowserRouter and the URLs React Router provides. We are never making a request to the server for a particular URL.
This is not the case when we enter something in the URL bar. Or, in my case last night, refresh /blog page to see if I could get the API call to work. In these instances, the browser is saying, "Send me whatever resource you have at /blog." To which Netlify answers, "I don't have anything there. Here's a 404." There is nothing there because I have an SPA. There are no individual pages.
This isn't just a Netlify problem, but the solution depends on which deployment method you're using. Since I'm on Netlify, that's what I'll go over here.
Accessing URLs on an SPA on Netlify
Admittedly I sat through the lecture on deployment several months ago, but apparently I forgot this key piece. How great it was to then get a second chance reminder today. To fix my issue, I:
- Added a file called
_redirects
to the root of my project - Added the line
/* /index.html 200
to the file - In Netlify, I went to my site > Site Configuration > Build & Deploy, and then updated the Build Command to be
npm run build && cp _redirects build
- Pushed all changes to GitHub
My site redeploys after any pushes, so that had it fixed in a couple minutes. What is happening here is this:
/*
is a wildcard to listen for all subdirectories on my domain- We then tell Netlify to return /index.html (the entirety of our SPA) and a 200 status code for those URLs
- At this point, React Router can take over and render the correct components
I did Google this issue shortly after and it does seem to be an easy to miss one. Hopefully writing this out means I will not forget it on my next deploy!