Fix 404 errors for frontend JS files when using Vite proxy. Use when: (1) Browser shows "Failed to load resource: 404" for JS/JSX files that exist on disk, (2) Vite serves HTML instead of JavaScript for module imports, (3) You have a client folder named "api" (or similar) AND a Vite proxy configured for "/api". The proxy intercepts requests for client-side files when folder names match proxy paths. Applies to Vite, Vite+React, Vite+Vue projects with dev server proxy configuration.
Scanned 5/27/2026
Install via CLI
openskills install divinevideo/divine-mobile---
name: vite-proxy-folder-name-conflict
description: |
Fix 404 errors for frontend JS files when using Vite proxy. Use when: (1) Browser shows
"Failed to load resource: 404" for JS/JSX files that exist on disk, (2) Vite serves HTML
instead of JavaScript for module imports, (3) You have a client folder named "api" (or
similar) AND a Vite proxy configured for "/api". The proxy intercepts requests for
client-side files when folder names match proxy paths. Applies to Vite, Vite+React,
Vite+Vue projects with dev server proxy configuration.
author: Claude Code
version: 1.0.0
date: 2026-01-21
---
# Vite Proxy Folder Name Conflict
## Problem
Frontend JavaScript/JSX files return 404 errors even though they exist on disk. The browser
console shows errors like:
```
usePeople.js:1 Failed to load resource: the server responded with a status of 404 (Not Found)
useMedia.js:1 Failed to load resource: the server responded with a status of 404 (Not Found)
```
The files exist at paths like `src/client/api/hooks/usePeople.js`, but Vite returns 404 or
serves HTML instead of JavaScript.
## Context / Trigger Conditions
This issue occurs when ALL of these conditions are true:
1. **Vite dev server** with proxy configuration in `vite.config.js`:
```javascript
server: {
proxy: {
'/api': {
target: 'http://localhost:3001',
changeOrigin: true,
},
},
}
```
2. **Client-side folder** with the same name as the proxy path:
```
src/client/
├── api/ ← Folder name matches proxy path "/api"
│ ├── client.js
│ └── hooks/
│ ├── usePeople.js
│ └── useMedia.js
```
3. **Imports** that resolve to the proxied path:
```javascript
// In src/client/pages/Directory.jsx
import { usePeople } from '../api/hooks/usePeople.js';
// Vite transforms this to: /api/hooks/usePeople.js
// This matches the proxy rule and gets sent to backend!
```
## Root Cause
Vite's module resolution transforms relative imports to absolute paths. When you import
`../api/hooks/usePeople.js` from a page, Vite resolves it to `/api/hooks/usePeople.js`.
The proxy configuration matches paths starting with `/api` and forwards them to the backend
server. Since `/api/hooks/usePeople.js` starts with `/api`, it gets proxied to the backend
instead of being served as a static file.
The backend doesn't have a route for `/api/hooks/usePeople.js`, so it returns 404.
## Solution
**Option 1: Rename the client folder (Recommended)**
Rename the conflicting folder to something that won't match the proxy path:
```bash
# Rename api to services (or lib, helpers, etc.)
mv src/client/api src/client/services
# Update all imports
find src/client -name "*.jsx" -o -name "*.js" | xargs sed -i '' 's|from.*['"'"'"]\.\.\/api|from "../services|g'
```
**Option 2: Use a different proxy path**
Change the proxy path to something more specific:
```javascript
// vite.config.js
server: {
proxy: {
'/api/v1': { // More specific path
target: 'http://localhost:3001',
changeOrigin: true,
},
},
}
```
**Option 3: Configure proxy to exclude certain patterns**
Use a custom function to exclude certain paths:
```javascript
server: {
proxy: {
'/api': {
target: 'http://localhost:3001',
changeOrigin: true,
bypass: (req) => {
// Don't proxy requests for JS/TS files
if (req.url.match(/\.(js|jsx|ts|tsx|mjs)$/)) {
return req.url;
}
},
},
},
}
```
## Verification
After applying the fix:
1. Clear Vite's cache: `rm -rf node_modules/.vite`
2. Restart the dev server: `npm run dev`
3. Check browser console - 404 errors should be gone
4. Verify the app loads and API calls still work
Test both:
- Frontend file serving: `curl http://localhost:5173/services/hooks/usePeople.js` should return JavaScript
- API proxying: `curl http://localhost:5173/api/people` should return JSON from backend
## Example
**Before (broken):**
```
src/client/
├── api/ ← Conflicts with proxy
│ └── hooks/
│ └── usePeople.js
├── pages/
│ └── Directory.jsx ← import from '../api/hooks/usePeople.js'
vite.config.js:
proxy: { '/api': 'http://localhost:3001' }
Result: Browser gets 404 for usePeople.js
```
**After (fixed):**
```
src/client/
├── services/ ← Renamed to avoid conflict
│ └── hooks/
│ └── usePeople.js
├── pages/
│ └── Directory.jsx ← import from '../services/hooks/usePeople.js'
vite.config.js:
proxy: { '/api': 'http://localhost:3001' } ← Unchanged
Result: Frontend files served correctly, API still proxied
```
## Notes
- This issue is not specific to React—it affects any Vite project with proxies
- Common conflicting folder names: `api`, `graphql`, `socket`, `ws`
- The issue only manifests in development (Vite dev server); production builds don't have this problem
- If using TypeScript path aliases, ensure they also avoid proxy path conflicts
- Always clear Vite's cache (`node_modules/.vite`) after changing folder structure
## Related Issues
- Similar issues can occur with other dev servers (webpack-dev-server, Create React App)
- If using a monorepo, check proxy configs in both root and package-level configs
No comments yet. Be the first to comment!