浅谈 storeToRefs
StoreToRefs 是专门用来把 Pinia store 解构成「仍然有响应性 + 完整 TS 提示」的 refs 工具。
这是一个前端构建环境里非常核心、也非常容易混淆的问题。下面我们从来源、使用场景、编译时机、安全性四个维度来谈谈 import.meta.env 和 process.env 的区别。
process.env是 Node.js 的环境变量接口import.meta.env是 Vite(ESM)在构建期注入的前端环境变量
process.env 是什么?console.log(process.env.NODE_ENV);
👉 不能直接用
浏览器里没有 process:
// 浏览器原生环境 ❌
Uncaught ReferenceError: process is not defined
因为 Webpack 帮你“编译期替换”了
process.env.NODE_ENV
// ⬇️ 构建时被替换成
"production"
本质是 字符串替换,不是运行时读取。
import.meta.env 是什么?import.meta
console.log(import.meta.env.MODE);
process
| 维度 | process.env | import.meta.env |
|---|---|---|
| 来源 | Node.js | Vite |
| 标准 | Node API | ESM 标准扩展 |
| 浏览器可用 | ❌(需编译替换) | ✅ |
| 注入时机 | 构建期 | 构建期 |
| 是否运行时读取 | ❌ | ❌ |
| 推荐前端使用 | ❌ | ✅ |
⚠️ 两者都不是“前端运行时读取服务器环境变量”
process.env?process
// Vite 项目中 ❌
process.env.API_URL
会直接报错。
VITE_ 开头# .env
VITE_API_URL=https://api.example.com
console.log(import.meta.env.VITE_API_URL);
❌ 否则 不会注入到前端
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里的变量 ≠ 私密
它们会:
VITE_SECRET_KEY=xxxx
Node 端
process.env.DB_PASSWORD
浏览器端
import.meta.env.VITE_API_URL
两套环境变量是刻意分开的。
| 位置 | 运行在哪 | 能访问什么 |
|---|---|---|
| SSR Server | Node.js | process.env |
| Client Bundle | 浏览器 | import.meta.env |
浏览器里 永远不可能安全地访问服务器环境变量。
很多人误解:
“SSR 是不是浏览器代码先在 Node 跑一遍?”
❌ 不完全对
SSR 实际是:
Node.js 先跑一份 → 生成 HTML
浏览器再跑一份 → hydrate
这两次执行:
// server.ts / entry-server.ts
const dbPassword = process.env.DB_PASSWORD;
✔️ 真实运行时读取
✔️ 不会进 bundle
✔️ 只存在于服务器内存
// entry-client.ts / React/Vue 组件
const apiUrl = import.meta.env.VITE_API_URL;
✔️ 构建期注入
✔️ 会打进 JS
✔️ 用户可见
// ❌ 绝对禁止
process.env.DB_PASSWORD → 浏览器
SSR 不会、也不允许,自动帮你“透传”环境变量
process.env
// utils/config.ts(被 server + client 共用)
export const API = process.env.API_URL; // ❌
问题:
✅ 正确方式:
export const API = import.meta.env.VITE_API_URL;
或者:
export const API =typeof window === 'undefined'
? process.env.INTERNAL_API
: import.meta.env.VITE_API_URL;
// Vue/React 组件里
console.log(process.env.DB_PASSWORD); // ❌
哪怕你在 SSR 模式下,这段代码:
// ❌ 想通过部署切换 API
import.meta.env.VITE_API_URL
🚨 这是 构建期值:
build 时确定
→ CDN 缓存
→ 所有用户共享
想运行期切换?只能:
┌──────────────────────────┐
│ 浏览器 Client │
│ import.meta.env.VITE_* │ ← 公开配置
└───────────▲──────────────┘
│
HTTP / HTML
│
┌───────────┴──────────────┐
│ Node SSR Server │
│ process.env.* │ ← 私密配置
└───────────▲──────────────┘
│
内部访问
│
┌───────────┴──────────────┐
│ DB / Redis / OSS │
└──────────────────────────┘
这是一条 单向、安全的数据流。
| 类型 | 用途 |
|---|---|
| runtimeConfig | Server-only |
| runtimeConfig.public | Client 可见 |
| process.env | 仅 server |
👉 Nuxt 本质也是在帮你维护这条边界
import.meta.env是运行时读取
❌ 错,仍是构建期注入
可以用它动态切换环境
❌ 不行,想动态只能:
Vite 里还能继续用
process.env
❌ 除非你手动 polyfill(不推荐)
import.meta.env.VITE_*
process.env