Concept lesson · explains an idea. Code is shown for reading, not run.
Your app works on your computer, and then something breaks after deploy. These are the problems that come up again and again, with how to recognise and fix each one. Several were reproduced for this course on a real Apache server; they are marked.
1. A blank white page after deploying
What you see: an empty page; the console shows 404 errors for /assets/index-xxxx.js and similar.
Why: the file paths in index.html do not match where you uploaded the files. The usual cause is deploying to a subfolder with the default base: '/'. Reproduced: the browser asked for the files at the domain root and got two 404 errors.
Fix: build with the right base (--base=/subfolder/), set the router basename, and re-upload. Check that dist/index.html has the right paths (Deployment Fundamentals).
2. 404 when you refresh an inner page
What you see: the home page works, a link click works, but refreshing /about, or opening a copied link, gives a server “404 Not Found”.
Why: the server looks for a file called about. Reproduced: Apache returned 404 for /about until the rewrite rule was added.
Fix: a fallback to index.html on the server (.htaccess, Nginx try_files, _redirects).
3. The page looks right, but unknown URLs return status 200
What you see: no error, but search consoles report “soft 404” pages.
Why: the server answers every URL with index.html and status 200, and React shows “not found” in the browser. Reproduced.
Fix: accept it for private apps, add noindex to the not-found screen, or use a framework with server rendering for content that must be indexed.
4. Environment variables are undefined
What you see: undefined in the page or Failed to fetch undefined/api/....
Why: the variable has no VITE_ prefix; it is missing in the build environment; or it was changed after the build (values are baked in at build time).
Fix: use VITE_ names, set them where the build runs (CI settings or the right .env.production), and rebuild (Environment Configuration).
5. CORS errors in the console
What you see: Access to fetch at '...' from origin '...' has been blocked by CORS policy.
Why: the server you call does not allow your site’s origin. It worked locally because of a dev proxy or because the API allowed localhost.
Fix: configure CORS on the API for your production origin, or call your own backend that calls the API. You cannot fix it in React (API Security Fundamentals).
6. Mixed content blocked
What you see: requests to http://... blocked on an https:// page.
Fix: use HTTPS for the API and for every resource, and use protocol-safe URLs.
7. “Failed to fetch dynamically imported module” after a new deploy
What you see: a user who had the site open before you deployed clicks to a lazy route and gets an error.
Why: the old page asks for a chunk whose hashed file name no longer exists, because the new build replaced it.
Fix: wrap lazy routes in an error boundary that offers “reload” (Error Boundaries); keep the previous build’s files on the server for a while; or reload the page automatically when a chunk fails.
8. Works on Windows or macOS, fails on Linux
What you see: Module not found in the production build or a missing image on the server.
Why: Windows and macOS file systems often ignore upper and lower case; Linux does not. import Button from './button.jsx' finds Button.jsx on your machine and fails on the server.
Fix: match the exact letter case in imports and asset paths. A CI build on Linux catches it.
9. The old version keeps appearing
What you see: you deployed, but users (or you) still see the previous version.
Why: index.html was cached, a CDN holds the old copy, or a service worker serves old files.
Fix: never cache index.html for long; purge the CDN; handle service worker updates carefully (or remove a service worker you do not need) (Deployment Fundamentals).
10. A tip for Git Bash on Windows: --base gets rewritten
What you see: the built index.html contains paths like /Program Files/Git/shop/assets/....
Why: Git Bash converts a leading / in command-line arguments into a Windows path. Reproduced while preparing this course.
Fix: set base in vite.config.js instead of the command line, run the command in PowerShell or Command Prompt, or disable path conversion for that command (MSYS_NO_PATHCONV=1).
11. process is not defined or require is not defined
Why: a package or your code assumes Node.js globals (process.env, require). Browsers do not have them.
Fix: use import.meta.env instead of process.env in Vite projects; use import instead of require; check that the package supports browsers.
12. A slow or janky app only in production
Why: a huge bundle, uncompressed files, unoptimised images, no caching, or a slow API.
Fix: measure with Lighthouse and the Network panel; compress; lazy-load; resize images (Performance and Security Checklist).
13. You cannot read the minified error
What you see: TypeError: e is not a function pointing at index-xxxx.js:1:48210.
Fix: use source maps with an error tracker (such as Sentry or similar tools) so production errors map back to your original code, and report errors from your root error boundary (Error Boundaries).
14. React error numbers
In production builds React uses short error codes (“Minified React error #310”) to save size. Open the link in the message, or search react.dev for the code, to read the full text. In development you get the complete message, so reproduce the bug there when you can.
A habit that prevents most of these
Always run npm run build and npm run preview before you deploy, and check the deployed site in a private window with the console open: refresh on an inner page, click a lazy route, and look at the Network tab for failed requests.
Key points
- Blank page: wrong
base. 404 on refresh: missing server fallback.undefinedvariables:VITE_prefix and build-time values. - CORS and mixed content are server and protocol problems, not React problems.
- Preview the build, match file name case, and keep error tracking with source maps.