React-Environment-Variable

學起來會很方便。

簡述

在進入職場前,環境變數對我來說主要是拿來儲存 API Key 之類的東西,一直到了最近我才理解環境變數其實還有另一個用途是「拿來區分不同環境」。

舉例來說,最常見的差異是開發環境和生產環境上的 API 端口可能會不一樣,這時候就很適合用環境變數來設定端口的值。又或者說在不同環境上可能會想呈現一些不同的資訊,這時候也很適合用環境變數來設置。

總而言之,這篇主要是想紀錄一下在 React 上如何使用環境變數。

NODE_ENV

當我們在用 npm run startnpm run buildnpm run test 時其實預設會自動來帶入 NODE_ENV 這個環境變數,而這個值會顯示目前的環境是什麼:

  • development
  • production
  • test

換句話說,其實你可以把 react 預設給你的指令想成是這樣:

1
2
3
4
5
6
"scripts": {
"start": "NODE_ENV=development react-scripts start",
"build": "NODE_ENV=production react-scripts build",
"test": "NODE_ENV=test react-scripts test",
"eject": "react-scripts eject"
}

只是這些值是不能修改的,所以在實際情況中你不會看到 NODE_ENV=xxxx 這樣的設定。

來舉個例子,假設我們有底下的 Code:

1
2
3
4
5
6
7
8
9
10
function App() {
return (
<div className='App'>
<header className='App-header'>
<img src={logo} className='App-logo' alt='logo' />
<p>Env: {process.env.NODE_ENV}</p>
</header>
</div>
)
}

在 Dev 環境(npm run start)上跑的結果會是:

example1-dev

在 Production 環境(npm run build)上跑的結會是:

example1-pro

透過終端上輸入 Env 變數

假設目前的 Code 長這樣:

1
2
3
4
5
6
7
8
9
10
function App() {
return (
<div className='App'>
<header className='App-header'>
<img src={logo} className='App-logo' alt='logo' />
<p>Env: {process.env.REACT_APP_DEMO_CODE}</p>
</header>
</div>
)
}

為了讀取到 REACT_APP_DEMO_CODE 這個變數,我們可以在執行 react-script 之前把變數寫進去:

example2-cmd

或者是寫在 package.json 中(兩個背後的執行方式是一樣的):

1
2
3
4
5
6
"scripts": {
"start": "REACT_APP_DEMO_CODE=PeaNu react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
}

這邊的執行結果長這樣:

example2-result

透過 .env 檔案來輸入變數

Create React App 預設會自動存取這幾個 .env 檔案:

  • .env:可以在所有環境中存取,除了 test
  • .env.local:可以在所有環境中存取,除了 test(更強的優先權)
  • .env.development, .env.test, .env.production:可以在指定的還境中存取
  • .env.development.local, .env.test.local, .env.production.local:可以在指定的還境中存取(更強的優先權)

所以你只要建立符合這些名稱的檔案以後,就可以直接在專案中存取到這些 Env 變數。

會分成這麼多的原因主要是為了針對不同環境來讀取不同的 Env 變數,等一下會在解釋他們實際的差別,這邊先來看個示範。

首先在根目錄建立 .env 檔案,並填入底下內容:

1
REACT_APP_DEMO_CODE='Hello PeaNu'

接著就能存取到這個變數了:

example3-result

順道一提,因為這邊示範用的是 .env 檔案,所以不管是 development 或 production 都可以存取這個變數。

所以這幾個檔案的差別在哪?

我們先來看官方文件,它其實有提到每個 .env 檔案之間的「優先權」:

  • npm start: .env.development.local, .env.local, .env.development, .env
  • npm run build: .env.production.local, .env.local, .env.production, .env
  • npm test: .env.test.local, .env.test, .env (note .env.local is missing)

附註:(優先順序是左邊 > 右邊)

舉例來說,如果你的專案同時存在 .env.env.local 時,在 npm run start 的情境下會採用 env.local 的內容,.env 就不會被存取到,其他的也是以此類推。

存取 package.json 中的內容

假設我們的 package.json 有這些內容:

1
2
3
4
5
6
7
{
"name": "my-awesome-project",
"version": "0.1.0",
"homepage": ".",
"private": true
// ...
}

如果我們想透過 .env 來存取這些內容的話,可以用 $ 來存取變數:

1
2
REACT_APP_VERSION=$npm_package_version
REACT_APP_NAME=$npm_package_name

接著在 Code 裡面存取這些 Env 變數就可以拿到對應的值了:

1
2
3
4
5
6
7
8
9
10
11
12
13
function App() {
return (
<div className='App'>
<header className='App-header'>
<img src={logo} className='App-logo' alt='logo' />
<p>Current Version: {process.env.REACT_APP_VERSION}</p>
<p>Current Name: {process.env.REACT_APP_NAME}</p>
</header>
</div>
)
}

export default App

example4-result

自定義 .env 檔案

如果你不想要用預設提供的那些 .env 檔案名稱(.env.production.env.development 等等那些),而是想自己取名字,例如說我想建立 .env.dev.env.demo 來分別給 Dev / Demo 環境使用。

1
2
3
4
// .env.dev
REACT_APP_VERSION=$npm_package_version
REACT_APP_NAME=$npm_package_name
REACT_APP_MESSAGE='Welcome to dev envioment'
1
2
3
4
// .env.demo
REACT_APP_VERSION=$npm_package_version
REACT_APP_NAME=$npm_package_name
REACT_APP_MESSAGE='Welcome to demo envioment'

那麼現在會碰到的問題是如果沒告訴 react-scripts 的話,他都吃不到這兩個 .env 檔案的內容。

這時候就可以把 npm script 的部分修改成底下這樣:

1
2
3
4
5
6
7
8
{
"scripts": {
"start": "sh -ac '. ./.env.dev; react-scripts start'",
"build": "sh -ac '. ./.env.demo; react-scripts build'",
"test": "react-scripts test",
"eject": "react-scripts eject"
}
}

附註:注意 sh -ac 後面要執行的指令要放在單引號(') 中

關於這個 sh -ac 的意思我不想解釋太深,但我自己的理解是:透過 sh 來執行一段 shell。因為我們是直接呼叫 shell,所以有能力把 .env 帶入 process 物件中,並且執行 react-scripts,詳細可以參考這篇討論

如果上面聽不懂的話也沒關係,你只要知道透過它我們就可以把指定的 .env 來丟給 react-scripts 執行就好了。

設定好以後執行 npm run start 會得到這樣的結果:

example5-dev

執行 npm run build 以後會得到這樣的結果:

example5-demo

Echarts Note Neovim-配置筆記
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×