前端环境变量及vite中本地环境配置实践

news/2024/11/28 23:37:20/

前言

前端在之前并没有工程化的概念,甚至开发环境、测试环境、生产环境全靠大家手动配置。

有了nodejs之后,环境变量 (environment variables)这个概念,便慢慢进入了前端的视野,方便了前端各种环境自动化配置及本地环境的运行。现如今 webpack  、 rollup、vite 等打包工具大行其道,我们不得不将它重视起来。在现代前端开发的整个链路中, 环境变量起到一个项目的配置枢纽作用,也是前端提效的重要一环。今天,我们就一步一步剖析环境变量在前端的使用场景及环境变量是如何在前端环境中发挥作用的。

1、cross-env 配置环境变量,

"build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"

大家经常会看到这种代码,其中cross-env NODE_ENV=production,指定的环境变量key为NODE_ENV,值为production,这样调用之后呢,我们可以通过process.env.NODE_ENV  获取对应的环境变量。

process 是node 的一个进程环境,其中通过process.env可以获取进程环境中的环境变量,方便node在调用时处理各种环境信息。

这种是最基本的环境变量配置方式,NODE_ENV基本上常用的只有两种,development和production,用来做开发和生产的区分。

2、先看一个pageage.json中script的部分。

"scripts": {"dev": "vite","build": "tsc && vite build","preview": "vite preview"},

我们在执行npm run dev的时NODE_ENV 会自动变成develop,为什么可以自动设置呢?只有了解了事情的本质我们才可以更放心大胆的使用各种命令。要想知道为什么会这么执行,我们首先要知道npm run dev 执行的vite方法干了什么,然后我们一步步的来扒源码。先找到vite这个文件夹。

首先我们要知道,当执行npm run 时会自动找到当前目录下的scripts对象,比如我们npm run dev,就会找到package.json下scripts 下的dev 这个指令。我相信可能有些同学会试过,直接在当前目录下执行vite,然后得到了一个:

或者大家会有这个疑问,为什么npm run dev 执行 script 下的dev触发vite可以执行,而我们直接执行不可以呢?这是因为在界面中执行vite是必须要全局安装的才可以的。而不全局安装的要用的话,使用scripts执行,而scripts会默认查找当前node_modules下对应的文件夹,比如vite。找到对应的vite文件夹之后会查找对应的package.json下的bin对应的执行文件,像vite如下:

然后承接上面的疑问,为什么会有默认的development 这个环境变量,在vite中的源代码如下:

他会有个默认值,如果不设置的话,就默认是development。

vite build的时候会默认传入production,所以就变成了production

 所以在vite中,vite 和 vite build 这两个指令执行的时候,环境变量NODE_ENV的值默认为development和production 。

3、介绍了环境变量及vite中默认环境变量的配置,下面我们用vite打包工具来实际落地使用,在实际项目开发中,我们会区分多个环境,就我们自己的项目来说,会有开发、测试、灰度、生产。其中开发环境又分为开发1,开发2,开发3,开发4,测试分为测试1等。

3.1 常见基础项目最省事的做法

import { defineConfig } from "vite";import react from "@vitejs/plugin-react";import * as path from "path";const target = "https://dev1.advai.cn”;export default defineConfig(({ command, mode }) => {return {plugins: [react()],server: {host: "0.0.0.0",proxy: {"/api/dashboard": {target,changeOrigin: true,secure: false,xfwd: false,},},},base: mode === "production" ? "./" : "",resolve: {alias: {"@": path.resolve(__dirname, "./src"),},},};});

这种方案好处是一看就懂,坏处就是你改了地址,代码会被提上去,把别人的本地地址也会覆盖掉。

我们本地要区分多环境时,这种方案就不行,所以,各种构建工具都提供了环境变量的配置及使用,我们这里着重介绍vite的使用,及vite为什么可以这么用,知己知彼,才能用得更好,玩得更溜。

再来看我们之前的那个script案例,

"scripts": {"dev": "vite","build": "tsc && vite build","preview": "vite preview"},

执行vite的时候,会自动种下一个环境变量,叫NODE_ENV来区分我们当前的环境是什么。

那么,其实我们本地请求后端的各种环境也可以通过环境变量来设置。我们可以通过在根目录添加.env.development,.env.development.local两个文件。

其中.env.development 可以包含各个环境的所有配置项,更像是一个清单,大概内容如下:

# dev1# VITE_TARGET=https://dev1.advai.cn# dev2#VITE_TARGET=https://dev2.advai.cn# prodVITE_TARGET=https://prod.advai.cn

.env.development.local文件中是要用到的具体的后端环境,例如:

# dev1VITE_TARGET=https://dev1.advai.cn

这样做有个好处,正常的话,.env.development.local 这个文件是git ignore 要忽略的,这样代码提上去之后会有一个默认启用的VITE_TARGET。

配置完了,环境变量我们要怎么使用呢?

export default defineConfig(({ command, mode }) => {const env = loadEnv(mode, path.resolve(process.cwd()));console.log('env', env);});

这时我们就能获取到自己的环境变量。

完整示例:

import path from 'path';import fs from 'fs';import process from 'process';import { defineConfig, loadEnv } from 'vite';import legacy from '@vitejs/plugin-legacy';import react from '@vitejs/plugin-react';// https://vitejs.dev/config/export default defineConfig(({ command, mode }) => {const env = loadEnv(mode, path.resolve(process.cwd()));console.log('env', env);return {plugins: [react(),],server: {proxy: {'/api/service': {target: env.VITE_TARGET,changeOrigin: true,secure: false,},},host: true,},};});

通过使用env.VITE_TARGET我们就可以动态的获取到本地环境变量中的后端地址了。

其中有的小伙伴可能觉得VITE_ 有点碍事,我们直接写TARGET 不好吗?那我们来试一下,我们将env.development.local改为:

# dev1
TARGET=https://dev1.advai.cn

然后重新执行npm run dev,会发现获取到了一个空对象:

为什么呢?要了解这个问题,首先要知道咱们调用的loadEnv这个方法是干啥用的,官网上也有介绍:

loadEnv接收三个参数,第一个是.env后面的名字,第二个是绝对路径,第三个参数是你环境变量名的前缀,在vite中默认是VITE_,为什么不传VITE_的环境变量就不显示了呢?源码在这里:

vite/env.ts at 134ce6817984bad0f5fb043481502531fee9b1db · vitejs/vite · GitHub ,我将其中几个重要的地方拿出来:

(1)、需要抓取的文件名称

const envFiles = [/** default file */ `.env`,/** local file */ `.env.local`,/** mode file */ `.env.${mode}`,/** mode local file */ `.env.${mode}.local`,]

这里定义vite会抓取的文件名称,并且顺序就是优先级,也就是`.env.${mode}.local` >  `.env.${mode}` >`.env.local` >   `.env` 。这里的环境变量的优先级的根据文件的优先级加载,当有重名的环境变量时,会按文件的优先级来覆盖环境变量的值。

(2)判断包含prefixes的key

for (const key in process.env) {if (prefixes.some((prefix) => key.startsWith(prefix)) &&env[key] === undefined) {env[key] = process.env[key];}}

这段代码写的就是刚才为什么获取不到不带VITE_环境变量的原因,因为这个会判断key是否包含你写的prefixes,然后加载到env这个对象中。如果你没传prefixes 的话,那么默认就是VITE_。

(3)读取路径内容,并返回给process.env

for (const file of envFiles) {const path = lookupFile(envDir, [file], { pathOnly: true, rootDir: envDir });if (path) {const parsed = dotenv.parse(fs__default.readFileSync(path), {debug: ((_a = process.env.DEBUG) === null || _a === void 0 ? void 0 : _a.includes('vite:dotenv')) || undefined});// let environment variables use each othermain({parsed,// prevent process.env mutationignoreProcessEnv: true});// only keys that start with prefix are exposed to clientfor (const [key, value] of Object.entries(parsed)) {if (prefixes.some((prefix) => key.startsWith(prefix)) &&env[key] === undefined) {env[key] = value;}else if (key === 'NODE_ENV' &&process.env.VITE_USER_NODE_ENV === undefined) {// NODE_ENV override in .env fileprocess.env.VITE_USER_NODE_ENV = value;}}}}

遍历envFiles 文件列表,判断如果有对应路径的话,读取路径内容,并取出prefix 开头的环境变量,并返回给process.env。

还有的朋友可能要问,我为什么非要在根目录下创建两个文件?这样我看起来乱得很,我想创建一个文件夹来存放那些env环境变量。其实vite也提供了加载指定目录env文件的配置项,这是官网的介绍

最后我们的vite配置文件改成了:

export default defineConfig(({ command, mode }) => {const env = loadEnv(mode, path.resolve(process.cwd()));return {envDir: './env',plugins: [react(),],server: {proxy: {'/api/iam-service': {target: env.VITE_TARGET,changeOrigin: true,secure: false,},'/accounts/': {target: env.VITE_TARGET,changeOrigin: true,secure: false,},},host: true,},}});

环境变量的默认目录由当前路径改为当前路径下的env文件夹:

 .env.development的内容:

# dev1# VITE_TARGET=https://dev1.advai.cn# dev2#VITE_TARGET=https://dev2.advai.cn# prodVITE_TARGET=https://prod.advai.cn

.env.development.local的内容:

# dev1VITE_TARGET=https://dev1.advai.cn

 .git ignore别忘记修改,这样我们才可以让我们本地的环境变量只作用在本地,

node_modules
.DS_Store
dist
dist-ssr
*.local
node_modules/*
.vscode/

总结:前端现在每天都在发生着变化,从一开始的jquery到现在的vue、react、angular,想要用其实并不难,难的是要保持我们一直前进的脚步,前端虽然关于环境变量的东西并不多,但这种简单的东西理解的透彻了才会让我们逐渐成长。


http://www.ppmy.cn/news/1633.html

相关文章

免费查题接口

免费查题接口 本平台优点: 多题库查题、独立后台、响应速度快、全网平台可查、功能最全! 1.想要给自己的公众号获得查题接口,只需要两步! 2.题库: 查题校园题库:查题校园题库后台(点击跳转&a…

[附源码]Python计算机毕业设计SSM教务一点通管理系统(程序+LW)

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

世界杯太精彩了,带大家用Python做个足球游戏,边玩游戏边看比赛

文章目录 Python零基础快速制作足球游戏(附源代码) 前言 一、Python环境说明 二、游戏程序说明 1、游戏开始界面 2、人物移动规则说明,可支持两位玩家 3、足球规则 4、主方法调取 三、游戏运行效果与比赛结果 1、游戏开始界面 2、…

毫米波传感器原理介绍:测速_1相位

在前文中,我们分析了 IF信号的频率,并展示了该频率与物体到雷达的距离 成正比。在本文中,我们将探讨IF 信号的相位。如果我们希望了解 FMCW 雷达响应物体极小位移的能力,那么研究相位就非常重要。雷达正是凭此非常快速且准确地测量…

sql serve数据库基础入门(2)

前言 🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨ 🐻推荐专栏: 🍔🍟🌯 c语言初阶 🔑个人信条: 🌵知行合一 🍉本篇简介:>: 在上一篇的最后,牛牛介绍了怎么创建表,本篇牛牛介绍如…

新手入门SLAM必备资料

新手入门SLAM必备资料 文章目录 新手入门SLAM必备资料一、SLAM学习书籍1.必读经典2.有很多期,跟着会议一起出的文集3.入门书籍,简单实现及代码4.SLAM入门教材吐血推荐,对深入理解SLAM实质非常有帮助5.作者Joan Sola关于Graph-SLAM的教程,包含位姿变换、传感器模型、图优化以…

【Unity3D】绘制物体表面三角形网格

1 仅绘制三角形网格 1)创建游戏对象 创建一个空对象,重命名为 Grid,并在其下添加需要绘制网格的对象,如下: 场景显示如下: 2)添加脚本组件 GridController.cs using System; using UnityEngin…

Python Gui之tkinter(下)

6.Radiobutton单按按钮 Radiobutton控件用于选择同一组单选按钮中的一个。Radiobutton可以显示文本,也可以显示图像。 7.Checkbutton复选按钮 Checkbutton控件用于选择多个按钮的情况。Checkbutton可以显示文本,也可以显示图像。 经典的Gui类的写法&a…