This web page requires JavaScript to be enabled.

JavaScript is an object-oriented computer programming language commonly used to create interactive effects within web browsers.

How to enable JavaScript?

SPA get 404 error when refreshing the page or access directly and SEO?

Blog, Snippets November 1, 2022 0

When developing and deploying SPA app, eg: Reactjs, the navigation between pages works perfectly by clicking through several routes and everything seemed fine.

Somehow the URL looks like:

…until we refreshed the page or tried to access a route directly. We got a 404 error.

Nam Le

One of working around solution:

Use HashRouter instead of BrowserRouter.

Then, we can try to refresh or enter directly the page. Okay that would be an easy one.

But since we want to have nice and clean URLs without the hash # (a.k.a URI fragments), that was no option. So let’s dig deeper and have a look at the reason for the error.

When we’re visiting a route of your app directly, web server tries to map the URL to a file/resource in the public folder. In this case it looks for /job/431.html which obviously doesn’t exist – therefore the 404 error.

To avoid that, we have to tell web server to redirect all requests to our index.html, so our app can perform some routing magic for that URL.

Step 1 – Config the Web Server

We have various configs based on your web server platform.

Apache httpd .htaccess

RewriteEngine On
# If an existing asset or directory is requested go to it as it is
RewriteRule ^ - [L]

# If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html


server {
  root /var/www/mysite/; # or location of your choice
  index index.html;

  location /{
    try_files $uri $uri/ =404;

Node.js/ Express

app.get('/*', function(req, res) {
  res.sendFile(path.join(__dirname, 'path/to/your/index.html'), function(err) {
    if (err) {

IIS web.config

We have to install URL Rewrite for this to work.

<?xml version="1.0" encoding="UTF-8"?>
                <rule name="Handle HTML5 History Mode " stopProcessing="true">
                    <match url="(.*)" />
                    <conditions logicalGrouping="MatchAll">
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                    <action type="Rewrite" url="/" />

Webpack 5 devServer.proxy

With Webpack 5, we have some configs. Please refer here:

Step 2 – Enabling HTML5 mode in different frameworks & routers

In index.html, be sure to include a base href, like so:

<base href="/">




With react-router-dom, Use BrowserRouter instead of HashRouter.

BrowserRouter is a router implementation that uses the HTML5 history API (pushstate, replacestate, and popstate events) to keep your UI in sync with the URL. It is the parent component used to store all other components.


We need to set the router mode to history. Reference

const router = new VueRouter({
  mode: 'history',
  routes: [...]

One more thing about … SEO

The issue with this is that now Google doesn’t consider this an AJAX Single Page Application. SPAs with client-side routing should implement the History API to change pages.

We can do this relatively easily with SSR like Next.js?

There is a good part: Google itself suggests that to benefit from proper indexing with topic Understand the JavaScript SEO basics, which will be discussed next topic.

Original written from my blog:
@Le Quoc Nam, Saigon, 01 Nov 2022

Last modified on February 9th, 2023 at 10:37 pm

Nam Le

0 responds

Leave a Reply

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.