【基础篇】一文带你掌握vite中的环境变量 (结尾对比vue-cli)

345 阅读4分钟

.env 文件

Vite 使用 dotenv 从你的 环境目录 中的下列文件加载额外的环境变量:

.env                # 所有情况下都会加载
.env.local          # 所有情况下都会加载,但会被 git 忽略
.env.[mode]         # 只在指定模式下加载
.env.[mode].local   # 只在指定模式下加载,但会被 git 忽略
  • .env是公用文件,在不同环境下会和并对应的.env.[mode]文件。比如开发环境下会将.env.env.[development]两个文件合并
  • .env优先级相对较低,在.env.[mode]文件中遇到同名变量时会被覆盖

客户端获取环境变量

import.meta.env

客户端会通过import.meta.env获取环境变量

vite内建变量

  • import.meta.env.MODE: {string} 应用运行的模式。

  • import.meta.env.BASE_URL: {string} 部署应用时的基本 URL。他由base 配置项决定。

  • import.meta.env.PROD: {boolean} 应用是否运行在生产环境(使用 NODE_ENV='production' 运行开发服务器或构建应用时使用 NODE_ENV='production' )。

  • import.meta.env.DEV: {boolean} 应用是否运行在开发环境 (永远与 import.meta.env.PROD相反)。

  • import.meta.env.SSR: {boolean} 应用是否运行在 server 上

获取环境变量

限制:除了内置的几个变量以外,变量文件(.env.env.[mode])中带有前缀(envPrefix)的key会被过滤到客户端 (防止意外泄漏)

// 通过envPrefix属性配置前缀来指定环境变量文件中的哪些变量是可以在页面访问的 
import { defineConfig } from "vite"
export default defineConfig({
    envPrefix: 'MyENV'  // 将默认值修改
})
// .env
MyENV_TARGET = 50
// .env.development
MyENV_TARGET = 100
// main.ts
console.log(import.meta.env.MyENV_TARGET) // 100

如果要增加类型提示可以在env.d.ts中补充类型

/// <reference types="vite/client" />
interface ImportMetaEnv {
    readonly MyENV_TARGET: number,   // 补充类型
}

服务器获取环境变量值

loadEnv

  • vite 内部内置了dotenv第三方库(该库的作用:将.env下的环境变量植入到process.env),但是vite默认并有没有直接将其植入,而是暴露了一个方法loadEnv,返回环境变量对象👇
  • 相比于客户端获取变量的值会受到前缀限制,在配置文件中是不会的
import { defineConfig, loadEnv } from 'vite'

export default defineConfig(({command, mode}) => {
    // 第一个参mode,表示读取mode后缀的环境变量文件,将其和.env公共环境变量文件合并
    // 第二个参数process.cwd(): 表示.env文件所在目录
    // 第三个参数envPrefix: 表示返回的变量根据该值过滤,可以填'APP_'前缀过滤
    // console.log(process.env)
    const env = loadEnv(mode, process.cwd(), '')
    console.log('loadEnv', env)
    // code ...
})

为什么不直接通过process.env去取变量,而是通过暴露的方法loadEnv返回的对象去取呢?

  • 因为我们的配置文件中是可以通过envDir属性去指定(改变)读取env的目录的,如果我们直接通过process.env去取的话应该取哪个目录下的呢,我们在顶部取变量值,下面可能将对应的配置属性改变

总结

  • 无论是页面上获取环境变量还是配置文件获取环境变量,都是将.env.env.[mode] 合并到一起
  • 可以通过--mode来传入指定的mode 比如: 新增测试脚本命令test, "test": "vite --mode test",这样可以读取.env和.env.test两个文件下的环境变量,
  • 在配置文件中可以通过loadEnv来读取全部的变量,在页面中可以通过import.meta.env来获取带有envPrefix前缀的变量

向客户端注入全局变量

define

定义全局常量替换方式。其中每项在开发环境下会被定义在全局,而在构建时被静态替换。

Vite 使用 esbuild define 来进行替换,因此值的表达式必须是一个包含 JSON 可序列化值(null、boolean、number、string、array 或 object)或单一标识符的字符串。对于非字符串值,Vite 将自动使用 JSON.stringify 将其转换为字符串。

export default defineConfig({
    define: {
      'import.meta.env.defineVV': 666,  // 注入import.meta.env.defineVV, 注意:这里是注入的
       defineCC: 777  // 注入defineCC
    },
})
// main.ts
console.log('import.meta.env.defineVV', import.meta.env.defineVV)  // import.meta.env.defineVV 666
console.log('defineCC', defineCC) // defineCC 777

如果需要标注ts类型

/// <reference types="vite/client" />
interface ImportMetaEnv {
    readonly defineVV:number
}
declare const defineCC: number

对比vue-cli脚手架

vue-cli也是同样的思路:

  • .env以及.env.[mode]同样会合并,同名变量.env的优先级更低

  • 客户端侧的环境变量,通过process.env.获取。(vite通过import.meta.env.)

    • 本身也会有内置的环境变量:NODE_ENVBASE_URL
    • VUE_APP前缀的变量
  • 服务端通过process.env.获取变量文件中全部的变量。(vite通过loadEnv)

  • 向客户端注入全局变量通过webpack.DefinePlugin。(vite通过define选项)