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

news2024/11/13 12:55:27

前言

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

有了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

 # prod

VITE_TARGET=https://prod.advai.cn

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

# dev1

VITE_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 other

            main({

                parsed,

                // prevent process.env mutation

                ignoreProcessEnv: true

            });

            // only keys that start with prefix are exposed to client

            for (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 file

                    process.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

 # prod

VITE_TARGET=https://prod.advai.cn

.env.development.local的内容:

# dev1

VITE_TARGET=https://dev1.advai.cn

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/61925.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android背景和音乐

Android背景和音乐前言一、添加背景图片二、加入背景音乐前言 简单的给app添加背景图和音乐 一、添加背景图片 准备好一张合适的背景图片新建一个Empty Activity项目选择Java语言在res中创建一个mipmap文件,将准备的图片粘贴到该文件目录下 在activity_main.xml里面添加代码…

mysql高阶语句

目录 前言 一、高级sql语句 1、按关键字排序 二、区间判断 ——且/或 三、 distinct 查询不重复记录 四、对结果进行分组 五、限制结果条目——limit 六、设置别名(alias ——>as) 七、通配符 八、子查询 前言 当我们对mysql数据库进行了查…

GJB 5000B二级-QA质量保证

1、主要变化情况 修订2条,合并1条(绿色),新增1条(黄色) 新增的主要内容 将原标准过程域名称“过程和产品质量保证”改为“质量保证” 目的:评价并改进已执行的过程和所产生的工作产品的质量,确保其满足已制定的过程说明和适用的标准。 (GJB5000A:过程和产品质量保…

RISC-V SiFiveU64内核——L2 Prefetcher预期器

目录L2 Prefetcher简介操作流退出页边界Memory Map控制寄存器L2 Prefetcher 初始化L2 prefetcher是U64内核新增的功能,U54内核没有这个功能。打开L2 prefetcher功能后,当访问大片内存,同时dcache中没有缓存时,访问内存的速率可以提…

用R语言和python进行社交网络中的社区检测

在这篇文章中,我用R语言和python检测社交网络中的社区。最近我们被客户要求撰写关于社区检测的研究报告,包括一些图形和统计输出。 相关视频:复杂网络分析CNA简介与R语言对婚礼数据聚类(社区检测)和可视化|数据分享 复…

(一)LTspice简介

文章目录前言一、举例1.1、RC滤波1.2、仿真结果二、软件安装总结前言 LTspice是一款高性能SPICE仿真器软件,包括原理图捕获图形界面。可探测原理图以产生仿真结果,通过LTspice内置波形查看器轻松探索。与其他SPICE解决方案相比,LTspice的增强…

mysql之SQL练习

常见面试题 学生表:student(学号,学生姓名,出生年月,性别) 成绩表:score(学号,课程号,成绩) 课程表:course(课程号,课程名称,教师号) 教师表:teacher(教师号,教师姓名) 1查询学生总成绩排名 SELECTstu_no,sum(score_prize) AS to…

安装Hadoop下hive的问题

ji问题的主要来源,由于收到安装文档后替换了一下,出现的问题 一,配置完成后,系统变量需要重启虚拟机, bash 变量需要刷新 #系统环境变量需要重启,bash变量只要source或切换就可以 source .bash_profile 我…

VUE+Spring Boot前后端分离开发实战(六):基于RABC权限通用后台管理系统-给角色动态分配权限和用户

文章目录 前言功能设计后端实现前端实现写在后面前言 本文记录了通用后台管理系统中RABC权限中两个功能:给角色分配权限、给角色设置用户。 给角色分配用户:前端使用到了elementUI中的tree,包括加载树以及给已选配权限给默认值等。给角色设置用户:前端用到了elementUI中的…

我们需要工具支持键集分页

我们需要工具支持键集分页 (use-the-index-luke.com) 您是否知道分页非常麻烦但很容易避免?offset offset指示数据库跳过查询的前 N 个结果。但是,数据库仍必须从磁盘获取这些行并按顺序排列它们,然后才能发送以下行。 这不是实现问题&…

超好用的大数据分析平台分享,SuccBI 一站式大数据分析平台

SuccBI 一站式大数据分析平台融合了数据汇集、加工、智能调度、自助分析可视化、中国式报表等功能为企业提供一站式的大数据分析处理能力。 数据汇集、加工 连接各类分散的数据并进行加工、清洗、调度、元数据管理,帮助企业轻松汇集、管理和共享数据资产。 丰富的数…

SAR信号处理基础2——线性调频信号频谱与驻定相位原理

前面已经给出了线性调频信号的时域表达形式,并介绍了信号的实部、虚部、相位、频率等,本文介绍线性调频信号的频谱,以及推导线性调频信号时常用的驻定相位原理。计算信号的频谱,实际上就是对信号做傅里叶变换。即 驻定相位原理认…

Java高校宿舍管理系统寝室管理(含源码+论文+答辩PPT等)

项目功能简介: 本项目含代码详细讲解视频,手把手带同学们敲代码从0到1完成项目 该项目采用技术JSP、Servlet、jdbc、前端框架 bootstrap、jQuery,bootstrap-datetimepicker日期插件、Tomcat服务器、MySQL数据库 项目含有源码、配套开发软件、软件安装教程…

Linux和WIN的优势

1.性价比方面 Linux服务器与Windows服务器就性价比而言,Linux服务器优势是很明显的。Linux作为资源管理和操作系统来说,是开源、免费的,而正版的Windows的操作系统是收费的,因而就性价比来说Linux服务器优于Windows服务器。 2.性…

python的自定义函数的用法和实例

目录 1.自定义函数的语法和用法 (1)引入 (2)语法 (3)用法:用于自定义目标函数语法。 (4)调用函数 ①语法 ②解释 2.实例 (1)简单的用法 …

[附源码]计算机毕业设计小区物业管理系统Springboot程序

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

Vector - VTESTStudio(软件篇) - CAPL实现MD5算法 - 01

OTA是当前车载行业非常热门的一个话题和研究方向,然而车辆又是跟大家的生命安全息息相关的一个日常工具,因此对于车辆升级的限制条件和安全阈值是我们不可避开的一个话题,今天我们来介绍一下对于文件的校验常用的一个算法MD5。 今天我们先来说下什么是MD5算法,这个…

Java基础:Object类、常用API

第一章 Object类 1.1 概述 java.lang.Object类是Java语言中的根类,即所有类的父类。它中描述的所有方法子类都可以使用。在对象实例化的时候,最终找的父类就是Object。 如果一个类没有特别指定父类, 那么默认则继承自Object类。例如&#…

MOSFET 和 IGBT 栅极驱动器电路的基本原理学习笔记(一)MOSFET技术

MOSFET技术 1.器件类型 2.MOSFET模型 3.MOSFET关键参数 4.开关应用 5.开通过程 6.关断过程 7.功率损耗 8.寄生器件的影响 双极晶体管和 MOSFET 晶体管的工作原理相同。从根本上说,这两种晶体管都是电荷控制器件,这就意味着它们的输出电流与控制电极在半…

4.1 一个简单的Linux Kernel模块

Linux内核包含非常多个组件,但不同的应用场景下需要打包的组件也不尽相同,更何况我们常常因为一些iot设备本身硬件资源有限,为了物尽其用要对内核组件进行裁剪。例如,对于路由器设备来说,我们再在打包Linux 内核时并不需要打包BT等驱动模块。Linux提供了一种称之为模块-Mo…