#6: Use Vite's loadEnv() for VITE_BASE so .env.production actually wins

defineAdminConfig / defineGuestConfig were reading process.env.VITE_BASE,
but Vite does NOT populate process.env from .env files at config-evaluation
time — those go into import.meta.env for the client bundle only. So the
VITE_BASE that new-project.sh writes to frontend/.env.production was
silently ignored, base fell back to '/', and SPA assets 404'd behind the
Apache /projects/<name>/ proxy prefix (blank page on every public route).

Switch both factories to Vite's defineConfig + loadEnv pattern. A
process.env.VITE_BASE override still wins so CI invocations that
explicitly export the variable keep working.

Bumps to 0.3.6.

Closes #6

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Uwe Schuster 2026-04-25 21:36:23 +02:00
parent 5b0bec8850
commit b1a13b83fd
3 changed files with 25 additions and 14 deletions

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "@uschuster/webapp-scaffold",
"version": "0.3.1",
"version": "0.3.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@uschuster/webapp-scaffold",
"version": "0.3.1",
"version": "0.3.6",
"license": "UNLICENSED",
"bin": {
"webapp-scaffold-fetch-openapi": "bin/fetch-openapi.sh",

View file

@ -1,6 +1,6 @@
{
"name": "@uschuster/webapp-scaffold",
"version": "0.3.5",
"version": "0.3.6",
"description": "Shared build scripts + Vite config factories for webapp-template-derived projects.",
"type": "module",
"bin": {

View file

@ -6,8 +6,15 @@
// Both honour the same Apache-proxy-prefix baseUrl convention and keep
// their outputs under a conventional path so the `StaticController` and
// Apache vhost can serve them without per-project tweaks.
//
// VITE_BASE resolution: Vite does NOT populate `process.env.VITE_BASE` from
// .env files at config-evaluation time (those go into `import.meta.env` for
// the client bundle only). To pick up the value `new-project.sh` writes to
// `frontend/.env.production`, we use Vite's own `loadEnv()` helper. A
// `process.env.VITE_BASE` override still wins so CI invocations that
// `export VITE_BASE=…` keep working.
import type { UserConfig } from 'vite';
import { defineConfig, loadEnv, type UserConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
@ -20,10 +27,15 @@ export interface AdminConfigOptions {
outDir?: string;
}
export function defineAdminConfig(opts: AdminConfigOptions): UserConfig {
const base = process.env.VITE_BASE || '/';
return {
base,
function resolveBase(mode: string, root: string): string {
if (process.env.VITE_BASE) return process.env.VITE_BASE;
const env = loadEnv(mode, root, '');
return env.VITE_BASE || '/';
}
export function defineAdminConfig(opts: AdminConfigOptions) {
return defineConfig(({ mode }): UserConfig => ({
base: resolveBase(mode, opts.root),
plugins: [react()],
build: {
outDir: opts.outDir ?? path.resolve(opts.root, '../static/dist'),
@ -33,7 +45,7 @@ export function defineAdminConfig(opts: AdminConfigOptions): UserConfig {
? { output: { manualChunks: opts.vendorChunks } }
: undefined,
},
};
}));
}
export interface GuestConfigOptions extends AdminConfigOptions {
@ -41,10 +53,9 @@ export interface GuestConfigOptions extends AdminConfigOptions {
entry?: string;
}
export function defineGuestConfig(opts: GuestConfigOptions): UserConfig {
const base = process.env.VITE_BASE || '/';
return {
base,
export function defineGuestConfig(opts: GuestConfigOptions) {
return defineConfig(({ mode }): UserConfig => ({
base: resolveBase(mode, opts.root),
plugins: [react()],
build: {
outDir: opts.outDir ?? path.resolve(opts.root, '../static/guest/dist'),
@ -60,5 +71,5 @@ export function defineGuestConfig(opts: GuestConfigOptions): UserConfig {
},
},
},
};
}));
}