Webpack 通过 dotenv 插件在构建时将 .env 文件中的变量(如 REACT_APP_BASE_URL)注入编译上下文,但这些值不会以明文形式出现在最终 JS 文件中——它们被静态替换为字面量或直接内联,从而避免敏感 URL 泄露。
webpack 通过 dotenv 插件在构建时将 `.env` 文件中的变量(如 `react_app_base_url`)注入编译上下文,但这些值**不会以明文形式出现在最终 js 文件中**——它们被静态替换为字面量或直接内联,从而避免敏感 url 泄露。
在现代前端工程中,将后端 API 地址硬编码进源码是严重的设计缺陷:既违背安全原则,又破坏部署灵活性。你观察到的现象——main.js、1.chunk.js 等产物中完全搜不到 REACT_APP_BASE_URL 或其实际值(如 https://api.example.com)——并非魔法,而是 Webpack 构建流程中环境变量的静态替换机制在起作用。
关键在于:.env.prod 中定义的变量(如 REACT_APP_BASE_URL=https://prod-api.example.com)并不会在运行时通过 process.env 动态读取(浏览器中 process.env 本身并不存在),而是由 Webpack 在编译阶段识别并直接替换源码中对应的引用。
例如,假设你的 React 组件中这样调用 API:
// src/api/client.js
export const fetchUser = () =>
fetch(`${process.env.REACT_APP_BASE_URL}/users`);当 Webpack 配合 Dotenv 插件(如你配置的 new Dotenv({ path: "./.env.prod" }))和 DefinePlugin(React 官方脚手架默认启用,或需手动配置)执行构建时,会发生以下关键步骤:
- 加载环境变量:Dotenv 插件读取 .env.prod,将键值对挂载到 Node.js 的 process.env(仅构建时有效);
- 静态替换:webpack.DefinePlugin(或 @babel/plugin-transform-env 等)将源码中所有 process.env.REACT_APP_BASE_URL 字面量替换为字符串 "https://prod-api.example.com";
- 代码优化:Terser 等压缩器进一步内联该字符串,最终产物中只保留 fetch("https://prod-api.example.com/users") —— 原始变量名和 .env 文件彻底消失。
✅ 正确配置示例(webpack.config.prod.js):
const webpack = require('webpack');
const Dotenv = require('dotenv-webpack');
module.exports = {
mode: 'production',
// ...其他配置
plugins: [
new Dotenv({
path: './.env.prod',
systemvars: true, // 允许覆盖系统环境变量
}),
new webpack.DefinePlugin({
'process.env.REACT_APP_BASE_URL': JSON.stringify(
process.env.REACT_APP_BASE_URL
),
}),
],
};⚠️ 重要注意事项:
- 前缀约束:Create React App 要求自定义环境变量必须以 REACT_APP_ 开头,否则会被忽略(这是安全防护,防止意外泄露 NODE_ENV 等敏感系统变量);
- 构建时绑定:环境变量在 webpack 启动瞬间即被固化,无法在浏览器运行时动态切换。若需运行时配置(如多租户 SaaS),应通过独立的 /config.json 接口获取;
- 安全性本质:该机制不提供“加密”,而是“构建期解耦”——URL 不出现在源码中,且不同环境使用不同 .env 文件,避免误发布;
- 验证方法:检查最终 JS 文件中是否还存在 process.env 字符串,若已全部替换,则说明机制生效。
总结:Webpack 的环境变量注入不是运行时查找,而是编译期代码重写。它让前端代码保持环境无关性,同时确保敏感配置永不进入客户端产物——这才是符合 Twelve-Factor App 原则的生产就绪实践。

















