Reputation: 19695
I have a React app, and I have an issue with 404 in my navigation, if I try to refresh a page that is not the root page, it will give me a 404.
Thing is it only happens to me on production and not on dev.
In dev environment, I use npm start
, on prod environment, I use serve build
.
This make debug more complicated, as I lose the hot-reload option for debugging. I must compile my docker image each time I make a change.
Here is a bit of my code:
<BrowserRouter>
<div>
<Switch>
<Route exact path="/premiere-connexion" component={FirstLoginLayout}/>
{(user.state === "1" && window.location.pathname === "/premiere-connexion") &&
<Redirect to="/premiere-connexion"/>}
<PrivateRoute path="/bo" component={BackOfficeLayout} profiles={["ADMIN"]}/>
<Route exact path="/" component={Customer}/>
<Redirect to="/"/>
</Switch>
}
</div>
</BrowserRouter>
Any Idea how should I reproduce it in local ?
Upvotes: 4
Views: 3164
Reputation: 31
if using netlify hosting then you can try creating file _redirects and add the 1 line code
/* /index.html 200
Upvotes: 0
Reputation: 333
I ended up here as I hade the same problem; when you call React Router addresses directly you get a 404 error when you run react on a docker.
The solution is to tell your nginx that send non existing urls to index.html (and it is pretty much easy)
You need to make a nginx.conf
file (in my case next to Dockerfile) and copy it in /etc/nginx/nginx.conf inside your container.
Here is the nginx.conf
# auto detects a good number of processes to run
worker_processes auto;
#Provides the configuration file context in which the directives that affect connection processing are specified.
events {
# Sets the maximum number of simultaneous connections that can be opened by a worker process.
worker_connections 8000;
# Tells the worker to accept multiple connections at a time
multi_accept on;
}
http {
# what times to include
include /etc/nginx/mime.types;
# what is the default one
default_type application/octet-stream;
# Sets the path, format, and configuration for a buffered log write
log_format compression '$remote_addr - $remote_user [$time_local] '
'"$request" $status $upstream_addr '
'"$http_referer" "$http_user_agent"';
server {
# listen on port 80
listen 80;
# save logs here
access_log /var/log/nginx/access.log compression;
# where the root here
root /usr/share/nginx/html;
# what file to server as index
index index.html index.htm;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to redirecting to index.html
try_files $uri $uri/ /index.html;
}
# Media: images, icons, video, audio, HTC
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
expires 1M;
access_log off;
add_header Cache-Control "public";
}
# Javascript and CSS files
location ~* \.(?:css|js)$ {
try_files $uri =404;
expires 1y;
access_log off;
add_header Cache-Control "public";
}
# Any route containing a file extension (e.g. /devicesfile.js)
location ~ ^.+\..+$ {
try_files $uri =404;
}
}
}
That is how you apply it : add COPY nginx.conf /etc/nginx/nginx.conf
in your Dockerfile.
My Dockerfile
looks like this :
# build environment
FROM node:13.12.0-alpine as build
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH
COPY package.json ./
COPY package-lock.json ./
RUN npm ci --silent
RUN npm install [email protected] -g --silent
COPY . ./
RUN npm run build
# production environment
FROM nginx:stable-alpine
# Nginx configuration
COPY nginx.conf /etc/nginx/nginx.conf
COPY --from=build /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
The line try_files $uri $uri/ /index.html;
tells nginx to fall back to index.html
Hope it helps others that end-up here
Upvotes: 0
Reputation: 19695
With @hbentlov recommendations, I solved this issue creating a file serve.json
in the public/
folder, with this content:
{
"rewrites": [{
"source": "**",
"destination": "/index.html"
}]
}
Upvotes: 4