( mode: string, envDir: string | false, prefixes: string | string[] = 'VITE_', )
| 31 | * variables already present in `process.env`. |
| 32 | */ |
| 33 | export function loadEnv( |
| 34 | mode: string, |
| 35 | envDir: string | false, |
| 36 | prefixes: string | string[] = 'VITE_', |
| 37 | ): Record<string, string> { |
| 38 | const start = performance.now() |
| 39 | const getTime = () => `${(performance.now() - start).toFixed(2)}ms` |
| 40 | |
| 41 | if (mode === 'local') { |
| 42 | throw new Error( |
| 43 | `"local" cannot be used as a mode name because it conflicts with ` + |
| 44 | `the .local postfix for .env files.`, |
| 45 | ) |
| 46 | } |
| 47 | prefixes = arraify(prefixes) |
| 48 | const env: Record<string, string> = {} |
| 49 | const envFiles = getEnvFilesForMode(mode, envDir) |
| 50 | |
| 51 | debug?.(`loading env files: %O`, envFiles) |
| 52 | |
| 53 | const parsed = Object.fromEntries( |
| 54 | envFiles.flatMap((filePath) => { |
| 55 | const stat = tryStatSync(filePath) |
| 56 | // Support FIFOs (named pipes) for apps like 1Password |
| 57 | if (!stat || (!stat.isFile() && !stat.isFIFO())) return [] |
| 58 | |
| 59 | const parsedEnv = parseEnv(fs.readFileSync(filePath, 'utf-8')) |
| 60 | return Object.entries(parsedEnv as Record<string, string>) |
| 61 | }), |
| 62 | ) |
| 63 | |
| 64 | debug?.(`env files loaded in ${getTime()}`) |
| 65 | |
| 66 | // test NODE_ENV override before expand as otherwise process.env.NODE_ENV would override this |
| 67 | if (parsed.NODE_ENV && process.env.VITE_USER_NODE_ENV === undefined) { |
| 68 | process.env.VITE_USER_NODE_ENV = parsed.NODE_ENV |
| 69 | } |
| 70 | // support BROWSER and BROWSER_ARGS env variables |
| 71 | if (parsed.BROWSER && process.env.BROWSER === undefined) { |
| 72 | process.env.BROWSER = parsed.BROWSER |
| 73 | } |
| 74 | if (parsed.BROWSER_ARGS && process.env.BROWSER_ARGS === undefined) { |
| 75 | process.env.BROWSER_ARGS = parsed.BROWSER_ARGS |
| 76 | } |
| 77 | |
| 78 | // let environment variables use each other. make a copy of `process.env` so that `dotenv-expand` |
| 79 | // doesn't re-assign the expanded values to the global `process.env`. |
| 80 | const processEnv = { ...process.env } as DotenvPopulateInput |
| 81 | expand({ parsed, processEnv }) |
| 82 | |
| 83 | // only keys that start with prefix are exposed to client |
| 84 | for (const [key, value] of Object.entries(parsed)) { |
| 85 | if (prefixes.some((prefix) => key.startsWith(prefix))) { |
| 86 | env[key] = value |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | // Vite Task may know prefixed envs not present here; fetch them and let |
no test coverage detected