When referencing an environment variable that doesnt exist, vite dumps your whole environment into the bundle as an object (original) (raw)
Describe the bug
When you reference an env var, the idea is that Vite will replace the reference with the value of that env var. So given the following .env
And the following code
console.log(import.meta.env.VITE_FOO);
The resulting output should be
And this is true and works as expected. But now reference an env var that doesn't exist, you'd expect the replacement to become undefined, like so:
console.log(import.meta.env.VITE_FOO); // 'foo' console.log(import.meta.env.VITE_BAR); // undefined
What actually happens is the whole "env" object is dumped directly into the bundle, then references the var from that, which because its not defined, in the end gives you undefined
var o = { VITE_FOO: "foo", BASE_URL: "/", MODE: "production", DEV: !1, PROD: !0, SSR: !1, };
console.log("foo"); console.log(o.VITE_BAR);
I believe this is wrong and can lead to bad security leaks and instead it should output the following
console.log("foo"); console.log(undefined);
Reproduction
https://github.com/joshmanders/vite-env-bug
Steps to reproduce
Run npm install
Run npm run build
Inspect output in dist/assets/
System Info
System: OS: macOS 14.5 CPU: (10) arm64 Apple M1 Max Memory: 1.38 GB / 64.00 GB Shell: 3.7.1 - /opt/homebrew/bin/fish Binaries: Node: 20.15.0 - /opt/homebrew/bin/node npm: 10.7.0 - /opt/homebrew/bin/npm Watchman: 2024.06.24.00 - /opt/homebrew/bin/watchman Browsers: Brave Browser: 126.1.67.123 Chrome: 126.0.6478.127 Edge: 126.0.2592.102 Safari: 17.5 npmPackages: vite: ^5.3.4 => 5.3.4
Used Package Manager
npm
Logs
Click to expand!
vite:config bundled config file loaded in 11.67ms +0ms vite:config using resolved config: { vite:config root: '/Users/josh/Code/joshmanders/vite-env-bug', vite:config build: { vite:config target: [ 'es2020', 'edge88', 'firefox78', 'chrome87', 'safari14' ], vite:config cssTarget: [ 'es2020', 'edge88', 'firefox78', 'chrome87', 'safari14' ], vite:config outDir: './dist', vite:config assetsDir: 'assets', vite:config assetsInlineLimit: 4096, vite:config cssCodeSplit: true, vite:config sourcemap: false, vite:config rollupOptions: { input: [Array] }, vite:config minify: 'esbuild', vite:config terserOptions: {}, vite:config write: true, vite:config emptyOutDir: null, vite:config copyPublicDir: true, vite:config manifest: false, vite:config lib: false, vite:config ssr: false, vite:config ssrManifest: false, vite:config ssrEmitAssets: false, vite:config reportCompressedSize: true, vite:config chunkSizeWarningLimit: 500, vite:config watch: null, vite:config commonjsOptions: { include: [Array], extensions: [Array] }, vite:config dynamicImportVarsOptions: { warnOnError: true, exclude: [Array] }, vite:config modulePreload: { polyfill: true }, vite:config cssMinify: true vite:config }, vite:config configFile: '/Users/josh/Code/joshmanders/vite-env-bug/vite.config.js', vite:config configFileDependencies: [ '/Users/josh/Code/joshmanders/vite-env-bug/vite.config.js' ], vite:config inlineConfig: { vite:config root: undefined, vite:config base: undefined, vite:config mode: undefined, vite:config configFile: undefined, vite:config logLevel: undefined, vite:config clearScreen: undefined, vite:config build: {} vite:config }, vite:config base: '/', vite:config rawBase: '/', vite:config resolve: { vite:config mainFields: [ 'browser', 'module', 'jsnext:main', 'jsnext' ], vite:config conditions: [], vite:config extensions: [ vite:config '.mjs', '.js', vite:config '.mts', '.ts', vite:config '.jsx', '.tsx', vite:config '.json' vite:config ], vite:config dedupe: [], vite:config preserveSymlinks: false, vite:config alias: [ [Object], [Object] ] vite:config }, vite:config publicDir: '/Users/josh/Code/joshmanders/vite-env-bug/public', vite:config cacheDir: '/Users/josh/Code/joshmanders/vite-env-bug/node_modules/.vite', vite:config command: 'build', vite:config mode: 'production', vite:config ssr: { vite:config target: 'node', vite:config optimizeDeps: { noDiscovery: true, esbuildOptions: [Object] } vite:config }, vite:config isWorker: false, vite:config mainConfig: null, vite:config bundleChain: [], vite:config isProduction: true, vite:config plugins: [ vite:config 'vite:build-metadata', vite:config 'vite:watch-package-data', vite:config 'vite:pre-alias', vite:config 'alias', vite:config 'vite:modulepreload-polyfill', vite:config 'vite:resolve', vite:config 'vite:html-inline-proxy', vite:config 'vite:css', vite:config 'vite:esbuild', vite:config 'vite:json', vite:config 'vite:wasm-helper', vite:config 'vite:worker', vite:config 'vite:asset', vite:config 'vite:wasm-fallback', vite:config 'vite:define', vite:config 'vite:css-post', vite:config 'vite:build-html', vite:config 'vite:worker-import-meta-url', vite:config 'vite:asset-import-meta-url', vite:config 'vite:force-systemjs-wrap-complete', vite:config 'commonjs', vite:config 'vite:data-uri', vite:config 'vite:dynamic-import-vars', vite:config 'vite:import-glob', vite:config 'vite:build-import-analysis', vite:config 'vite:esbuild-transpile', vite:config 'vite:terser', vite:config 'vite:reporter', vite:config 'vite:load-fallback' vite:config ], vite:config css: { lightningcss: undefined }, vite:config esbuild: { jsxDev: false }, vite:config server: { vite:config preTransformRequests: true, vite:config sourcemapIgnoreList: [Function: isInNodeModules$1], vite:config middlewareMode: false, vite:config fs: { vite:config strict: true, vite:config allow: [Array], vite:config deny: [Array], vite:config cachedChecks: undefined vite:config } vite:config }, vite:config preview: { vite:config port: undefined, vite:config strictPort: undefined, vite:config host: undefined, vite:config https: undefined, vite:config open: undefined, vite:config proxy: undefined, vite:config cors: undefined, vite:config headers: undefined vite:config }, vite:config envDir: '/Users/josh/Code/joshmanders/vite-env-bug', vite:config env: { vite:config VITE_FOO: 'foo', vite:config BASE_URL: '/', vite:config MODE: 'production', vite:config DEV: false, vite:config PROD: true vite:config }, vite:config assetsInclude: [Function: assetsInclude], vite:config logger: { vite:config hasWarned: false, vite:config info: [Function: info], vite:config warn: [Function: warn], vite:config warnOnce: [Function: warnOnce], vite:config error: [Function: error], vite:config clearScreen: [Function: clearScreen], vite:config hasErrorLogged: [Function: hasErrorLogged] vite:config }, vite:config packageCache: Map(1) { vite:config 'fnpd_/Users/josh/Code/joshmanders/vite-env-bug' => { vite:config dir: '/Users/josh/Code/joshmanders/vite-env-bug', vite:config data: [Object], vite:config hasSideEffects: [Function: hasSideEffects], vite:config webResolvedImports: {}, vite:config nodeResolvedImports: {}, vite:config setResolvedCache: [Function: setResolvedCache], vite:config getResolvedCache: [Function: getResolvedCache] vite:config }, vite:config set: [Function (anonymous)] vite:config }, vite:config createResolver: [Function: createResolver], vite:config optimizeDeps: { vite:config holdUntilCrawlEnd: true, vite:config esbuildOptions: { preserveSymlinks: false } vite:config }, vite:config worker: { format: 'iife', plugins: '() => plugins', rollupOptions: {} }, vite:config appType: 'spa', vite:config experimental: { importGlobRestoreExtension: false, hmrPartialAccept: false }, vite:config getSortedPlugins: [Function: getSortedPlugins], vite:config getSortedPluginHooks: [Function: getSortedPluginHooks] vite:config } +17ms
Validations
- Follow our Code of Conduct
- Read the Contributing Guidelines.
- Read the docs.
- Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- Make sure this is a Vite issue and not a framework-specific issue. For example, if it's a Vue SFC related bug, it should likely be reported to vuejs/core instead.
- Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.
- The provided reproduction is a minimal reproducible example of the bug.