TL;DR - the error is misleading - the server is not finding the index.html file.
Explanation below assumes you are deploying the public dist folder as a sub directory of the server folder.
Something like:
Project
|
+-- dist
| |
| +-- index.html
| +-- assets
| +-- |
| +-- index-fb329e31.js
| +-- index-ec6a2ce7.css
|
+-- index.html
+-- index.js
You have 3 modes of working with vite:
- development where vite server serves the static files
- development with built files - where your express server serves the static files
- production with built files - where your express server serves the static files
Case 1: development, 2 ports
In this scenario you work with 2 ports - vite (5173 by default) and your express server (let's say its 3002). You have hmr & all that fun stuff.
Opening the browser on localhost:5173 goes to vite server. It knows how to load the correct static files.
Inside your app you have API calls that go to localhost:3002.
In your express file your write a handler for it:
app.use('/hello', (req, res) => res.send('world'))
Everyone is happy :)
Case 2: development, 1 port
Now you want to build & test everything works before deploying to prod.
You need to run your app as you'd run it in prod - where the express server
is serving the static files.
- you build the client static files with vite build. This generates a dist folder with all the static assets & index.html file
- you run the server & run the app in the browser on localhost:3002
Now all requests go to the server, which wasn't the case before.
You need to point express to your static folder like so:
// ++
app.use(express.static(path.join(__dirname, 'dist')))
// ++
app.use('/hello', (req, res) => res.send('world'))
Note: the actual path depends on your folder structure, so you might need to modify this a bit
Now going to localhost:3002 will serve your index.html file
Everyone is happy :)
Case 3: production
This works very similarly to case 2, as here also the express server is serving all the files.
Bonus: API requests & client router
Once you add a client router to your application (e.g. /profile page), you will need to tell express that this should serve a static file and not search for a /profile endpoint.
Easiest way to do this is to prefix all api calls with something like /api,
and tell express that all other requests not starting with /api (like /profile) should return the index.html.
Example:
app.use(express.static(path.join(__dirname, 'dist')))
// ++
app.get(/^(?!\/api).\*/, (req, res) => {
res.sendFile(path.join(\_\_dirname, 'dist', 'index.html'))
})
// ++
app.use('/hello', (req, res) => res.send('world'))