Vite / 环境变量 / import.meta

401 阅读3分钟

1. import.meta 是什么

  • 归属:ECMAScript(ES Module)里的模块元信息,不是 Node 专有 API。
  • 浏览器里:由引擎 + 构建工具(如 Vite)在模块代码里提供;Vite 会扩展出 import.meta.envimport.meta.hot 等。
  • 为什么在控制台直接输入会报错:DevTools 默认不是 type="module" 的模块上下文,容易出现 Cannot use 'import.meta' outside a module。应在项目模块里 console.log,或用模块脚本验证。

2. import.meta.env 里到底有什么

  • 不是整个 .env 文件原文,也不是机器上全部环境变量。
  • 默认规则:只有以 VITE_ 开头的变量会暴露到前端 import.meta.env(可用 envPrefix 改,但要谨慎)。
  • 另有:Vite 内置字段,如 MODEBASE_URLDEVPRODSSR 等(以当前 Vite 版本文档为准)。
  • 未带 VITE_ 的变量:仍可被 vite.configloadEnv() 读到,但不会自动进浏览器里的 import.meta.env

3. .env 文件与 mode 怎么对应

  • vite / vite dev:默认 mode = development → 会加载 .env.development 等。
  • vite build:默认 mode = production → 会加载 .env.production 等。
  • 显式指定vite build --mode test → 加载 .env.test不会在默认 dev 下读 .env.test
  • 因此:写在 .env.test 里的 VITE_*,在 pnpm vite(development)下可能根本未加载,控制台就看不到。

4. 为什么用 VITE_ 前缀

  • 目的:防止把数据库密码、内网地址等整份 .env 打进可在用户浏览器里执行的 JS
  • VITE_ 表示:开发者明确允许该变量出现在前端构建产物里。

5. VITE_PROXY 与敏感信息

  • VITE_ 的变量有资格出现在 import.meta.env
  • 若业务代码从不访问 import.meta.env.VITE_PROXY,生产包未必会把该字符串打进 chunk;但在 dev 下若 console.log(import.meta.env),仍可能看到。
  • 建议:仅给 Vite 开发服务器用的代理配置,用VITE_ 变量 + 只在 vite.configloadEnv 读取,避免误暴露;不必为「配代理」强行抄进 test/pre/prod 的 .env.*,除非真有对应需求。

6. esbuild.dropVITE_DROP_CONSOLE

项目中的逻辑(见 vite.config.ts):

drop: viteEnv.VITE_DROP_CONSOLE && isProdFn(mode) ? ['console', 'debugger'] : [],
  • isProdFn(mode):在 Node 读配置时判断,等价于 mode === 'production'(见 build/getEnv.ts)。
  • 因此:只有 vite build 且未改 --mode(默认 production)或显式 --mode production 时,且 VITE_DROP_CONSOLE 为真,才会删 console / debugger
  • vite build --mode test / premode 不是 production这条不会删 console(即使对应 .env 里写了 VITE_DROP_CONSOLE)。
  • 开发mode === 'development',一般不删,方便调试。
  • build.minify: 'esbuild' 配合时,esbuild 相关选项才会在构建里稳定生效。

7. 「打包」≠ Vite 的 mode 一定是 production

  • 每次 vite build 都是发布型构建(压缩等),但 mode 可以叫 test / pre / development / production,用于切换加载哪份 .env.*import.meta.env.MODE
  • vite build 不带 --mode:默认 mode = production

8. getEnv.tsisProdFn vs env.ts

getEnv.ts
export function isDevFn(mode: string): boolean {
  return mode === 'development';
}

export function isProdFn(mode: string): boolean {
  return mode === 'production';
}

export function isTestFn(mode: string): boolean {
  return mode === 'test';
}
env.ts
 */
export const devMode = 'development';
export const testMode = 'test';
export const preMode = 'pre';
export const prodMode = 'production';

const KNOWN_LOGIN_ENV = new Set([devMode, testMode, preMode, prodMode]);

export const getLoginEnv = () =>
  import.meta.env.VITE_USER_MODE_ENV ?? (KNOWN_LOGIN_ENV.has(import.meta.env.MODE) ? import.meta.env.MODE : devMode);

export const isTestMode = () => getLoginEnv() === testMode;
export const isPreMode = () => getLoginEnv() === preMode;
export const isDevMode = () => import.meta.env.DEV;
export const isProdMode = () => getLoginEnv() === prodMode;
项目isProdFn(mode)(如 getEnv)env.ts(如 getLoginEnv / isProdMode
运行位置仅 Node,解析 vite.config浏览器 / 打包后的前端代码
数据来源defineConfig(({ mode }) => ...)import.meta.env(含 VITE_USER_MODE_ENVMODEDEV 等)
用途构建行为(删 console、代理等)业务逻辑(如版本检查间隔、登录环境)
能否互相替代不能:浏览器里调不到 isProdFn不能:vite.config 里不能靠运行时代码判断业务环境
  • isProdMode()(当前实现):getLoginEnv() === 'production',优先 VITE_USER_MODE_ENV,表达的是业务四环境,和 import.meta.env.PROD(是否「已构建产物」)不一定同一含义。
  • isDevMode():对应 import.meta.env.DEV(本地 dev server 为 true,一般 build 产物为 false)。

9. 快速对照表

问题结论
控制台为何没有 import.meta默认非模块上下文
为何只有部分 env 出现在前端默认仅 VITE_* + 内置字段
.env.test 在 dev 里看不到dev 默认 development,不加载 .env.test
vite build 默认 modeproduction
删 console 何时生效mode === 'production'VITE_DROP_CONSOLE 为真(按当前项目写法)