vue3+ts項目中.env配置環(huán)境變量與情景配置方式
一、環(huán)境變量配置
官網(wǎng)https://cn.vitejs.dev/guide/env-and-mode.html#intellisense
1. 新建.env開頭的文件在根目錄
為了防止意外地將一些環(huán)境變量泄漏到客戶端,只有以 VITE_ 為前綴的變量才會暴露給經(jīng)過 vite 處理的代碼
.env所有環(huán)境默認加載.env.development開發(fā)模式默認加載.env.production生產(chǎn)模式默認加載.env.check自定義環(huán)境文件
示例:如.env文件
# title VITE_APP_TITLE = vue-guide-project
a. 模式
默認情況下,開發(fā)服務(wù)器 (dev 命令) 運行在 development (開發(fā)) 模式,而 build 命令則運行在 production (生產(chǎn)) 模式。
這意味著當(dāng)執(zhí)行 vite build 時,它會自動加載 .env.production 中可能存在的環(huán)境變量。
在某些情況下,若想在 vite build 時運行不同的模式來渲染不同的標(biāo)題,可以通過傳遞 --mode 選項標(biāo)志來覆蓋命令使用的默認模式。例如,如果你想在 staging (預(yù)發(fā)布)模式下構(gòu)建應(yīng)用:
vite build --mode staging
# package.json
{
# ...
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build --mode staging",
},
}還需要新建一個 .env.staging 文件:
# .env.staging VITE_APP_TITLE = My App (staging)
b. 簡單了解下NODE_ENV和模式Mode
NODE_ENV:定義:技術(shù)上講,NODE_ENV是一個由Node.js暴露給執(zhí)行腳本的系統(tǒng)環(huán)境變量。作用:通常用于確定服務(wù)器工具、構(gòu)建腳本和客戶端library在開發(fā)環(huán)境(development)還是生產(chǎn)環(huán)境(production)下的行為。它的值通常為"production"或"development",用于區(qū)分不同環(huán)境下的邏輯行為。- 模式(
Mode):定義:模式指項目運行或構(gòu)建時的一種特定狀態(tài)或配置。作用:在前端框架中,模式用于定義項目在不同階段(如開發(fā)、生產(chǎn)、測試)下的行為和配置。它可以包含多個環(huán)境變量,并通過特定的文件(如.env.production、.env.development等)來管理這些變量。
所以,我們所寫的.env可以理解為創(chuàng)建的不同的模式變量
2. TypeScript 智能提示,設(shè)置全局類型定義
就是在編碼過程中應(yīng)用這些自定義環(huán)境變量的時候,給出的智能提示。
src目錄下創(chuàng)建一個vite-env.d.ts或者env.d.ts文件src同級別types目錄下創(chuàng)建文件env.d.ts
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_APP_TITLE: string
// 更多環(huán)境變量...
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
interface ViteEnv extends ImportMetaEnv {}- 在
tsconfig.app.json文件中
專門用于處理項目src文件中的TypeScript配置文件,
include配置項加入文件:(會提示自定義設(shè)置的環(huán)境變量)
"include": [ // ... // 第一種方式對應(yīng)配置 "vite-env.d.ts", // 或者 "env.d.ts" // 第二種方式對應(yīng)配置 "types/**.d.ts" // 或者直接 "types" ],
效果圖:

00
- 或者
compilerOptions中加入types:(只會提示默認環(huán)境變量)
{
"compilerOptions": {
// ...
"types": ["vite/client"]
}
}效果圖:

3. 訪問環(huán)境變量
- 客戶端源碼(就是
src文件)中訪問:import.meta.env.VITE_APP_TITLE html中訪問環(huán)境變量:%VITE_APP_TITLE%,如果環(huán)境變量不存在,則會將被忽略而不被替換,- 在配置(
src文件外)文件中訪問環(huán)境變量
Vite 默認是不加載 .env 文件的,因為這些文件需要在執(zhí)行完 Vite 配置后才能確定加載哪一個,舉個例子,root 和 envDir 選項會影響加載行為。
不過當(dāng)你的確需要時,你可以使用 Vite 導(dǎo)出的 loadEnv 函數(shù)來加載指定的 .env 文件。
import { defineConfig, loadEnv } from 'vite'
export default defineConfig(({ command, mode }) => {
// command: "build" | "serve"
// mode 當(dāng)前模式
// 根據(jù)當(dāng)前工作目錄中的 `mode` 加載 .env 文件
// 設(shè)置第三個參數(shù)為 '' 來加載所有環(huán)境變量,而不管是否有 `VITE_` 前綴。
const env = loadEnv(mode, process.cwd(), '')
return {
// vite 配置
define: {
__APP_ENV__: JSON.stringify(env.APP_ENV),
},
}
})輸出:console.log(env)

二、情景配置-根據(jù)不同模式使用不同插件
1. 新建build/getEnv.ts 文件處理環(huán)境文件變量
loadEnv()獲取的環(huán)境變量env從輸出的值可以看出,全是字符串,所以我們可以自定義方法去轉(zhuǎn)換變量類型
/* eslint-disable */
// Read all environment variable configuration files to process.env
export function wrapperEnv(envConf: any): ViteEnv {
const ret: any = {}
for (const envName of Object.keys(envConf)) {
let realName = envConf[envName].replace(/\\n/g, '\n')
realName = realName === 'true' ? true : realName === 'false' ? false : realName
if (envName === 'VITE_PORT') {
realName = Number(realName)
}
if (envName === 'VITE_PROXY' && realName) {
try {
realName = JSON.parse(realName.replace(/'/g, '"'))
} catch (error) {
realName = ''
}
}
ret[envName] = realName
}
return ret
}2. build/plugins/index.ts
新建build/plugins 文件夾處理各種plugins,將每一個plugin配置單獨抽離
plugins文件目錄

- 入口文件
build/plugins/index.ts
// 插件配置 入口文件index.ts
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import { PluginOption } from 'vite'
import VueDevTools from 'vite-plugin-vue-devtools'
import { Px2remPlugin } from './Px2rem' // rem
import { svgLoaderPlugin } from './SvgLoader' // SVG
import { UnocssPlugin } from './Unocss' // unocss
import { VisualizerPlugin } from './Visualizer' // 打包分析
import { ViteCompressionPlugin } from './ViteCompression' // 壓縮gzip
import { ViteImageOptimizerPlugin } from './ViteImageOptimizer' // 圖片壓縮
import { ViteRestartPlugin } from './ViteRestartPlugin' // 修改配置文件自動重啟
export const usePlugins = (isBuild: boolean, viteEnv: ViteEnv) => {
const { VITE_OPEN_VISUALIZER, VITE_OPEN_SVG_LOADER, VITE_OPEN_PX2REM, VITE_OPEN_COMPRESSION } =
viteEnv
const plugins: PluginOption[] = [vue(), vueJsx()]
plugins.push(UnocssPlugin())
if (VITE_OPEN_PX2REM) plugins.push(Px2remPlugin())
if (VITE_OPEN_SVG_LOADER) plugins.push(svgLoaderPlugin())
// 開發(fā)模式下
if (!isBuild) {
plugins.push(VueDevTools())
plugins.push(ViteRestartPlugin())
}
if (isBuild) {
plugins.push(ViteImageOptimizerPlugin())
// 壓縮gzip
VITE_OPEN_COMPRESSION && plugins.push(ViteCompressionPlugin())
// 打包分析
VITE_OPEN_VISUALIZER && plugins.push(VisualizerPlugin())
}
return plugins
}
- 單個
plugin示例:

3. tsconfig.node.json
專門用于Node.js環(huán)境中的TypeScript配置文件,它定義了用于Node.js應(yīng)用程序的TypeScript編譯器選項
tsconfig.node.json文件中:
"include": [ // ... "build/**/*.ts", "types" // 全局類型 ],
4. .eslintrc.cjs中添加
overrides: [
{
files: ['*.ts', '*.tsx', '*.vue'],
rules: {
// 解決 ts 全局類型定義后,eslint報錯的問題
'no-undef': 'off'
}
}
],
// ...
'no-unused-expressions': 'off' // 關(guān)閉禁止使用表達式5. vite.config.ts中
import { usePlugins } from './build/plugins'
// ...
export default defineConfig(({ command, mode }) => {
const isBuild = command === 'build'
const root = process.cwd()
const env = loadEnv(mode, root)
const viteEnv = wrapperEnv(env)
return {
plugins: usePlugins(isBuild, viteEnv),
// ...
}
})三、情景配置-server和build配置
build文件夾中創(chuàng)建server.ts和build.ts文件
1. 將build配置寫入build.ts文件中
export const useBuild = () => {
return {
// 10kb以下,轉(zhuǎn)Base64
assetsInlineLimit: 1024 * 10,
// chunkSizeWarningLimit: 1500,//配置文件大小提醒限制,默認500
rollupOptions: {
output: {
// 每個node_modules模塊分成一個js文件
manualChunks(id: string) {
if (id.includes('node_modules')) {
return 'vendor'
// return id.toString().split('node_modules/.pnpm/')[1].split('/')[0].toString()
}
return undefined
},
// 用于從入口點創(chuàng)建的塊的打包輸出格式[name]表示文件名,[hash]表示該文件內(nèi)容hash值
entryFileNames: 'assets/js/[name].[hash].js', // 用于命名代碼拆分時創(chuàng)建的共享塊的輸出命名
chunkFileNames: 'assets/js/[name].[hash].js', // 用于輸出靜態(tài)資源的命名,[ext]表示文件擴展名
assetFileNames: 'assets/[ext]/[name].[hash].[ext]'
}
}
}
}2. 將server配置寫入server.ts文件中
import type { ProxyOptions } from 'vite'
type ProxyItem = [string, string]
type ProxyList = ProxyItem[]
type ProxyTargetList = Record<string, ProxyOptions>
/**
* 創(chuàng)建代理,用于解析 .env.development 代理配置
*/
const userProxy = (proxyList: ProxyList = []) => {
const ret: ProxyTargetList = {}
proxyList.forEach((item) => {
const [prefix, target] = item
const httpsRE = /^https:\/\//
const isHttps = httpsRE.test(target)
ret[prefix] = {
target,
changeOrigin: true,
ws: true,
rewrite: (path: string) => path.replace(new RegExp(`^${prefix}`), ''),
// https is require secure=false
// Verify SSL certificate
...(isHttps ? { secure: false } : {})
}
})
return ret
}
/**
* server 配置
* @returns
*/
export const useServer = (viteEnv: ViteEnv) => {
const { VITE_PORT, VITE_PROXY } = viteEnv
return {
// 監(jiān)聽所有公共ip
// host: '0.0.0.0',
cors: true,
port: VITE_PORT,
proxy: userProxy(VITE_PROXY)
}
}
3. 完整vite.config.ts文件
import { fileURLToPath, URL } from 'node:url'
import { defineConfig, loadEnv } from 'vite'
import { useBuild } from './build/build'
import { wrapperEnv } from './build/getEnv'
import { usePlugins } from './build/plugins'
import { useServer } from './build/server'
export default defineConfig(({ command, mode }) => {
const isBuild = command === 'build'
const root = process.cwd()
const env = loadEnv(mode, root)
const viteEnv = wrapperEnv(env)
return {
plugins: usePlugins(isBuild, viteEnv),
server: useServer(viteEnv),
build: useBuild(),
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
css: {
preprocessorOptions: {
scss: {
additionalData: `
@use "./src/styles/variables.scss" as *;
@use "./src/styles/mixin.scss" as *;`,
javascriptEnabled: true
}
}
}
}
})
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

