18 Jan 2017

This article will take about 3 minutes to read.
13 Comments

If you ever had to deploy React Router app to the subfolder on the server, you know what the problem is. Routes will get messed up once you upload it to the server. Here are two solutions I use in these cases.

Easy way, just use HashRouter

The easiest way to achieve this is to use HashRouter instead of BrowserRouter.

import { HashRouter } from 'react-router';

// Then in render
<HashRouter history={ hashHistory }>
  ...
</HashRouter>

This is the best approach if your subfolder name changes (for example, if folder name is a build version). But you’ll have /#/ included in the every URL. If this bothers you, check the second solution.

Example of the routes

Hard way, setting base path by hand

If you want to keep browser history implementation, you’ll need to change few things. First, we need to update our routes to include full absolute path to the subfolder.

Using React Router’s basename

As Davis Cabral pointed out in the comments, instead of manually adding publicPath to all routes, it can be achieved by using React Router’s basename prop.

import { BrowserRouter } from 'react-router';

// Then in render
<BrowserRouter basename='/path/to/subfolder/'>
  ...
</BrowserRouter>

Doing it by the hand

I define my routes something like this:

const publicPath = '/path/to/subfolder/';

export const routeCodes = {
  HOME: publicPath,
  SEARCH: `${ publicPath }search`,
  ABOUT: `${ publicPath }about`,
};

// Then you can use them like this
// <Route exact path={ routeCodes.ABOUT } component={ About } />

Setting up .htaccess file

Once uplodaded to the server any route (but root /) will return 404 error. For example, if you try to open http://yourserver.com/path/to/subfolder/about, server will look for file (or folder) named about in the app subfolder. As it doesn’t exist, it will fail with 404.

You’ll need to add a simple .htaccess file, in order to tell the server to fallback to our index.html file. This is the same configuration we would use if the application was on the server root, just with a different absolute path to our index file.

RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]

# Fallback all other routes to index.html
RewriteRule ^ /path/to/subfolder/index.html [L]

Now our example routes will look like this

Notice about webpack’s output -> publicPath configuration

If you are using publicPath in webpack’s output object, make sure you either remove it or update to match your server build path. Removing it is easier, as it will create relative links, which should work with your new configuration.

output: {
  publicPath: '/', // Remove, or update it
  path: './build',
  filename: 'app-[hash].js',
},

I’m also interested if anyone has different/better ideas, cheers!

Category
React

Comments (13)

And
24 Nov 2017, 12:19 PM

Thanks!

Wilfried
20 Feb 2018, 01:39 PM

Thank you, helped me to solve my routing problem on sub folders.

Biswajit
02 Mar 2018, 10:38 AM

Can you please tell me how I will add .htaccess file, if I am deploying into IIS server.My app is in sub folder.

I donot have access to iis server. I will do deploy using jenkins.

I will appreciate your help.

Stanko
02 Mar 2018, 04:50 PM

Hello @Biswajit,

Unfortunately, I can't help you with that as I have no experience with IIS, but a quick search provided me with Translate .htaccess Content to IIS web.config. Hopefully that will help you.

Cheers!

Biswajit
06 Mar 2018, 06:14 AM

I solved this problem by using HashRouthing instead of BrowserRouting .Just I want to know what will be the wrong of using it.

Stanko
06 Mar 2018, 10:42 AM

As I mentioned in the article already, the biggest drawback is that you'll have /#/ in your URLs.

Davis Cabral
23 Mar 2018, 08:42 PM

You can use the "Router" prop "basename" for this.

<Router basename={'/subdir'} history={history}>

</Router>

Mikkel
12 Apr 2018, 11:24 AM

Where are you storing the .htaccess file?

Stanko
12 Apr 2018, 01:46 PM

Hey @Mikkel, .htaccess should be at the root of your project (where your index.html is).

@Davis, that is pretty neat, I missed that prop, thanks!

TheKid_||_
11 May 2018, 02:40 AM

@Davis is the best solutions ;D

Ram
07 Jul 2018, 10:48 AM

@Stanko:

Instead of this snippet,

<BrowserRouter basename='/path/to/subfolder/'>

can't we use this one ?

<BrowserRouter basename={location.pathname}>

This make the path configurable and this will work even if the path of subfolder changes, what do you feel about this?

Stanko
09 Jul 2018, 12:26 PM

Hello Ram,

That won't work as location.pathname is dynamic property. For example it will be / on your home page, but something like /users/view/1 on user profile. Then all of your links would be relative to /users/view/1 instead of /.

Cheers!

Eugene
06 Sep 2018, 03:55 PM

Thanks Stanko, you're a legend!

Was looking for a solution for the past couple of hours and this worked like magic.

Leave a comment

Sending failed, please try again.
Thank you! Your comment is sent. Please note that all of the comments go through moderation.