The storefront's router changes the address without asking the server for a page. Click Details on the Lamp: the address becomes /products/3, and the page only fetches /api/products/3. But a reload, or a link someone pasted, asks the server for GET /products/3 itself. There is no such file in client/dist, so Express answers 404 Cannot GET /products/3.
The fix is a fallback: for any other GET, send index.html. The browser loads the storefront, runs its script, and the router reads the address and shows the Lamp. In Express 5, the path "/{*splat}" matches every path.
Express tries the handlers in the order you write them, and the first one that answers wins:
app.get("/sale", (req, res) => {
res.send("Sale!");
});
app.get("/sale", (req, res) => {
res.send("Never sent");
});
// GET /sale → 200 Sale!
So the order decides. The /api handlers sit above, so a wrong API path stays a JSON 404. Files that exist come from express.static. A missing file under /assets needs a real 404 before the fallback, or the browser gets HTML where it expected a script.
Your server must answer:
GET /products/3 → 200 text/html the file client/dist/index.html
GET /cart → 200 text/html the file client/dist/index.html
GET /api/nope → 404 {"error": "Not found"}
GET /assets/app-4f2a.js → 200 the file client/dist/assets/app-4f2a.js
GET /assets/app-91c7.js → 404 Not found
Your task: in server/app.js, below express.static, add a fallback that sends dist's index.html for every other GET. Above it, add a handler for the paths under /assets that answers 404 with the text Not found.
Assignment
Follow the Coding Tutorial to answer deep links with the storefront's index.html, while API paths and missing scripts keep their 404s.
Hintres.sendFile needs the file's full path: build it with path.join from dist. A handler whose function sends nothing leaves the browser waiting.
Free plan: 30 tutor messages. PRO is unlimited.
