diff --git a/.env.example b/.env.example index b3972b8..33beffb 100644 --- a/.env.example +++ b/.env.example @@ -65,6 +65,11 @@ FILESYSTEM_DISK=local # ── Docker Compose knobs (host ports / uid / image) ────────────────── APP_PORT=80 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 DB_PORT=3306 # Containers run as this host user (must own the bind-mount). nexxo=1002 on this VM. diff --git a/vite.config.js b/vite.config.js index 2fa3389..394a8a2 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,43 +1,52 @@ -import { defineConfig } from 'vite'; +import { defineConfig, loadEnv } from 'vite'; import laravel from 'laravel-vite-plugin'; import tailwindcss from '@tailwindcss/vite'; -export default defineConfig({ - plugins: [ - laravel({ - input: ['resources/css/app.css', 'resources/js/app.js'], - refresh: true, - }), - tailwindcss(), - ], - server: { - // 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, 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 - // shipped image; set it in the dev .env only. Dev-only — prod builds assets, no HMR server. - hmr: { - host: process.env.VITE_HMR_HOST || 'localhost', +export default defineConfig(({ mode }) => { + // Read the .env FILE via Vite's loadEnv — NOT process.env: the dev container bind-mounts .env but + // does not export it into the process environment, so process.env.VITE_HMR_HOST is always empty + // there. VITE_HMR_HOST is the address the BROWSER uses to reach the dev VM (HMR websocket + the + // 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 + // host (never a broken hard 'localhost' that 404s the CSS/JS on a remote dev box). + const env = loadEnv(mode, process.cwd(), 'VITE_'); + + return { + plugins: [ + laravel({ + input: ['resources/css/app.css', 'resources/js/app.js'], + refresh: true, + }), + tailwindcss(), + ], + server: { + // 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/**', - ], - }, - }, + }; });