三分鐘教你搞定 React 項目多環境配置

在實際項目開發中,前端 er 常常會面對多個環境的接口:開發環境、測試環境、生產環境,所以項目中網絡請求的 baseUrl也需要跟隨這些環境來變化。

但是,我們一般會使用像 create-react-app或者 umi這樣的腳手架來做項目的初始化,這些腳手架將 webpack 的配置黑盒化了,如何在不執行 eject 操作的前提下優雅地配置多個項目環境呢?

在項目中最好不要一遇到問題就一鍵執行 eject 操作, eject 操作是不可逆的,執行之後會把所有細節都暴露在我們面前,讓項目目錄變得很龐大。

create-react-app 配置多環境接口

其實查看 create-react-app 的官方文檔可以發現,create-react-app 默認是支持多個環境配置文件的:

  • .env:默認。
  • .env.local:本地覆蓋。除 test 之外的所有環境都加載此文件
  • .env.development.env.test.env.production:設置特定環境。
  • .env.development.local.env.test.local.env.production.local:設置特定環境的本地覆蓋。

左側的文件比右側的文件具有更高的優先級:

  • npm start.env.development.local.env.development.env.local.env
  • npm run build.env.production.local.env.production.env.local.env
  • npm test.env.test.local.env.test.env (注意沒有 .env.local )

例如我們部門目前開發流程中只有開發環境和測試環境兩種接口(其中,本地開發和測試共用一個環境),

所以,我需要將測試環境下打包時使用的接口地址指定爲 env.development中的接口地址,我分別寫了兩份配置文件 .env.development 以及 env.production,但是根據以上create-react-app 的官方文檔,在執行 build 命令時,默認是加載 .env.production 文件中的變量,所以我在測試服務器上執行 npm run build 命令時就會使得接口地址被指定爲生產環境的接口地址,這顯然不是我想要的。

怎麼辦呢?

官方文檔也給了我們答案——可以使用 dotenv 來做環境變量的管理(dotenv 可將環境變量從 .env 文件加載到 process.env中。)

因爲我們要在命令行中使用,所以我們需要使用 dotenv-cli

話不多說,讓我們開始吧~

寫好各個環境的配置文件

首先,我們可以寫好每個環境下的配置文件。

# .env.development
REACT_APP_BASE_URL='http://development.xxx.xxx'
# env.production
REACT_APP_BASE_URL='http://production.xxx.xxx'

修改 package.json 中的 scripts來指定環境

"scripts": {
    "start": "react-app-rewired start",
    "build:dev": "dotenv -e .env.development react-app-rewired build",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject"
  }

這樣,當我需要在測試服務器上打包前端代碼時,我就可以執行npm run build:dev來指定使用 .env.development中的環境變量了~

UMI 配置多環境接口

有了以上的經驗我們就可以知道,其實多環境配置,不外乎就是將各個環境的配置文件分開,並使用額外的手段來在打包時指定對應環境的配置文件。

寫好各個環境的配置文件

查看 UMI 文檔 可知,環境變量被放在 config/config.js下的 define 這個配置中,

如果你使用 TypeScript 開發,那麼配置文件是 config/config.ts。

所以同樣的,我們可以將原來的 config/config.ts 做個分身,寫兩份配置文件,分別是 config/config.dev.ts 和 config/config.prod.ts

修改 package.json 中的 scripts 來指定環境

查看 umi生成的模版項目中的package.json 可以發現: umi 默認是使用 cross-env來爲 umi 打包指定配置文件。所以我們將package.json 中的 scripts 改寫如下:

"scripts": {
  "start": "react-app-rewired start",
  "build-dev": "cross-env UMI_ENV=dev umi dev",
  "build-test": "cross-env UMI_ENV=test umi build",
  "build-prod": "cross-env UMI_ENV=prod umi build",
},

tips:將配置和代碼分開存儲

將配置和代碼分開存儲

因爲各個環境的部署版本之間,配置文件的差異程度可能很大,但是代碼基本是不變的。

當然,上面所說的配置文件不包括內部應用程序的配置(例如,你可能將路由寫成了配置文件)。

判斷一個應用是否正確地將配置排除在代碼之外,一個簡單的方法是看該應用的基準代碼是否可以立刻開源,而不用擔心會暴露任何敏感的信息。——《The Twelve-Factor App》

反面教材

一個比較典型的反面教材就是在代碼中再寫一份類似 getBaseUrl.js這樣的文件來做環境判斷:

// getBaseUrl.js
const TEST_DOMAIN = process.env.REACT_APP_BASE_URL
const PRODUCTION_DOMAIN = process.env.REACT_APP_PRODUCTION_BASE_URL
let domain = TEST_DOMAIN

switch (process.env.NODE_ENV) {
  case 'development':
    domain = TEST_DOMAIN
    break
  case 'production':
    domain = PRODUCTION_DOMAIN
    break
  default:
    domain = TEST_DOMAIN
    break
}

export default domain

上面的變量是 .env 文件裏面寫好的變量:

# .env
REACT_APP_DEVELOPMENT_BASE_URL='http://xxxxxx' # 開發環境/測試環境的接口地址
REACT_APP_PRODUCTION_BASE_URL='http://xxxxxx'  # 生產環境的接口地址

其實我自己在剛開始用 React 寫項目的時候就是這麼幹的😅,這樣相當於將配置寫在了代碼裏面,不僅可維護性比較差,而且別人看你代碼的時候,可讀性也比較差。

測試
運行開發環境(npm start)、打包測試環境(npm run build:dev)、打包生產環境(npm run build:pro),分別 打印 process.env 如下:

// 1. 開發環境(npm start)
{NODE_ENV: "development", PUBLIC_URL: "", REACT_APP_ENV: "development"}
 
// 2. 測試環境(npm run build:dev)
{NODE_ENV: "production", PUBLIC_URL: "", REACT_APP_ENV: "development"}
 
// 3. 生產環境(npm run build:pro)
{NODE_ENV: "production", PUBLIC_URL: "", REACT_APP_ENV: "production"}


使用
html中:%REACT_APP_ENV%
js/jsx中:可以在 process.env 中訪問

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章