fix(dev): read VITE_HMR_HOST from the .env FILE (loadEnv), restoring dev HMR assets

Regression from the leak-scrub: vite.config read $process.env.VITE_HMR_HOST, but the dev container
bind-mounts .env without exporting it into the process environment — so it was ALWAYS empty and the
hmr host fell back to 'localhost'. On a remote dev box the browser then loaded the Vite client + app.css
+ app.js from localhost:5173 (ERR_CONNECTION_REFUSED) → the whole panel rendered unstyled. Switch to
Vite's loadEnv (reads the .env file, same source the other VITE_* vars use) and fall back to undefined
(Vite infers the host from the request) instead of a hard 'localhost'. The real address stays in the
untracked dev .env (documented in .env.example, no IP committed). Verified: dev assets load 200 + the
login renders styled, and `npm run build` (prod) still succeeds.
feat/v1-foundation
boban 2026-07-05 11:06:53 +02:00
parent c63af35194
commit e6f6e7f8a4
2 changed files with 52 additions and 38 deletions

View File

@ -65,6 +65,11 @@ FILESYSTEM_DISK=local
# ── Docker Compose knobs (host ports / uid / image) ────────────────── # ── Docker Compose knobs (host ports / uid / image) ──────────────────
APP_PORT=80 APP_PORT=80
VITE_PORT=5173 VITE_PORT=5173
# Dev HMR only: the address the BROWSER uses to reach this box's Vite dev server (the dev VM's LAN IP
# or hostname, e.g. 192.0.2.10). Needed when developing against a REMOTE box — otherwise the CSS/JS
# load from the wrong origin. Leave unset for purely local dev; Vite then infers it from the request
# host. Never used in prod (assets are built). Keep the real address in the untracked .env only.
# VITE_HMR_HOST=
REVERB_HOST_PORT=8080 REVERB_HOST_PORT=8080
DB_PORT=3306 DB_PORT=3306
# Containers run as this host user (must own the bind-mount). nexxo=1002 on this VM. # Containers run as this host user (must own the bind-mount). nexxo=1002 on this VM.

View File

@ -1,43 +1,52 @@
import { defineConfig } from 'vite'; import { defineConfig, loadEnv } from 'vite';
import laravel from 'laravel-vite-plugin'; import laravel from 'laravel-vite-plugin';
import tailwindcss from '@tailwindcss/vite'; import tailwindcss from '@tailwindcss/vite';
export default defineConfig({ export default defineConfig(({ mode }) => {
plugins: [ // Read the .env FILE via Vite's loadEnv — NOT process.env: the dev container bind-mounts .env but
laravel({ // does not export it into the process environment, so process.env.VITE_HMR_HOST is always empty
input: ['resources/css/app.css', 'resources/js/app.js'], // there. VITE_HMR_HOST is the address the BROWSER uses to reach the dev VM (HMR websocket + the
refresh: true, // hot-asset origin). It lives ONLY in the gitignored dev .env, so no private/internal address is
}), // committed or baked into the shipped image. Unset → undefined → Vite infers it from the request
tailwindcss(), // host (never a broken hard 'localhost' that 404s the CSS/JS on a remote dev box).
], const env = loadEnv(mode, process.cwd(), 'VITE_');
server: {
// Bind all interfaces inside the container; the browser reaches the VM. return {
host: '0.0.0.0', plugins: [
port: 5173, laravel({
strictPort: true, input: ['resources/css/app.css', 'resources/js/app.js'],
cors: true, refresh: true,
// Remote HMR: hot file + websocket point at the dev VM, not 0.0.0.0/localhost. The host is }),
// env-driven (VITE_HMR_HOST) so no private/internal address is committed or baked into the tailwindcss(),
// shipped image; set it in the dev .env only. Dev-only — prod builds assets, no HMR server. ],
hmr: { server: {
host: process.env.VITE_HMR_HOST || 'localhost', // Bind all interfaces inside the container; the browser reaches the VM.
host: '0.0.0.0',
port: 5173,
strictPort: true,
cors: true,
// Remote HMR: hot file + websocket point at the dev VM (VITE_HMR_HOST), not 0.0.0.0.
// Dev-only — prod builds assets, there is no HMR server.
hmr: {
host: env.VITE_HMR_HOST || undefined,
},
// The repo is rooted in $HOME — keep the watcher off heavy/irrelevant trees.
watch: {
ignored: [
'**/vendor/**',
'**/node_modules/**',
'**/storage/**',
'**/.git/**',
'**/.cache/**',
'**/.npm/**',
'**/.vscode-server/**',
'**/.dotnet/**',
'**/.composer/**',
'**/.config/**',
'**/.claude/**',
'**/.local/**',
],
},
}, },
// The repo is rooted in $HOME — keep the watcher off heavy/irrelevant trees. };
watch: {
ignored: [
'**/vendor/**',
'**/node_modules/**',
'**/storage/**',
'**/.git/**',
'**/.cache/**',
'**/.npm/**',
'**/.vscode-server/**',
'**/.dotnet/**',
'**/.composer/**',
'**/.config/**',
'**/.claude/**',
'**/.local/**',
],
},
},
}); });