Vite production build asset 404s when deploying to subpaths
0 reputation · 20 Mar 2023, 13:51 UTC
0 reputation · 20 Mar 2023, 13:51 UTC
Vite's development server handles asset resolution from memory using root-relative paths. However, the production build process uses Rollup to rewrite asset URLs based on the base configuration in vite.config.js. This creates a discrepancy when an application is hosted under a subpath (e.g., /my-app/) or a CDN prefix rather than the domain root.
While a default base: '/' allows the application to function correctly during local development, the resulting build generates HTML and JavaScript that reference absolute root paths. If the deployment environment does not match this root structure, assets fail to load.
Furthermore, the use of import.meta.env.BASE_URL for manual URL construction is statically replaced at build time. If the build-time configuration differs from the runtime deployment path, there is no native mechanism for runtime correction.
./) and absolute subpaths when resolving nested chunks in a production build?import.meta.env.BASE_URL remains consistent across varying deployment environments without triggering a full rebuild?31775 reputation · 20 Mar 2023, 14:24 UTC
To resolve 404 errors when deploying a Vite application to a subpath, you must align the base configuration in vite.config.js with your deployment directory. By default, Vite uses /, which generates absolute paths that fail when the app is hosted at a location like /my-app/.
Depending on your deployment requirements, use one of the following settings:
base: '/my-app/' if the deployment path is static and known. This ensures all assets are prefixed with the specific subpath.base: './' to make asset references relative to the index.html file. This allows the build to be portable across different subpaths without modification.// vite.config.js
import { defineConfig } from 'vite'
export default defineConfig({
base: '/my-app/', // or './' for relative paths
})
Vite distinguishes between these paths during the Rollup bundling phase. An absolute base (/my-app/) hardcodes the prefix into the HTML and JS chunks. A relative base (./) instructs the browser to resolve assets relative to the current URL. While relative paths offer portability, they can cause 404s if you use client-side routing (e.g., React Router or Vue Router) with "pretty URLs" (like /my-app/user/profile), as the browser may attempt to find assets relative to the /user/ directory rather than the app root.
Because import.meta.env.BASE_URL is a static replacement performed at build time, it cannot be changed at runtime. To maintain consistency across varying environments without a full rebuild, the most reliable approach is to use relative paths (./). If absolute paths are required for routing stability, you must use environment variables during the build process to inject the correct base path for each specific target environment.
npm run build.dist/index.html file.<script> and <link> tags start with your specified subpath or ./ rather than a leading slash.Diagnostic Note: Are you using a client-side router with history mode? If so, relative paths may fail on deep-linked pages, and a specific absolute subpath is required.
Use comments to ask for clarification. Post a solution as an answer.
31,775 reputation · 20 Mar 2023, 17:18 UTC
Since import.meta.env.BASE_URL is inlined at build time, one pattern that avoids rebuilds is injecting a small inline script into index.html that sets window.__BASE_URL__, then reading that global in the app instead of the env constant. The trade-off: you lose Vite's static replacement and must manage the global yourself, including typing it for TypeScript.
The base: './' approach only works if the server preserves the relative URL structure. If your host rewrites /my-app/ to / (common with SPA fallback rules), the browser resolves chunk URLs against the rewritten location and you still get 404s. Verify by checking the network tab: the failing request path tells you whether the problem is the emitted URL or the server's rewrite layer.
Also note that for a CDN prefix with absolute URLs, a rebuild with the matching base is effectively required — post-build rewrite plugins exist but add maintenance overhead. Tested behavior assumes Vite 4/5; confirm against your version's docs.