浅谈 import.meta.env 和 process.env 的区别

这是一个前端构建环境里非常核心、也非常容易混淆的问题 。下面我们从来源、使用场景、编译时机、安全性 四个维度来谈谈 import.meta.envprocess.env 的区别。


一句话结论

process.env 是 Node.js 的环境变量接口 import.meta.env 是 Vite(ESM)在构建期注入的前端环境变量


一、process.env 是什么?

1️⃣ 本质

  • 来自 Node.js
  • 运行时读取 服务器 / 构建机的系统环境变量
  • 本身 浏览器里不存在
ts 复制代码
console.log(process.env.NODE_ENV);

2️⃣ 使用场景

  • Node 服务
  • 构建工具(Webpack / Vite / Rollup)
  • SSR(Node 端)

3️⃣ 前端能不能用?

👉 不能直接用

浏览器里没有 process

ts 复制代码
// 浏览器原生环境 ❌
Uncaught ReferenceError: process is not defined

4️⃣ 为什么 Webpack 项目里能用?

因为 Webpack 帮你"编译期替换"了

ts 复制代码
process.env.NODE_ENV
// ⬇️ 构建时被替换成
"production"

本质是 字符串替换,不是运行时读取。


二、import.meta.env 是什么?

1️⃣ 本质

  • Vite 提供
  • 基于 ES Module 的 import.meta
  • 构建期 + 运行期可用(但值是构建期确定的)
ts 复制代码
console.log(import.meta.env.MODE);

2️⃣ 特点

  • 浏览器里 原生支持
  • 不依赖 Node 的 process
  • 更符合现代 ESM 规范

三、两者核心区别对比(重点)

维度 process.env import.meta.env
来源 Node.js Vite
标准 Node API ESM 标准扩展
浏览器可用 ❌(需编译替换)
注入时机 构建期 构建期
是否运行时读取
推荐前端使用

⚠️ 两者都不是"前端运行时读取服务器环境变量"


四、Vite 中为什么不用 process.env

1️⃣ 因为 Vite 不再默认注入 process

ts 复制代码
// Vite 项目中 ❌
process.env.API_URL

会直接报错。

2️⃣ 官方设计选择

  • 避免 Node 全局污染
  • 更贴近浏览器真实环境
  • 更利于 Tree Shaking

五、Vite 环境变量的正确用法(非常重要)

1️⃣ 必须以 VITE_ 开头

ts 复制代码
# .env
VITE_API_URL=https://api.example.com
console.log(import.meta.env.VITE_API_URL);

❌ 否则 不会注入到前端


2️⃣ 内置变量

ts 复制代码
import.meta.env.MODE        // development / production
import.meta.env.DEV         // true / false
import.meta.env.PROD        // true / false
import.meta.env.BASE_URL

六、安全性

⚠️ 重要警告

import.meta.env 里的变量 ≠ 私密

它们会:

  • 打进 JS Bundle
  • 可在 DevTools 直接看到

❌ 不要这样做

ts 复制代码
VITE_SECRET_KEY=xxxx

✅ 正确做法

  • 前端:只放"公开配置"(API 域名、开关)
  • 私密变量 :只放在 Node / 服务端

七、SSR / 全栈项目里怎么区分?

在 Vite + SSR(如 Nuxt / 自建 SSR):

Node 端

ts 复制代码
process.env.DB_PASSWORD

浏览器端

ts 复制代码
import.meta.env.VITE_API_URL

两套环境变量是刻意分开的

为什么必须分成两套?(设计原因)

1️⃣ 执行环境不同(这是根因)

位置 运行在哪 能访问什么
SSR Server Node.js process.env
Client Bundle 浏览器 import.meta.env

浏览器里 永远不可能安全地访问服务器环境变量


2️⃣ SSR ≠ 浏览器

很多人误解:

"SSR 是不是浏览器代码先在 Node 跑一遍?"

不完全对

SSR 实际是:

ts 复制代码
Node.js 先跑一份 → 生成 HTML
浏览器再跑一份 → hydrate

这两次执行:

  • 环境不同
  • 变量来源不同
  • 安全级别不同

在 Vite + SSR 中,变量的"真实流向"

1️⃣ Node 端(SSR Server)

ts 复制代码
// server.ts / entry-server.ts
const dbPassword = process.env.DB_PASSWORD;

✔️ 真实运行时读取

✔️ 不会进 bundle

✔️ 只存在于服务器内存


2️⃣ Client 端(浏览器)

ts 复制代码
// entry-client.ts / React/Vue 组件
const apiUrl = import.meta.env.VITE_API_URL;

✔️ 构建期注入

✔️ 会打进 JS

✔️ 用户可见


3️⃣ 中间那条"禁止通道"

ts 复制代码
// ❌ 绝对禁止
process.env.DB_PASSWORD → 浏览器

SSR 不会、也不允许,自动帮你"透传"环境变量


SSR 中最容易踩的 3 个坑(重点)


❌ 坑 1:在"共享代码"里直接用 process.env

ts 复制代码
// utils/config.ts(被 server + client 共用)
export const API = process.env.API_URL; // ❌

问题:

  • Server OK
  • Client 直接炸(或被错误替换)

✅ 正确方式:

ts 复制代码
export const API = import.meta.env.VITE_API_URL;

或者:

ts 复制代码
export const API =typeof window === 'undefined'
    ? process.env.INTERNAL_API
    : import.meta.env.VITE_API_URL;

❌ 坑 2:误以为 SSR 可以"顺手用数据库变量"

ts 复制代码
// Vue/React 组件里
console.log(process.env.DB_PASSWORD); // ❌

哪怕你在 SSR 模式下,这段代码:

  • 最终仍会跑在浏览器
  • 会被打包
  • 是严重安全漏洞

❌ 坑 3:把"环境变量"当成"运行时配置"

ts 复制代码
// ❌ 想通过部署切换 API
import.meta.env.VITE_API_URL

🚨 这是 构建期值

ts 复制代码
build 时确定
→ CDN 缓存
→ 所有用户共享

想运行期切换?只能:

  • 接口返回配置
  • HTML 注入 window.CONFIG
  • 拉 JSON 配置文件

SSR 项目里"正确的分层模型"(工程视角)

ts 复制代码
┌──────────────────────────┐
│        浏览器 Client       │
│  import.meta.env.VITE_*   │ ← 公开配置
└───────────▲──────────────┘
            │
        HTTP / HTML
            │
┌───────────┴──────────────┐
│        Node SSR Server     │
│      process.env.*        │ ← 私密配置
└───────────▲──────────────┘
            │
        内部访问
            │
┌───────────┴──────────────┐
│        DB / Redis / OSS    │
└──────────────────────────┘

这是一条 单向、安全的数据流


Nuxt / 自建 SSR 的对应关系

类型 用途
runtimeConfig Server-only
runtimeConfig.public Client 可见
process.env 仅 server

👉 Nuxt 本质也是在帮你维护这条边界


八、常见误区总结

❌ 误区 1

import.meta.env 是运行时读取

,仍是构建期注入


❌ 误区 2

可以用它动态切换环境

不行,想动态只能:

  • 接口返回配置
  • 或运行时请求 JSON

❌ 误区 3

Vite 里还能继续用 process.env

❌ 除非你手动 polyfill(不推荐)


九、总结

  • 前端(Vite)只认 import.meta.env.VITE_*
  • 服务端(Node)只认 process.env
  • 永远不要把秘密放进前端 env
相关推荐
Electrolux3 小时前
[wllama]纯前端实现大语言模型调用:在浏览器里跑 AI 是什么体验。以调用腾讯 HY-MT1.5 混元翻译模型为例
前端·aigc·ai编程
sanra1233 小时前
前端定位相关技巧
前端·vue
起名时在学Aiifox3 小时前
从零实现前端数据格式化工具:以船员经验数据展示为例
前端·vue.js·typescript·es6
oMcLin3 小时前
如何在Manjaro Linux上配置并优化Caddy Web服务器,确保高并发流量下的稳定性与安全性?
linux·服务器·前端
码途潇潇4 小时前
JavaScript 中 ==、===、Object.is 以及 null、undefined、undeclared 的区别
前端·javascript
之恒君4 小时前
Node.js 模块加载 - 4 - CJS 和 ESM 互操作避坑清单
前端·node.js
放牛的小伙4 小时前
vue 表格 vxe-table 加载数据的几种方式,更新数据的用法
vue.js
be or not to be4 小时前
CSS 背景(background)系列属性
前端·css·css3
前端snow4 小时前
在手机端做个滚动效果
前端
webkubor4 小时前
🧠 2025:AI 写代码越来越强,但我的项目返工却更多了
前端·机器学习·ai编程