Homelable could only own the root of an origin. Behind an existing proxy at `https://home.example/homelab/` the built `index.html` still asked for `/assets/*`, which fell through to whatever owned the root — and when that answered `text/html` for a `<script>` under `nosniff`, the browser failed the load on an HTTP 200. The only workaround was patching the checkout and rebuilding on every upgrade. One build-time knob, `VITE_BASE_PATH`, becomes Vite's `base`. Vite rewrites the asset URLs it emits; everything the app builds by hand goes through the new `utils/basePath.ts` — the axios instances, the WebSocket URL, the live-view route, the local brand icons, and the OIDC login href. `resolveServerPath` covers what the *backend* hands back, which is always root-absolute because it cannot know where the SPA is mounted: uploaded floor-plan URLs already stored in a canvas are resolved at render time, so plans predating the move keep loading. The OIDC callback used to redirect to `/`, dropping subpath users at the origin root after login; it now reads the prefix back out of `OIDC_REDIRECT_URI`. The default is `/`, and stays a no-op there by construction: every helper returns the string it returned before, the root build output is unchanged and both nginx sites are byte-identical to what shipped — the Docker image copies `docker/nginx.conf` verbatim and the installer keeps its original heredoc. Only a non-default prefix takes the generated config. Those generated configs use `root`, never `alias`, since `alias` plus `try_files` mis-resolves `$uri` — the Docker build lands the bundle in the matching subdirectory, and the installer symlinks it under `/var/www/homelable`. Both accept either reverse-proxy style, prefix forwarded intact or already stripped, with no redirect loop between them, and `absolute_redirect off` stops the no-slash 301 from eating the port. Closes #334. ha-relevant: maybe
React + TypeScript + Vite
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Currently, two official plugins are available:
- @vitejs/plugin-react uses Babel (or oxc when used in rolldown-vite) for Fast Refresh
- @vitejs/plugin-react-swc uses SWC for Fast Refresh
React Compiler
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see this documentation.
Expanding the ESLint configuration
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Remove tseslint.configs.recommended and replace with this
tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
tseslint.configs.stylisticTypeChecked,
// Other configs...
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
You can also install eslint-plugin-react-x and eslint-plugin-react-dom for React-specific lint rules:
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])