I have my website hosted on a subdirectory, as an example, http://mywebsite/admin, where /admin is the subdirectory
I have my react app (create-react-app production build) uploaded into the /admin subdirectory. I am also using react-router v4 BrowserRouter to have some simple client-side routing performed. Below are some relevant snippets on my react-app:
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
import { BrowserRouter } from 'react-router-dom';
import './css/custom.css';
ReactDOM.render(<BrowserRouter basename="/admin"><App /></BrowserRouter>, document.getElementById("root"));
inside App.jsx render function
<Route
path='/students'
render={(props) =>
<Students
{...props}
/>
}
/>
<Route
path='/teachers'
render={(props) =>
<Teachers
{...props}
/>
}
/>
All is well and working when navigating the site including the nested urls which are mainly, as you have seen on the snippets, /admin/students
& /admin/teachers
.
The main issue: when I am on the /admin/teachers
route and I refresh the page, the page does not load anything. Refreshing works when I am on /admin
route only. But not when it is /admin/teachers
nor /admin/students
.
This is not the first time I have built an SPA using react-router v4 hosted on Apache server. I have reused the .htaccess I have on my previous project. This .htaccess also resides at the /admin
subdirectory. Below is the .htaccess
:
.htaccess
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.html?path=$1 [NC,L,QSA]
This routes all requests to the index.html built by the create-react-app production build. However, upon my investigations, this type of configuration only works on a project that is not on a subdirectory and is not using nested URLs.
Note, that I have 2 .htaccess
now. One on root and another one at the /admin
subdirectory. Both contain the same .htaccess
codes. The reason for this is, I have another SPA running at the root directory.
What am I missing?
How to Properly Configure Apache on a SPA React App that Resides on a Subdirectory that uses Nested URLs built from React Router?
3
Answers
This is where I made a mistake:
Simply adjusting my root
.htaccess
and deleting the.htaccess
that was inside the /admin subdirectory fixed the main issue described on my question.Root .htaccess:
I actually don’t know the answer to your problem, but I can suggest you to play with
Location
directive; something likeHope this helps.
Primarily addressing the OP’s answer, plus some other notes…
This wasn’t necessarily a "mistake" – you would just need to make sure you are using the correct directives. In fact, keeping the two
.htaccess
files separate could be preferable if these are intended to be entirely separate SPAs.To have two separate – identical –
.htaccess
files the important points are:RewriteBase
directive. (Which would override the directory-prefix.)When the
RewriteRule
substitution string is a relative path then the directory-prefix (ie. the location of the.htaccess
file) is added back at the end of the rewriting process.So, both
/.htaccess
and/admin/.htaccess
would contain identical directives:HOWEVER, a slight difference with this solution and the OP’s solution is that the
admin/
part of the URL-path is not passed to thepath
URL parameter. You could hardcode this if required. eg.index.html?path=admin/$1
. Or account for this in your script.The first
RewriteRule
is just a minor optimisation that prevents further filesystem checks after the request has already been rewritten toindex.html
.Note that I changed
(.*)
(0 or more) to(.+)
(1 or more). This avoids the additional directory check when requesting the root directory. ie.example.com/
andexample.com/admin/
. You are not rewriting these requests, but instead are reliant onDirectoryIndex index.html
being set appropriately – this is the default setting in the server config.Since the substitution string (
index.php?page=$1
) is relative, when in the document root it will effectively rewrite to/index.php
and when in/admin/.htaccess
it will effectively rewrite back to/admin/index.php
.Note that the mod_rewrite directives in
/admin/.htaccess
completely override the mod_rewrite directives in the parent.htaccess
file since mod_rewrite directives are not inherited by default (unlike other modules).Alternatively, to avoid repetition, whilst still maintaining two separate
.htaccess
files you could enable mod_rewrite inheritance in the/admin/.htaccess
file. For example…In the root
/.htaccess
file:Then, in
/admin/.htaccess
you would have the following instead:This inherits the parent mod_rewrite directives as if they were literally copied in-place in the
/admin/.htaccess
file.However, this adds an additional layer of complexity. Apart from the SPA in
/admin
now being dependent on the root.htaccess
file, you now have to be careful that you don’t add any breaking directives to the root.htaccess
file.Aside:
The first condition that checks for "admin" in the URL-path (incidentally, this checks for "admin" anywhere in the URL-path – which isn’t strictly correct) is not required – the check can be performed more optimally in the
RewriteRule
directive itself. For example:These two rules can be combined into one if desired, possibly at the expense of some clarity. For example:
The
$1
backreference then contains the optional path-prefix, eitheradmin/
or nothing. And$0
contains the full match.