前端項(xiàng)目中.env文件的原理和實(shí)現(xiàn)方法代碼
為什么要用 .env?
在前端開(kāi)發(fā)中,我們經(jīng)常需要區(qū)分不同環(huán)境下的配置,比如:
- 開(kāi)發(fā)環(huán)境(開(kāi)發(fā)調(diào)試用的 API 地址、本地調(diào)試開(kāi)關(guān));
- 測(cè)試環(huán)境(給測(cè)試同學(xué)用的接口域名、測(cè)試賬號(hào));
- 生產(chǎn)環(huán)境(線上穩(wěn)定接口、CDN 域名、是否啟用 mock 數(shù)據(jù)等)。
如果把這些配置直接寫死在代碼里,不僅管理麻煩,還容易出現(xiàn)「改配置 → 重新打包 → 發(fā)錯(cuò)環(huán)境」的坑。
這時(shí)候 .env 文件就派上用場(chǎng)了。
?? 它能把不同環(huán)境的變量抽離出來(lái),統(tǒng)一放在一個(gè)文件里,通過(guò)工具在打包或運(yùn)行時(shí)注入到代碼中,大大提升了項(xiàng)目的可維護(hù)性。
環(huán)境準(zhǔn)備
我們先來(lái)簡(jiǎn)單準(zhǔn)備下環(huán)境。
如果想直接看 dotenv 的源碼,可以克隆官方項(xiàng)目:
git clone https://github.com/motdotla/dotenv.git # cd dotenv && yarn i # VSCode 打開(kāi)當(dāng)前項(xiàng)目 code .
dotenv 的作用
官方項(xiàng)目地址:
dotenv 是一個(gè)零依賴模塊,用來(lái)把 .env 文件中的環(huán)境變量加載到 process.env 中。
如果需要進(jìn)一步使用變量展開(kāi),還可以配合 dotenv-expand 一起使用。
在前端項(xiàng)目里,.env 文件非常常見(jiàn),比如 vue-cli 和 create-react-app 都支持它。
.env 文件寫法示例
NAME=gengyun AGE=18 VITE_APP_ENV=production VITE_ROUTER_BASE_URL=/ai-form VITE_APP_PRO_USE_MOCK=true
從上面這個(gè) .env 文件就能看出來(lái),.env 的主要用途就是:
- 讀取
.env文件; - 解析成
key=value形式的對(duì)象; - 掛載到
process.env上; - 最后返回解析好的對(duì)象,方便使用。
一個(gè)簡(jiǎn)易版實(shí)現(xiàn)
下面寫一個(gè)簡(jiǎn)單的實(shí)現(xiàn),核心就是 用 Node.js 讀取文件,解析成對(duì)象,然后賦值給 process.env。
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;
雖然能用,但這個(gè) config 函數(shù)還很簡(jiǎn)陋,缺少一些常見(jiàn)功能,比如:
- 支持用戶自定義
.env文件路徑; - 支持自定義編碼;
- 添加
debug模式,方便輸出提示; - 更友好的報(bào)錯(cuò)信息(畢竟
.env文件寫法很隨意)。
升級(jí)版實(shí)現(xiàn)
官方的 dotenv 庫(kù)在源碼里對(duì)這些功能做了處理,比如路徑解析、編碼設(shè)置、調(diào)試日志等。我們也可以稍微擴(kuò)展一下:
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 函數(shù)還處理了更多細(xì)節(jié),比如:
- 正則匹配;
- 支持單雙引號(hào);
- 跨平臺(tái)兼容(Windows/Linux 換行符不同)。
一句話總結(jié)
dotenv 的原理很簡(jiǎn)單:
?? 用 fs.readFileSync 讀取 .env 文件,解析成 key=value 對(duì)象,然后把對(duì)象里的變量掛到 process.env 上。
前端項(xiàng)目里的額外說(shuō)明
不過(guò)要注意:
在 Node.js 環(huán)境(如服務(wù)端)下,直接掛到 process.env 就能用了。
但在 前端項(xiàng)目(瀏覽器環(huán)境)里,瀏覽器本身是訪問(wèn)不到 process 的。
所以像 vue-cli 或 vite 這樣的工具,會(huì)在構(gòu)建階段借助 webpack 的 DefinePlugin(或 Vite 內(nèi)置的變量替換機(jī)制)把 .env 文件里的變量直接替換成具體值,注入到代碼里。
總結(jié) & 擴(kuò)展思考
.env 文件的核心價(jià)值在于:
- 配置解耦:不用把不同環(huán)境的配置寫死在代碼里;
- 方便管理:一套代碼,多套環(huán)境;
- 安全性:敏感信息可以集中管理,避免硬編碼到倉(cāng)庫(kù)。
擴(kuò)展思考:
- 在 前端項(xiàng)目 中,哪些變量適合放在
.env?哪些不能?(比如 API 地址 可以,秘鑰 一定不要!) - 在 多人協(xié)作 時(shí),如何管理不同成員的本地
.env文件?(比如.env.local不要提交到 git) - 除了
dotenv,有沒(méi)有類似的工具?
這些問(wèn)題都值得在實(shí)際項(xiàng)目中思考和總結(jié)。
到此這篇關(guān)于前端項(xiàng)目中.env文件的原理和實(shí)現(xiàn)方法的文章就介紹到這了,更多相關(guān)前端.env文件原理和實(shí)現(xiàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript array常用方法代碼實(shí)例詳解
這篇文章主要介紹了JavaScript array常用方法代碼實(shí)例詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
簡(jiǎn)單實(shí)現(xiàn)節(jié)流函數(shù)和防抖函數(shù)過(guò)程解析
這篇文章主要介紹了簡(jiǎn)單實(shí)現(xiàn)節(jié)流函數(shù)和防抖函數(shù)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10
基于ssm框架實(shí)現(xiàn)layui分頁(yè)效果
這篇文章主要為大家詳細(xì)介紹了基于ssm框架實(shí)現(xiàn)layui分頁(yè)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-07-07
JS一維數(shù)組轉(zhuǎn)化為三維數(shù)組方法
這篇文章主要給大家分享了JS一維數(shù)組轉(zhuǎn)化為三維數(shù)組的方法,下面文章圍繞JS數(shù)組轉(zhuǎn)換的相關(guān)資料展開(kāi)內(nèi)容,對(duì)大家的學(xué)習(xí)有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-01-01
詳解ES6 export default 和 import語(yǔ)句中的解構(gòu)賦值
這篇文章主要介紹了詳解ES6 export default 和 import語(yǔ)句中的解構(gòu)賦值,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-05-05

