aindrajaya / aindrajaya/tmat-gis

Failed to load module script: MIME type error when deployed via HAProxy with path-based routing

Abierto
#19 0 comentarios 0 reacciones 1 asignado Reclamado por @aindrajaya Ver en GitHub
bug
Lenguaje dominante
TypeScript
Estrellas
0
Forks
0
Métricas de merge de PR
Sin PR fusionados en 30 d

Descripción

## 🐛 Bug Report: Module Script MIME Type Error in Production Deployment

### 📋 Issue Description

**Summary:**
Vite React application fails to load JavaScript modules in production when deployed behind HAProxy with path-based routing (`/spagambut`). Browser throws MIME type error expecting JavaScript but receiving HTML instead.

**Environment:**
- **Framework:** Vite 5.x + React 18
- **Deployment:** Docker (nginx alpine) + HAProxy reverse proxy
- **Routing:** Path-based routing (`/spagambut/`)
- **Server:** Ubuntu 20.04.6 LTS, Docker 29.1.3

---

### 🔴 Error Message

```
Failed to load module script: Expected a JavaScript module script but the server
responded with a MIME type of "text/html". Strict MIME type checking is enforced
for module scripts per HTML spec.
```

**Browser Console:**
```
GET http://27.50.21.155/assets/index-abc123.js 404 (Not Found)
```

**Expected:**
```
GET http://27.50.21.155/spagambut/assets/index-abc123.js 200 OK
```

---

### 🔍 Root Cause

**Issue:** Vite application built with default base path (`/`) but deployed at subpath (`/spagambut/`) via HAProxy.

**What happened:**
1. Vite builds `index.html` with asset references like: `/assets/main.js`
2. HAProxy strips `/spagambut` prefix before forwarding to application
3. Browser requests `/assets/main.js` (wrong - not found)
4. Nginx returns `index.html` for non-existent routes (SPA fallback)
5. Browser receives HTML instead of JavaScript → MIME type error

**Technical Details:**

HAProxy configuration strips path:
```haproxy
backend spagambut
http-request replace-path /(/)?(.*) /\2
server tmat-gis-app 27.50.21.155:9001 check
```

Built `index.html` references:
```html

```

Should reference:
```html

```

---

### 📸 Screenshots

**Browser Network Tab (Before Fix):**
```
Request URL: http://27.50.21.155/assets/index-abc123.js
Status: 404 Not Found
Content-Type: text/html
```

**Browser Console (Before Fix):**
```
❌ Failed to load module script
❌ GET /assets/main.js 404
```

Image

---

### 🔄 Steps to Reproduce

1. **Create Vite React app:**
```bash
npm create vite@latest my-app -- --template react-ts
cd my-app
npm install
```

2. **Build with default config:**
```javascript
// vite.config.ts (default - no base path)
export default defineConfig({
plugins: [react()],
})
```

3. **Deploy to Docker with Nginx:**
```dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
```

4. **Configure HAProxy with path-based routing:**
```haproxy
backend my_app
http-request replace-path /(/)?(.*) /\2
server app 127.0.0.1:3000 check
```

5. **Access via path:** `http://example.com/my-app/`

6. **Result:** Module script MIME type error

---

### ✅ Solution

**Fix:** Configure Vite `base` option to match deployment path.

#### Option 1: Static Base Path

```javascript
// vite.config.ts
export default defineConfig({
plugins: [react()],
base: '/spagambut/', // Match HAProxy path
})
```

#### Option 2: Environment Variable (Recommended)

```javascript
// vite.config.ts
import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig(({ mode }) => {
const env = loadEnv(mode, '.', '')
return {
base: env.VITE_BASE_PATH || '/',
plugins: [react()],
}
})
```

```bash
# .env (production)
VITE_BASE_PATH=/spagambut/
```

#### Option 3: Use Subdomain Routing (Avoids Issue)

Instead of path-based routing, use subdomain:

```haproxy
acl is_my_app hdr(host) -i app.example.com
use_backend my_app if is_my_app

backend my_app
server app 127.0.0.1:3000 check
# No path stripping needed
```

Then keep Vite base as `/`:
```javascript
export default defineConfig({
base: '/', // No path prefix needed
})
```

---

### 🧪 Verification

**After fix:**

1. **Build output includes base path:**
```html

```

2. **Browser requests correct paths:**
```
GET http://27.50.21.155/spagambut/assets/index-abc123.js
Status: 200 OK
Content-Type: application/javascript
```

3. **No console errors:**
```
✅ All modules loaded successfully
✅ No MIME type errors
```

---

### 📚 Related Issues

- Similar to: #[issue_number] (if exists)
- Vite docs: [[Base Path Configuration](https://vitejs.dev/guide/build.html#public-base-path)](https://vitejs.dev/guide/build.html#public-base-path)
- Related to SPA routing with Nginx fallback

---

### 🔧 Environment Details

```yaml
OS: Ubuntu 20.04.6 LTS
Node: 20.x
npm: 10.x
Vite: 5.x
React: 18.x
Docker: 29.1.3
HAProxy: 2.x
Nginx: 1.25-alpine
Browser: Chrome 120 / Firefox 121
```

**Package versions:**
```json
{
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@vitejs/plugin-react": "^4.2.1",
"vite": "^5.0.8"
}
}
```

---

### 💡 Additional Context

**Why this happens:**
- Vite builds assets with absolute paths from root
- HAProxy path stripping changes the effective root
- Mismatch between build-time paths and runtime paths
- Nginx SPA fallback serves HTML for 404s, causing MIME type confusion

**Alternative workarounds:**
1. Configure HAProxy to NOT strip path (pass `/spagambut/` to backend)
2. Use subdomain routing instead of path-based
3. Configure Vite's `base` option to match deployment path ✅ (Recommended)

**Production deployment checklist:**
- [ ] Set `base` in `vite.config.ts`
- [ ] Add `VITE_BASE_PATH` to environment variables
- [ ] Rebuild Docker image with `--no-cache`
- [ ] Verify `index.html` has correct asset paths
- [ ] Test in browser console (no MIME errors)
- [ ] Check Network tab (200 OK for all assets)

---

### 🏷️ Labels

`bug` `vite` `deployment` `docker` `haproxy` `mime-type` `production` `module-script`

---

### 👥 Assignees

@aindrajaya

---

### 🔗 References

- [[Vite Build Options - Public Base Path](https://vitejs.dev/config/build-options.html#build-base)](https://vitejs.dev/config/build-options.html#build-base)
- [[MDN: JavaScript modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules)
- [[HAProxy Path Rewriting](https://www.haproxy.com/documentation/hapee/latest/traffic-routing/rewrites/rewrite-url/)](https://www.haproxy.com/documentation/hapee/latest/traffic-routing/rewrites/rewrite-url/)

---

**Status:** ✅ Resolved
**Resolution:** Added `base: env.VITE_BASE_PATH || '/'` to `vite.config.ts` and set `VITE_BASE_PATH=/spagambut/` in production environment.

---

### 📝 Commit Reference

```
fix: Add configurable base path for HAProxy deployment

- Added VITE_BASE_PATH environment variable support
- Allows deployment at /spagambut/ path via HAProxy
- Defaults to / for local development
- Resolves module script MIME type error in production

Fixes #[issue_number]
```

Guía de contribución

No hay ninguna guía de contribución indexada para este repositorio

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.