前端项目中 .env 文件的原理和实现

为什么要用 .env?

在前端开发中,我们经常需要区分不同环境下的配置,比如:

  • 开发环境(开发调试用的 API 地址、本地调试开关);
  • 测试环境(给测试同学用的接口域名、测试账号);
  • 生产环境(线上稳定接口、CDN 域名、是否启用 mock 数据等)。

如果把这些配置直接写死在代码里,不仅管理麻烦,还容易出现「改配置 → 重新打包 → 发错环境」的坑。

这时候 .env 文件就派上用场了。

👉 它能把不同环境的变量抽离出来,统一放在一个文件里,通过工具在打包或运行时注入到代码中,大大提升了项目的可维护性。


环境准备

我们先来简单准备下环境。

如果想直接看 dotenv 的源码,可以克隆官方项目:

bash 复制代码
git clone https://github.com/motdotla/dotenv.git
# cd dotenv && yarn i
# VSCode 打开当前项目
code .

dotenv 的作用

官方项目地址:

👉 github.com/motdotla/do...

dotenv 是一个零依赖模块,用来把 .env 文件中的环境变量加载到 process.env 中。

如果需要进一步使用变量展开,还可以配合 dotenv-expand 一起使用。

在前端项目里,.env 文件非常常见,比如 vue-clicreate-react-app 都支持它。


.env 文件写法示例

ini 复制代码
NAME=gengyun
AGE=18
VITE_APP_ENV=production
VITE_ROUTER_BASE_URL=/ai-form
VITE_APP_PRO_USE_MOCK=true

从上面这个 .env 文件就能看出来,.env 的主要用途就是:

  1. 读取 .env 文件;
  2. 解析成 key=value 形式的对象;
  3. 挂载到 process.env 上;
  4. 最后返回解析好的对象,方便使用。

一个简易版实现

下面写一个简单的实现,核心就是 用 Node.js 读取文件,解析成对象,然后赋值给 process.env

javascript 复制代码
const fs = require('fs');
const path = require('path');

const parse = function (src) {
  const obj = {};
  src.toString().split('\n').forEach(function (line) {
    const keyValueArr = line.split('=');
    const key = keyValueArr[0];
    const val = keyValueArr[1] || '';
    obj[key] = val;
  });
  return obj;
}

const config = function () {
  const dotenvPath = path.resolve(process.cwd(), '.env');
  const parsed = parse(fs.readFileSync(dotenvPath, 'utf-8'));

  Object.keys(parsed).forEach(function (key) {
    if (!Object.prototype.hasOwnProperty.call(process.env, key)) {
      process.env[key] = parsed[key];
    }
  });

  return parsed;
};

console.log(config());
console.log(process.env);

module.exports.config = config;
module.exports.parse = parse;

虽然能用,但这个 config 函数还很简陋,缺少一些常见功能,比如:

  • 支持用户自定义 .env 文件路径;
  • 支持自定义编码;
  • 添加 debug 模式,方便输出提示;
  • 更友好的报错信息(毕竟 .env 文件写法很随意)。

升级版实现

官方的 dotenv 库在源码里对这些功能做了处理,比如路径解析、编码设置、调试日志等。我们也可以稍微扩展一下:

ini 复制代码
const fs = require('fs');
const os = require('os');
const path = require('path');

function resolveHome(envPath) {
  return envPath[0] === '~' ? path.join(os.homedir(), envPath.slice(1)) : envPath;
}

const config = function (options) {
  let dotenvPath = path.resolve(process.cwd(), '.env');
  let encoding = 'utf8';
  let debug = false;

  if (options) {
    if (options.path != null) {
      dotenvPath = resolveHome(options.path);
    }
    if (options.encoding != null) {
      encoding = options.encoding;
    }
    if (options.debug != null) {
      debug = true;
    }
  }

  try {
    const parsed = parse(fs.readFileSync(dotenvPath, { encoding }), { debug });

    Object.keys(parsed).forEach(function (key) {
      if (!Object.prototype.hasOwnProperty.call(process.env, key)) {
        process.env[key] = parsed[key];
      } else if (debug) {
        console.log(`"${key}" is already defined in process.env and will not be overwritten`);
      }
    });

    return parsed;
  } catch (e) {
    return { error: e };
  }
};

dotenv 官方的 parse 函数还处理了更多细节,比如:

  • 正则匹配;
  • 支持单双引号;
  • 跨平台兼容(Windows/Linux 换行符不同)。

一句话总结

dotenv 的原理很简单:

👉 用 fs.readFileSync 读取 .env 文件,解析成 key=value 对象,然后把对象里的变量挂到 process.env 上。


前端项目里的额外说明

不过要注意:

Node.js 环境 (如服务端)下,直接挂到 process.env 就能用了。

但在 前端项目 (浏览器环境)里,浏览器本身是访问不到 process 的。

所以像 vue-clivite 这样的工具,会在构建阶段借助 webpack 的 DefinePlugin (或 Vite 内置的变量替换机制)把 .env 文件里的变量直接替换成具体值,注入到代码里。


总结 & 扩展思考

.env 文件的核心价值在于:

  • 配置解耦:不用把不同环境的配置写死在代码里;
  • 方便管理:一套代码,多套环境;
  • 安全性:敏感信息可以集中管理,避免硬编码到仓库。

扩展思考:

  • 前端项目 中,哪些变量适合放在 .env?哪些不能?(比如 API 地址 可以,秘钥 一定不要!)
  • 多人协作 时,如何管理不同成员的本地 .env 文件?(比如 .env.local 不要提交到 git)
  • 除了 dotenv,有没有类似的工具?

这些问题都值得在实际项目中思考和总结。

相关推荐
Jonathan Star21 小时前
沉浸式雨天海岸:用A-Frame打造WebXR互动场景
前端·javascript
工业甲酰苯胺1 天前
实现 json path 来评估函数式解析器的损耗
java·前端·json
老前端的功夫1 天前
Web应用的永生之术:PWA落地与实践深度指南
java·开发语言·前端·javascript·css·node.js
LilySesy1 天前
ABAP+WHERE字段长度不一致报错解决
java·前端·javascript·bug·sap·abap·alv
Wang's Blog1 天前
前端FAQ: Vue 3 与 Vue 2 相⽐有哪些重要的改进?
前端·javascript·vue.js
再希1 天前
React+Tailwind CSS+Shadcn UI
前端·react.js·ui
用户47949283569151 天前
JavaScript 的 NaN !== NaN 之谜:从 CPU 指令到 IEEE 754 标准的完整解密
前端·javascript
群联云防护小杜1 天前
国产化环境下 Web 应用如何满足等保 2.0?从 Nginx 配置到 AI 防护实战
运维·前端·nginx
醉方休1 天前
Web3.js 全面解析
前端·javascript·electron
java1234_小锋1 天前
Spring事件监听的核心机制是什么?
java·spring·面试