前端项目中 .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,有没有类似的工具?

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

相关推荐
lijun_xiao20093 小时前
前端最新Vue2+Vue3基础入门到实战项目全套教程
前端
90后的晨仔3 小时前
Pinia 状态管理原理与实战全解析
前端·vue.js
杰克尼3 小时前
JavaWeb_p165部门管理
java·开发语言·前端
90后的晨仔3 小时前
Vue3 状态管理完全指南:从响应式 API 到 Pinia
前端·vue.js
90后的晨仔3 小时前
Vue 内置组件全解析:提升开发效率的五大神器
前端·vue.js
我胡为喜呀3 小时前
Vue3 中的 watch 和 watchEffect:如何优雅地监听数据变化
前端·javascript·vue.js
我登哥MVP4 小时前
Ajax 详解
java·前端·ajax·javaweb
非凡ghost4 小时前
Typora(跨平台MarkDown编辑器) v1.12.2 中文绿色版
前端·windows·智能手机·编辑器·软件需求
馨谙5 小时前
/dev/null 是什么,有什么用途?
前端·chrome
JamSlade5 小时前
流式响应 sse 系统全流程 react + fastapi为例子
前端·react.js·fastapi