Recipes
Idiomatic compositions of @mongez/vite features. Drop the snippets into your vite.config.ts (and the matching .env files) and tweak.
Minimal SPA setup
import { defineConfig } from "vite";import react from "@vitejs/plugin-react";import mongezVite from "@mongez/vite";
export default defineConfig({ plugins: [ mongezVite(), // everything default-on except htaccess + preRender react(), ],});APP_NAME="My App"APP_PORT=3000
# .env.productionAPP_NAME="My App"PUBLIC_URL=https://cdn.example.com/<title>__APP_NAME__</title>What happens:
vite dev: loads.env.development, replaces__APP_NAME__withMy App, opens the browser, mirrors tsconfig paths.vite build: loads.env.production, setsconfig.base = "https://cdn.example.com/", replaces__APP_NAME__, zipsdist/.
Production CDN base URL via env
import mongezVite from "@mongez/vite";
export default defineConfig({ plugins: [ mongezVite({ envBaseUrlKey: "CDN_HOST", }), ],});CDN_HOST=https://assets.example.comvite build # → assets referenced from https://assets.example.com/Apache deployment with .htaccess + prerender
mongezVite({ htaccess: true, preRender: { url: "https://render.mentoor.io", cache: true, },});After vite build:
dist/├── assets/│ └── ...├── index.html├── .htaccess (SPA rewrites + Googlebot routing)├── prerender.php└── build.zipDrop the zip on an Apache box, unzip into the docroot, and SPA routing + crawler pre-rendering both work without further config.
Multi-stage builds (staging / production / preprod)
import mongezVite from "@mongez/vite";
export default defineConfig({ plugins: [ mongezVite({ productionEnvName: process.env.STAGE, }), ],});STAGE=staging vite build # loads .env.stagingSTAGE=preprod vite build # loads .env.preprodSTAGE=production vite build # loads .env.productionWithout STAGE, productionEnvName is undefined and the plugin falls through to the default chain (.env.production → .env.build → .env).
Disable everything except env + base + index.html
mongezVite({ autoOpenBrowser: false, linkTsconfigPaths: false, compressBuild: false, htaccess: false,});The plugin reduces to: load env, set config.base during build, replace __KEY__ tokens in index.html. Useful when you already have other plugins handling tsconfig paths, compression, and dev-server behaviour.
Custom html token delimiters
mongezVite({ htmlEnvPrefix: "<!-- ", htmlEnvSuffix: " -->",});<title><!-- APP_NAME --></title>Use HTML-comment-shaped tokens when your HTML is processed by a tool that strips __double_underscores__ (rare, but it happens).
Custom build artifact name
mongezVite({ compressedFileName: () => { const tag = process.env.GIT_TAG || "latest"; return `myapp-${tag}.zip`; },});GIT_TAG=v1.4.2 vite build# → dist/myapp-v1.4.2.zipFor an async lookup:
mongezVite({ compressedFileName: async () => { const tag = await readVersionFromS3(); return `myapp-${tag}.zip`; },});Layered env with shared defaults
APP_NAME="My App"APP_URL=https://example.com
# .env.developmentDB_HOST=localhostDEBUG=true
# .env.productionDB_HOST=prod-db.example.comDEBUG=falsePUBLIC_URL=https://cdn.example.com/mongezVite();What happens:
vite dev:.env.sharedloads first, then.env.development.APP_NAMEsurvives from shared;DB_HOSTandDEBUGcome from dev.vite build:.env.sharedfirst, then.env.production. Same idea.
This is @mongez/dotenv’s default — loadEnv is called with loadSharedEnv: true.
SPA + tsconfig paths
{ "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["src/*"], "@components/*": ["src/components/*"], "@lib": ["src/lib/index.ts"] } }}mongezVite(); // linkTsconfigPaths: true (default)import App from "@/App";import Button from "@components/Button";import { foo } from "@lib";Both tsc and Vite resolve the imports. No second plugin needed.
Reading the loaded env from app code
import mongezVite from "@mongez/vite";
export default defineConfig({ plugins: [mongezVite()],});// src/config.ts — runs at build / dev timeimport { env } from "@mongez/dotenv";
// loadEnv was already called from inside the plugin's config hook, so the// store is populated by the time vite reaches user code.export const config = { appName: env("APP_NAME") as string, port: env("APP_PORT", 3000) as number, debug: env("DEBUG", false) as boolean,};Note: this is for code that runs at build/dev time (e.g. inside
vite.config.ts’s own imports or pre-bundling plugins). Code that ships to the browser cannot read from@mongez/dotenv’s store at runtime — use Vite’s ownimport.meta.env.VITE_*mechanism for that. To expose a value asimport.meta.env.VITE_*, prefix it withVITE_in your.envfile.
Apache deploy script
#!/bin/bashset -e
STAGE=${1:-production}
# Build with the matching .env fileSTAGE=$STAGE vite build
# Ship the zip — compressBuild awaits the archive pipeline inside writeBundle,# so by the time `vite build` exits, dist/build.zip is finalised on disk.scp dist/build.zip server:/var/www/$STAGE-staging.zipssh server "cd /var/www && unzip -o $STAGE-staging.zip -d $STAGE"If you’d rather zip the output dir yourself (different archive format, additional files, etc.), disable compressBuild:
mongezVite({ compressBuild: false });vite build && cd dist && zip -r build.zip ./* && scp build.zip server:...