Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
883 views
in Technique[技术] by (71.8m points)

reactjs - How should I configure create-react-app to serve app from subdirectory?

I have classic web application rendered on server. I want to create admin panel as single page application in React. I want to server admin panel from https://smyapp.example.com/admin/. I try to use create-react-app but it assumes that i serve SPA from root URL. How should I configure create-react-app to serve app from "admin" subdirectory? In documentation I found "homepage" property but if I properly understand it requires complete url. I can't give complete url because my app is deployed in few environments.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

  1. 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)
  2. In public/index.html add the base element bellow, this is for static files like images.
<base href="%PUBLIC_URL%/">
  1. 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).
  2. If you use BrowserRouter, you can add basename prop:
<BrowserRouter basename={process.env.PUBLIC_URL} />
  1. 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>
  1. Use relative links inside your elements
<!-- "./assets/quotes.png" is also ok, but "/assets/quotes.png" is not -->
<img src="assets/quotes.png" alt="" />
  1. 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:


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...