我們在使用 Node 開發時,可能會碰到需要使用環境變數來設定不同情境所執行的邏輯,也可能是要避免在設定檔中或專案推送至遠端版控倉庫時暴露敏感資訊。
你可能直接使用過 export
來設定環境變數,但環境變數只要一多,執行的指令可能就會變得很長,而且也不好維護。
NODE_ENV=production node -e "console.log(process.env.NODE_ENV)"
更進階的用法是寫成一個檔案,並透過 env
來載入檔案的內容後再執行程式
env $(cat .env) node -e "console.log(process.env.NODE_ENV)"
不過如果我們在檔案內需要註解,可能就會導致環境變數無法正確被解析。
Dotenv 是一個 NPM 的模組,它可以將專案目錄下 .env
的檔案中的環境變數,自動載入至 process.env
,對於專案內使用環境變數非常方便,並且配置簡單也不需要其他依賴套件。
不僅可以添加單行註解,也可以在行內添加註解。
# 這裡可以寫註解
SECRET_KEY=YOURSECRETKEYGOESHERE # 行內註解
SECRET_HASH="something-with-a-#-hash" # 如果字串值包含井字號 # 可以用雙引號包起來
多行的數值也能夠支援
PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
...
Nu3xT...
...
-----END RSA PRIVATE KEY-----"
或者也可以在雙引號描述的字串中使用 \n
字元來表示換行:
PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\nNu3xT...\n-----END RSA PRIVATE KEY-----\n"
有了 DotEnv,你可以很方便的控制專案內的環境變數,甚至為多個環境中定義不同的 .env
檔案,使用時再依據環境指定要自動載入的檔案,便可以載入不同的環境變數應付開發或生產環境的要求。
在 Nuxt 3 中導入 DotEnv 來進行環境變數的載入與控制,讓專案可以控制在執行期間或是客戶端期間可以使用相對應的環境變數,如果你的 Nuxt 專案根目錄中存在一個 .env
檔案,它將會在你使用開發伺服器 nuxi dev
、編譯建構專案 nuxi build
及產生預渲染檔案 nuxi generate
時自動載入。
甚至在開發伺服器啟動時,你只要修改 .env 檔案內容,Nuxt 的實體會自動重新啟動並載入環境變數,並將新的值載入至 process.env
中。
當執行下列指令啟動開發伺服器時,預設會載入 .env
檔名的檔案作為環境變數使用。
npx nuxi dev
如果你想使用不同的檔案來載入環境變數,可以添加擴展 .env 的檔案名稱,例如 .env.local
或 .env.production
,在使用指令執行開發伺服器時,添加 --dotenv
標誌來指定載入的檔案。
npx nuxi dev --dotenv .env.local
當然在 nuxi 下有支援 --dotenv
的指令都可以用此方式來載入不同的環境變數檔案。
npx nuxi build --dotenv .env.production
有些情況你會在 ./nuxt.config.ts 配置 Runtime Config,以便在網站執行時可以使用這些設定,舉例來說,你可以為 API 配置相關的設定。
export default defineNuxtConfig({
runtimeConfig: {
apiSecret: '怎麼可以讓你知道呢 :P',
public: {
apiBase: '/api'
},
},
})
但一些敏感資訊如 Token、金鑰或憑證等,如果直接撰寫於這個設定中,可能依此一併的被推送至遠端版控制倉庫,不僅可能會洩漏敏感資訊,在不同環境的設定檔切換也不是這麼的方便。
Nuxt 3 在 Runtime Config 的配置上支援了 .env 來協助配置,若你的 .env 檔案內有配置相關變數時,在執行的過程中原本配置在 ./nuxt.config.ts 的屬性值,就會自動地被替換為匹配到的環境變數。
.env 的環境變數需要依照特定的格式才能正確的匹配到,命名的方式使用 NUXT_
及 NUXT_PUBLIC_
作為開頭,原本小駝峰命名的設定值,則以全大寫英文字母與使用底線 _
來分隔大小寫來表示。
舉個例子,上述設定的 apiSecret
與 public.apiBase
,在 .env 能匹配到的撰寫方式如下:
NUXT_API_SECRET=api_secret_token
NUXT_PUBLIC_API_BASE=https://api.nuxtjs.org
當我們要使用這兩個 Config 時,透過 Nuxt 3 提供的組合式函式 useRuntimeConfig
,就能夠取得 Nuxt Config 配置的設定值或透過 .env 自動載入所覆蓋的設定。
私有的設定 apiSecret
可以直接透過 runtimeConfig
來取值;公開的設定 apiBase
因為設定在 public 下,所以使用 runtimeConfig.public
來取得 apiBase
的值。
<script>
const runtimeConfig = useRuntimeConfig()
const { apiSecret } = runtimeConfig
const { apiBase } = runtimeConfig.public
</script>
本篇介紹的內容相對簡單,配置與使用上非常的容易,Runtime Config 在使用上也提供了私有與公開的設定方式,我僅需要記住不要將敏感或機密資訊放置在公開的地方,透過專案下 .env 檔案的你就能很方便的控制開發、測試或生產等環境的環境變數,並在啟動伺服器時自動的載入至 Runtime Config 中。與 App Config 不同的是,App Config 來提供給整個 Nuxt App 使用的響應式
配置,同樣也會暴露至客戶端,主要的特性是能夠在應用程式的生命週期來更新這個設定。
感謝大家的閱讀,歡迎大家給予建議與討論,也請各位大大鞭小力一些:)
如果對這個 Nuxt 3 系列感興趣,可以訂閱
接收通知,也歡迎分享給喜歡或正在學習 Nuxt 3 的夥伴。
參考資料
有個疑問還請大大解惑🙏
有點不明白什麼情況會要在 nuxt.config.ts
中配置環境變數,.env*
應該都能做到,且還不用管理兩個地方
您好,在 nuxt.config.ts
中配置的環境變數,可以在 Nuxt 3 中使用 useRuntimeConfig()
,來取得公開跟私有的環境變數。
而在 nuxt.config.ts
配置的環境變數,多數是為了方便也可以讓模組
做使用,而且也不需要依據各種不同環境來做配置。
確實如果你使用 .env
檔案,同樣可以建立 Runtime Config 的設定,指示要遵循 NUXT_
或 NUXT_PUBLIC_
開頭的命名方式。
當然,如果你不使用模組或 useRuntimeConfig()
,只單純的透過 .env
檔案來設置環境變數,那麼也是可以使用 Node 的 process.env
來取得。
只是相較於 useRuntimeConfig()
來說,useRuntimeConfig()
所回傳的物件,是包含 TypeScript 的檢查。
如果你只使用了 .env
檔案,所建立的環境變數,例如 NUXT_PUBLIC_TEST_CONFIG="123"
,在 useRuntimeConfig()
函式的回傳設定物件中,是沒辦法取得所建立的 testConfig
。
也就是說 useRuntimeConfig()
函式所回傳的設定,都需要在 nuxt.config.ts
中做配置,通常配置預設值或不敏感資訊,而在真正使用時,搭配 .env
檔案來做控制。
Ryan老師我有個小問題,
當我執行run build-pre後,再node .output/server/index.mjs的環境中剛開起頁面時,讀取的到apiSecret,隨後點擊NuxtLink到達/about的頁面時,接著再點擊/about內的NuxtLink回到首頁"/",主控台就會顯示401,抓取不到apiSecret,想問老師這是什麼問題呢?
下列提供我的程式碼
/composables/useHttp.js:
const fetch = async (url, params) => {
try {
const { public: { apiBase }, apiSecret } = useRuntimeConfig();
const reqUrl = apiBase + url
const customHeaders = { 'Key': apiSecret }
const { data, error } = await useFetch(reqUrl, { ...params, headers: customHeaders })
const result = data.value;
return result
}
.....
}
export default class Http {
get(url, params) {
return fetch(url, { method: 'get', params })
}
}
.env.dev:
NUXT_PUBLIC_API_TITLE=測試中
NUXT_PUBLIC_API_BASE=https://api.nuxtjs.org
NUXT_API_SECRET=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
package.json:
"build-pre": "npx nuxi build --dotenv .env.dev"
依據您的問題跟提供的範例程式,可以先檢查輸出出來的 .output 資料夾內,是否有包含 apiSecret 的相關字串。
以最新 Nuxt v3.12.4 為例,檔案路徑應為 .output/server/chunks/runtime.mjs
這個檔案內應該會有設置 inlineRuntimeConfig 變數,依照您的寫法跟編譯時的指定 .env.dev 檔案
appTitle, apiBase, apiSecret 這三個設定值應該都會有值才對。
可以先確認這個部分,如果有值,但是啟動伺服器後再您描述的流程上出現 401,那應該就是您有部分流程與邏輯設置錯誤,否則 Runtime Config 應以明確設置,不會有問題才對。
我再 .output/server/chunks/runtime.mjs裡有看到.env.dev的三個變數,但非常奇怪的是當我在路徑:http://localhost:3000/docs
點擊Go To Index後,開啟"檢視原始碼"發現Api的資料有出現,路徑也變回:http://localhost:3000
但是畫面卻沒有隨著變動,Console.log也顯示"Error: FetchError: [GET] "ApiUrl": 401 Access Denied",NetWork也是跳出Status:401,有點搞不清楚為什麼會這樣抓不到key但"檢視原始碼"卻會有資料
apiSecret 只會在伺服器端執行時取得的到,客戶端如果要訪問 apiSecret 是沒辦法的。
在檢視原始碼內會有,是因為這次的請求是由伺服器端接受處理(能訪問),所以拿到資料並回傳給前端。
通常 apiSecret 這個密鑰不會揭露給前端,如果在前端流程真的有需要打這種需要權限驗證的 API,建議是自己再封裝一層內部 API 提供給前端使用。