I have a React Vite app deployed in Azure the routes work well when clicking on links but when reloading the page in any of these routes, a 404 error shows. All routes work perfectly in dev local deployment after build, so I cannot recreate this in dev environment. I also added the _redirects file in the public folder, but still no change.
This is my vite.config.json
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
// https://vitejs.dev/config/
export default defineConfig({
build: {
commonjsOptions: {
include: ["tailwind.config.js", "node_modules/**"],
},
},
optimizeDeps: {
include: ["tailwind-config"],
},
plugins: [react()],
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
"tailwind-config": fileURLToPath(
new URL("./tailwind.config.js", import.meta.url)
),
},
},
});
The package.json file:
{
"name": "tailwise-react",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"@badeball/cypress-cucumber-preprocessor": "^20.0.2",
"@ckeditor/ckeditor5-build-balloon": "^40.2.0",
"@ckeditor/ckeditor5-build-balloon-block": "^40.2.0",
"@ckeditor/ckeditor5-build-classic": "^40.2.0",
"@ckeditor/ckeditor5-build-decoupled-document": "^40.2.0",
"@ckeditor/ckeditor5-build-inline": "^40.2.0",
"@cypress/webpack-preprocessor": "^6.0.1",
"@fullcalendar/core": "^6.1.10",
"@fullcalendar/daygrid": "^6.1.10",
"@fullcalendar/interaction": "^6.1.10",
"@fullcalendar/list": "^6.1.10",
"@fullcalendar/react": "^6.1.10",
"@fullcalendar/timegrid": "^6.1.10",
"@headlessui/react": "1.7.18",
"@hookform/resolvers": "^3.3.4",
"@left4code/tw-starter": "^3.1.36",
"@microsoft/signalr": "^8.0.7",
"@reduxjs/toolkit": "^1.8.5",
"axios": "^1.6.8",
"chart.js": "^4.4.1",
"cypress": "^13.7.1",
"d3-force": "^3.0.0",
"dayjs": "^1.11.10",
"dropzone": "^6.0.0-beta.2",
"elkjs": "^0.9.2",
"esbuild": "^0.20.2",
"flat": "^6.0.1",
"highlight.js": "^11.9.0",
"js-beautify": "^1.14.11",
"leaflet": "^1.9.4",
"leaflet.markercluster": "^1.5.3",
"litepicker": "^2.0.12",
"lucide": "^0.304.0",
"lucide-react": "^0.307.0",
"react": "^18.2.0",
"react-beautiful-dnd": "^13.1.1",
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-dom": "^18.2.0",
"react-draggable": "^4.4.6",
"react-dropzone": "^14.2.3",
"react-hook-form": "^7.49.3",
"react-icons": "^5.0.1",
"react-redux": "^9.0.4",
"react-router-dom": "^6.21.1",
"react-transition-group": "^4.4.5",
"reactflow": "^11.10.4",
"simplebar": "^6.2.5",
"strip-ansi": "^7.1.0",
"tabulator-tables": "^5.5.2",
"tiny-slider": "^2.9.4",
"tippy.js": "^6.3.7",
"toastify-js": "^1.12.0",
"tom-select": "2.3.1",
"xlsx": "^0.18.5",
"yup": "^1.3.3",
"zoom-vanilla.js": "^2.0.6"
},
"devDependencies": {
"@bahmutov/cypress-esbuild-preprocessor": "^2.2.0",
"@esbuild-plugins/node-modules-polyfill": "^0.2.2",
"@tailwindcss/forms": "^0.5.7",
"@types/dropzone": "^5.7.8",
"@types/flat": "^5.0.5",
"@types/js-beautify": "^1.14.3",
"@types/leaflet": "^1.9.8",
"@types/leaflet.markercluster": "^1.5.4",
"@types/lodash": "^4.14.202",
"@types/node": "^20.10.6",
"@types/react": "^18.2.47",
"@types/react-beautiful-dnd": "^13.1.8",
"@types/react-dom": "^18.2.18",
"@types/react-transition-group": "^4.4.10",
"@types/tabulator-tables": "^5.5.4",
"@types/toastify-js": "^1.12.3",
"@vitejs/plugin-react": "^4.2.1",
"autoprefixer": "^10.4.16",
"clsx": "^2.1.0",
"lodash": "^4.17.21",
"postcss": "^8.4.33",
"postcss-advanced-variables": "^3.0.1",
"postcss-import": "^16.0.0",
"postcss-nesting": "^12.0.2",
"tailwind-merge": "^2.2.0",
"tailwindcss": "^3.4.1",
"ts-loader": "^9.5.1",
"typescript": "5.4.5",
"vite": "^5.0.11",
"webpack": "^5.91.0"
},
"resolutions": {
"jackspeak": "2.1.1"
},
"cypress-cucumber-preprocessor": {
"nonGlobalStepDefinitions": false,
"stepDefinitions": "cypress/e2e/***.ts"
}
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
I'm using react-router-dom for the routes:
import { useRoutes } from "react-router-dom";
And my routes looks like this:
function Router() {
const routes = [
{
path: "/",
element: <Layout />,
children: [
{
path: "dashboard-ooi-designer/:ooiId/:vertexType",
element: <DashboardMain />,
},
{
path: "cooi-designer",
element: <TestCOOIModeler />,
},
(...)
The main.tsx file:
import ScrollToTop from "@/components/Base/ScrollToTop";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import { Provider } from "react-redux";
import { store } from "./stores/store";
import Router from "./router";
import "./assets/css/app.css";
import { ReactFlowProvider } from "reactflow";
import ContextProvider from "./api/context";
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<BrowserRouter>
<ContextProvider>
<Provider store={store}>
<ReactFlowProvider>
<Router />
</ReactFlowProvider>
</Provider>
<ScrollToTop />
</ContextProvider>
</BrowserRouter>
);
If some of you have any ideas about this issue, I found some questions but no definitive fix.
I tried the _redirects file with this content in the public folder
/* /index.html 200
I also tried to replicate the behavior locally but it didn't happen.
This is the log in Azure when I reload the page:
I found the solution to the issue in my case, and I hope it can be useful to others. I was following this post: https://medium.com/@jolin1010/deploy-react-app-on-azure-with-custom-web-config-606e9f8cff07, that was a lot of more clarifying, but there is a small detail that makes the difference https://learn.microsoft.com/en-us/answers/questions/1660913/azure-app-service-wont-display-my-website
Make sure you are using in your app service configuration, the start command:
pm2 serve /home/site/wwwroot --no-daemon --spa