UNPKG

vite-plugin-react-server

Version:
195 lines (179 loc) 6.52 kB
import { loadEnv, type ResolvedConfig } from "vite"; import { DEFAULT_CONFIG } from "./defaults.js"; import { getCondition } from "./getCondition.js"; import { getNodeEnv } from "./getNodeEnv.js"; import { getEnvKey } from "../env/getEnvKey.js"; type NestedEnv = { [key: string]: unknown | NestedEnv; }; function setNestedEnv(obj: NestedEnv, path: string[], value: string, verbose = false) { if (!path.length) return; const key = path[0]; if (path.length === 1) { obj[key] = value; return; } if (!obj[key] || typeof obj[key] === "string") { obj[key] = {}; } setNestedEnv(obj[key] as NestedEnv, path.slice(1), value, verbose); } /** * Adds the env to the process.env directly, returns a function to remove previously added env. */ export function resolveEnv( mode: string, envDir: string, prefixes: string | string[] = DEFAULT_CONFIG.ENV_PREFIX ) { const isPrefixesArray = Array.isArray(prefixes); if (isPrefixesArray && !prefixes.includes(DEFAULT_CONFIG.ENV_PREFIX)) { prefixes.push(DEFAULT_CONFIG.ENV_PREFIX); } const env: Record<string, string | boolean> = loadEnv(mode, envDir, prefixes); // Get the primary prefix for environment variable names const primaryPrefix = isPrefixesArray ? prefixes[0] : prefixes; // First, copy any existing environment variables that match our prefixes const existingEnv = Object.entries(process.env).reduce( (acc, [key, value]) => { if ( value && (isPrefixesArray ? prefixes.some((p) => key.startsWith(p)) : key.startsWith(prefixes)) ) { acc[key] = value; } return acc; }, {} as Record<string, string> ); // Merge existing env with loaded env, preferring existing values const mergedEnv = { ...env, ...existingEnv }; const modeKey = getEnvKey("MODE", primaryPrefix); if (!mergedEnv[modeKey] && process.env[modeKey] == null) { const modeIndex = process.argv.findIndex((arg) => arg === "--mode"); const isBuild = process.argv.includes("build"); const isPreview = process.argv.includes("preview"); if (modeIndex === -1) { const inferredMode = isPreview || isBuild ? "production" : "development"; if ( inferredMode === "production" && process.env["NODE_ENV"] !== "production" ) { console.warn( `NODE_ENV is not ${inferredMode} (${process.env["NODE_ENV"]}) but ${modeKey} is ${inferredMode}, NODE_ENV takes precedence` ); mergedEnv[modeKey] = getNodeEnv(); } else if ( inferredMode === "development" && process.env["NODE_ENV"] !== "development" ) { if (process.env["NODE_ENV"] === "test") { if (process.env["NODE_ENV"] !== "test") { console.warn( `NODE_ENV is not ${inferredMode} (${process.env["NODE_ENV"]}) but ${modeKey} is ${mode}, NODE_ENV takes precedence` ); } mergedEnv[modeKey] = "development"; } else { console.warn( `NODE_ENV is not ${inferredMode} (${process.env["NODE_ENV"]}) but ${modeKey} is ${mode}, NODE_ENV takes precedence` ); mergedEnv[modeKey] = getNodeEnv(); } } else { mergedEnv[modeKey] = inferredMode; } } else { // Check if the mode value is in the next argument const modeValue = process.argv[modeIndex + 1]; if (modeValue && !modeValue.startsWith("--")) { mergedEnv[modeKey] = modeValue; } else { // Fallback to default mode mergedEnv[modeKey] = getNodeEnv(); } } } const baseUrlKey = getEnvKey("BASE_URL", primaryPrefix); const ssrKey = getEnvKey("SSR", primaryPrefix); const devKey = getEnvKey("DEV", primaryPrefix); const prodKey = getEnvKey("PROD", primaryPrefix); const publicOriginKey = getEnvKey("PUBLIC_ORIGIN", primaryPrefix); if (!mergedEnv[baseUrlKey]) mergedEnv[baseUrlKey] = "/"; if (!mergedEnv[ssrKey]) mergedEnv[ssrKey] = String( process.argv.includes("--ssr") || getCondition("") === "server" ); if (!mergedEnv[devKey]) mergedEnv[devKey] = mergedEnv[modeKey] === "development"; if (!mergedEnv[prodKey]) mergedEnv[prodKey] = mergedEnv[modeKey] === "production"; if (!mergedEnv[publicOriginKey]) mergedEnv[publicOriginKey] = ""; if (!Object.keys(mergedEnv).length) return () => {}; const addedEnv: NestedEnv = {}; const exclude = isPrefixesArray ? (key: string) => !prefixes.some((prefix) => key.startsWith(prefix)) : (key: string) => !key.startsWith(prefixes); for (const key in mergedEnv) { if (exclude(key)) continue; if (process.env[key] != null) { // Environment variable was already set - don't override it or include it in cleanup continue; } process.env[key] = mergedEnv[key] as string; addedEnv[key] = mergedEnv[key]; } return createCleanupEnv(addedEnv); } export function resolveConfigDefine( resolvedConfig: Pick<ResolvedConfig, "define" | "envPrefix">, verbose = false ) { const { define } = resolvedConfig; const addedEnv: NestedEnv = {}; const envPrefix = Array.isArray(resolvedConfig.envPrefix) ? resolvedConfig.envPrefix[0] : resolvedConfig.envPrefix; for (const key in define) { if (!key || !key.startsWith(`process.env.${envPrefix}`)) continue; const withoutPrefix = key.split("process.env.")[1]; if (typeof define[key] === "string") { const path = withoutPrefix.split("."); setNestedEnv(addedEnv, path, define[key] as string, verbose); if (!process.env[path[0]]) process.env[path[0]] = {} as never; setNestedEnv( process.env[path[0]] as never, path.slice(1), define[key] as string, verbose ); } } return createCleanupEnv(addedEnv); } export function createCleanupEnv(env: NestedEnv) { return () => { for (const key in env) { delete process.env[key]; } }; } export const getMetaEnv = ( env = process.env, prefixes: string | string[] = DEFAULT_CONFIG.ENV_PREFIX ) => Object.fromEntries( Object.entries(env) .map(([key, value]) => { const prefix = Array.isArray(prefixes) ? prefixes.find((prefix) => key.startsWith(prefix)) : key.startsWith(prefixes) ? prefixes : undefined; if (typeof prefix !== "string" || prefix === "") { return undefined; } return [key.slice(prefix.length), value]; }) .filter(Array.isArray) );