Vue腳手架模式與環境變量
在真實項目裏,「如果每次切換環境都手動改代碼,不僅低效,還極易把測試地址帶到線上。Vue CLI 把「模式 + 環境變量」做成了一套約定大於配置的體系,只要理解規則,就能讓同一份源碼在任意環境自動作出正確的行為。
一、模式(mode)
Vue CLI 把「運行命令」抽象成三種默認模式:
development:對應vue-cli-service serveproduction:對應vue-cli-service buildtest:對應vue-cli-service test:unit
模式本身不攜帶任何變量,它只是約定文件名前綴。
當你執行:
npm run serve # 實際等價於 vue-cli-service serve --mode development
npm run build:staging # 自定義命令,等價於 vue-cli-service build --mode staging
CLI 會按以下順序尋找文件:
.env.[mode].local.env.[mode].env.local(永遠被 git ignore).env
同名變量後者覆蓋前者,因此你可以把公共值寫在 .env,把敏感值寫在 .env.local,把環境特有值寫在 .env.staging,一條命令即可切換。
二、環境變量
- 只有
VUE_APP_開頭的變量才會被打包
任何機器級環境變量(PATH、HOME …)都會被忽略,避免污染前端運行時。
想讓變量進 bundle,必須加前綴:
# .env.staging
VUE_APP_API_BASE=https://staging.api.example.com
在代碼裏直接用:
axios.defaults.baseURL = process.env.VUE_APP_API_BASE
構建時 CLI 會把 process.env.VUE_APP_API_BASE 替換為字符串字面量,零運行時開銷。
- 運行時不可動態修改
變量在 npm run build 那一刻就被寫死,前端無法通過 process.env.XXX = 'new' 去改。
需要運行時可變配置?把變量寫成 JSON 文件或接口返回,再在前端異步加載即可。
三、一個文件,一條命令,三種環境
假設我們要同時支持 dev / staging / prod:
根目錄
├─ .env # 公共配置
├─ .env.development # 本地開發
├─ .env.staging # 預發
├─ .env.production # 線上
└─ package.json
文件內容示例:
# .env
VUE_APP_TITLE=MyApp
# .env.development
VUE_APP_API_BASE=http://localhost:3000
# .env.staging
VUE_APP_API_BASE=https://staging.api.example.com
# .env.production
VUE_APP_API_BASE=https://api.example.com
自定義腳本:
"scripts": {
"serve": "vue-cli-service serve",
"build:staging": "vue-cli-service build --mode staging",
"build": "vue-cli-service build"
}
執行:
npm run build:staging
CLI 自動讀取 .env.staging 與 .env 合併,輸出包裏只有 https://staging.api.example.com。
四、CI/CD 中的最佳實踐
-
不把敏感密鑰寫進倉庫
把
.env*.local加入.gitignore,在 CI 裏用環境變量注入:
echo $STAGING_KEY >> .env.staging.local
-
單一 Dockerfile,多階段構建
通過
ARG MODE動態決定--mode,同一份鏡像可在測試、預發、生產之間漂移。 -
可視化差異
在構建日誌裏打印
console.log('Build mode:', process.env.NODE_ENV, process.env.VUE_APP_API_BASE),一眼確認變量是否生效。
五、常見問題
-
變量名可以改前綴嗎?
可以,在
vue.config.js裏設置envPrefix: 'APP_'即可。 -
為什麼本地
.env改了值不生效?vue-cli-service serve會緩存舊進程,重啓 dev-server 或加--no-cache即可。 -
如何讀取非 VUE_APP 變量?
在
vue.config.js用chainWebpack手動注入:
config.plugin('define').tap(args => {
args[0]['process.env.CUSTOM'] = JSON.stringify(process.env.CUSTOM)
return args
})