In addition to your requirements, I am adding mine:
- It should be done by CD, through an env variable.
- If I need to rename the subdirectory, I should only have to change the env variable.
- It should work with react-router.
- It should work with scss (sass) and html.
- Everything should work normally in dev mode (npm start).
I also had to implement it in Angular2+ project not long ago, I found it harder to implement in React then in Angular2+ where you are good to go with ng build --base-href /<project_name>/
. source
Short version
- Before building, set
PUBLIC_URL
env variable to the value of your subdirectory, let use /subdir
for example. You can also put this variable into your .env.production
(in case you do not have that file you can check the doc)
- In
public/index.html
add the base element bellow, this is for static files like images.
<base href="%PUBLIC_URL%/">
- Also in
public/index.html
, if you have custom link
element, make sure theyre are prefixed with %PUBLIC_URL%
(like manifest.json
and favicon.ico
href).
- If you use
BrowserRouter
, you can add basename
prop:
<BrowserRouter basename={process.env.PUBLIC_URL} />
- If you use
Router
instead, because you need access to history.push
method, to programmatically change page, do the following:
// history.tsx
import {createBrowserHistory} from 'history';
export default createBrowserHistory({ basename: process.env.PUBLIC_URL });
<!-- Where your router is, for me, App.tsx -->
<Router history={history}>
...
</Router>
- Use relative links inside your elements
<!-- "./assets/quotes.png" is also ok, but "/assets/quotes.png" is not -->
<img src="assets/quotes.png" alt="" />
- Move your
background-image
links from scss to jsx/tsx files (note that you may not need to do that if you use css files):
/*remove that*/
background-image: url('/assets/background-form.jpg');
<section style={{backgroundImage: `url('assets/background-form.jpg')`}}>
...
You should be done.
Additional informations
I preferred to use PUBLIC_URL
instead of homepage
in package.json
because I want to use env variable set on gitlab to set the subdir. Relevant resources about the subject:
PUBLIC_URL
override homepage
, and PUBLIC_URL
also take the domain name, if you provide one. If you set only homepage
, PUBLIC_URL
will be set to the value of homepage
.
If you do not want to use a base element in your index.html (I would not know why), you will need to append process.env.PUBLIC_URL
to every link yourself. Note that if you have react-router with a base element, but have not set basename
prop, you will get a warning.
Sass won't compile with an incorrect relative path. It also won't compile with correct relative path to your ../public/assets
folder, because of ModuleScopePlugin
restrictions, you can avoid the restriction by moving your image inside the src folder, I haven't tried that.
There seem to be no way of testing relative path in development mode (npm start). see comment
Finnaly, theses stackoverflow link have related issues: