在 Nuxt 3 中提供了兩種可以方式設定環境變數或前端需要使用的共用設定,分別是在 Nuxt 啟動時會在後端載入使用的 Runtime Config
及可以在前端被使用的 App Config
這兩者間的區別,將會在本篇做一些講解。
在開發網站或部署時,我們總是有一些環境變數需要做設置,dotenv 就是一個很好用的套件,能幫助我們將專案下 .env
檔案載入到 Node.js 的 process.env
之中,尤其在後端伺服器的 API 開發,這些不能公開或敏感的 Key 或設定值,通常不會與整個專案一起進行版本控制,而是針對不同環境與機器,配置於 .env
或環境變數之中。
這個 .env
設定檔內的環境變數,例如,資料庫的帳號密碼、第三方服務的 Token 或 API Key 等,通常只會在伺服器被讀取做使用,也不會洩漏這些設定給使用者知道,我們也稱之為執行時的設定 (Runtime Config)
。
Nuxt 3 提供了可以設定 Runtime Config 的方式,我們可以很方便的來設定這些環境變數給予伺服器執行時使用。
runtimeConfig
我們可以在 nuxt.config.ts
中添加 runtimeConfig
屬性,就可以來設定只有伺服器端可以使用的環境變數。
例如,在 nuxt.config.ts
檔案中,添加一個 apiSecret
至 runtimeConfig
屬性內:
export default defineNuxtConfig({
runtimeConfig: {
apiSecret: '怎麼可以讓你知道呢 :P'
}
})
我們就可以在 Server API 使用 useRuntimeConfig()
獲得執行時的設定,再從中取得 apiSecret
環境變數。
const runtimeConfig = useRuntimeConfig()
export default defineEventHandler((event) => {
const { apiSecret } = runtimeConfig
console.log(`接收到了一個 Server API 請求: ${event.req.url}`)
console.log(`執行時的環境變數 [apiSecret]: ${apiSecret}`)
return 'ok'
})
因為我們是定義在 Server API,所以可以在測試伺服器啟動的 Terminal 看見 console.log 的結果。
此外你也可以在插件或 Vue 中使用 useRuntimeConfig()
來取得執行時的設置,但也僅在 setup 或 Nuxt Lifecycle Hooks 中有效。
runtimeConfig
通常一些密鑰或敏感資訊,我們都會定義在 runtimeConfig
僅供伺服器端做使用,而 runtimeConfig
也可以配置一個 public
的屬性,來把一些環境變數於伺服器端或客戶端做使用,例如,API 的 Base URL 這類在伺服器端打 API 時會需要使用,而客戶端的操作流程也會打同樣的 API 位置,我們就可以使用 public
的屬性。
例如,在 nuxt.config.ts
檔案中,添加一個 apiBase
至 runtimeConfig.public
屬性內:
export default defineNuxtConfig({
runtimeConfig: {
apiSecret: '怎麼可以讓你知道呢 :P',
public: {
apiBase: '/api'
}
}
})
新增 ./pages/profile.vue
頁面:
<template>
<div class="my-24 flex flex-col items-center">
<span class="mt-4 text-2xl text-gray-600">回傳資料:</span>
<p class="mt-4 text-3xl font-semibold text-blue-500">{{ data }}</p>
</div>
</template>
<script setup>
const runtimeConfig = useRuntimeConfig()
const { apiBase } = runtimeConfig.public
console.log(toRaw(runtimeConfig))
const { data } = await useFetch(`${apiBase}/hello`)
</script>
添加在 runtimeConfig.public
屬性的環境變數,在伺服器端與客戶端都可以讀取得到。下圖中可以發現,在瀏覽器中的 Console 所印出的 runtimeConfig
是不會包含僅有在伺服器端能使用的 apiSecret
。
.env
建立環境變數Nuxt 在開發模式或執行時,已經有內建 dotenv,如果在專案目錄下添加了 .env
,Nuxt 會在開發期間、建構時或產生靜態網站時,自動載入 .env
內的環境變數。
例如建立 .env
檔案,內容如下:
NUXT_API_SECRET=api_secret_token
NUXT_PUBLIC_API_BASE=https://nuxtjs.org
這兩個值,將被 dotenv 自動載入至 process.env
中,作為環境變數。
不論是透過 dotenv 自動載入 .env
或其他方式配置的環境變數,只要環境變數命名是 NUXT_
開頭,這個環境變數將會覆蓋 runtimeConfig
的設置。
舉例來說,當我們 runtimeConfig
設置如下:
export default defineNuxtConfig({
runtimeConfig: {
apiSecret: '怎麼可以讓你知道呢 :P',
public: {
apiBase: '/api'
}
}
})
建立 .env
檔案或其他方式設置下列環境變數:
NUXT_API_SECRET=api_secret_token
NUXT_PUBLIC_API_BASE=https://nuxtjs.org
那麼 NUXT_API_SECRET
環境變數,將會覆蓋 runtimeConfig.apiSecret
,而 NUXT_PUBLIC_API_BASE
將會覆蓋 runtimeConfig.public.apiBase
,最終 runtimeConfig
的設定會變成如下:
{
apiSecret: 'api_secret_token', // 被 NUXT_API_SECRET 環境變數覆蓋
public: {
apiBase: 'https://nuxtjs.org' // 被 NUXT_PUBLIC_API_BASE 環境變數覆蓋
}
}
會有這樣子的特性是因為 Nuxt 會在啟動時,先載入 nuxt.conf.ts
內的 runtimeConfig
,建立出呼叫 useRuntimeConfig()
所得到的執行時設定,例如,先建構出了 _runtimeConfig
物件。
const _runtimeConfig = {
apiSecret: '怎麼可以讓你知道呢 :P',
public: {
apiBase: '/api'
}
}
接著會走訪這個 _runtimeConfig
物件裡面的 key
,逐一將 key 的名稱轉換蛇形命名法 (Snake case),並轉成全大寫再加上 NUXT_
前綴後取得對應的環境變數,如果存在就會以新值來覆蓋 _runtimeConfig
內的屬性。
例如 apiSecret
經過轉換變成 api_secret
,接著轉大寫 API_SECRET
最後加上前綴變成 NUXT_API_SECRET
,如此環境變數 NUXT_API_SECRET
的值就覆蓋 runtimeConfig.apiSecret
。
而在 public
下的設置,也會先轉為 public_apiBase
再經過蛇行命名成 public_api_base
等步驟,最後變成 NUXT_PUBLIC_API_BASE
來載入環境變數並覆蓋。
最後小提醒,當建構出生產環境的網站,如 .output
目錄後,dotenv 並不會包含在建構的網站內, 你需要再自己載入或配置環境變數才能正常運作哦,例如在 PM2 配置 env。
Nuxt 3 提供了一個 App Config 的配置方式,來提供給整個 Nuxt App 使用的響應式
配置,並且能夠在生命週期執行之中更新它。
appConfig
在 nuxt.config.ts
檔案中,可以在 appConfig
屬性內添加設置,例如,通常我們會添加像網站主題的主色等這類可以公開
的配置,讓網站可以使用這個設置。
export default defineNuxtConfig({
appConfig: {
theme: {
primaryColor: '#0ea5e9'
}
}
})
當建立好 appConfig
後,就可以使用組合式函數 useAppConfig()
來取得設置。
例如,建立 ./pages/config.vue
,內容如下:
<template>
<div class="my-24 flex flex-col items-center">
<span class="mt-4 text-2xl text-gray-600">theme.primaryColor:</span>
<p class="mt-4 text-3xl font-semibold text-blue-500">{{ theme.primaryColor }}</p>
</div>
</template>
<script setup>
const appConfig = useAppConfig()
const { theme } = appConfig
</script>
app.config
檔案你也可以在專案目錄下建立 app.config.ts
來配置 App Config,這個檔案的副檔名可以是 .ts、.js 或 .mjs。
export default defineAppConfig({
theme: {
primaryColor: '#3b82f6'
}
})
當建立了 app.config.ts
檔案,該設定會與 nuxt.config.ts
檔案中的appConfig
屬性結合,如果具有相同的命名,則以 app.config.ts
檔案內的設置為主。
當設定好的 App Config 在使用時,解構出的變數是具有響應性的,也就是說在其他頁面修改主題顏色的設定,可以響應至所有使用這個設定的元件。
舉個例子
新增一個 darkMode
的屬性至 app.config.ts
檔案內的 theme
:
export default defineAppConfig({
theme: {
primaryColor: '#3b82f6',
darkMode: false
}
})
建立 ./pages/index.vue
,內容如下:
<template>
<div class="bg-white py-24">
<div class="flex flex-col items-center">
<h1 class="text-6xl font-semibold text-gray-800">這裡是首頁</h1>
<div class="my-4 flex flex-col space-y-4">
<NuxtLink to="/config">前往 /config</NuxtLink>
</div>
<p class="mt-4 text-2xl text-gray-600">theme.darkMode:</p>
<span class="mt-4 text-3xl font-semibold text-blue-500">{{ theme.darkMode }}</span>
</div>
</div>
</template>
<script setup>
const appConfig = useAppConfig()
const { theme } = appConfig
</script>
建立 ./pages/config.vue
,內容如下:
<template>
<div class="my-24 flex flex-col items-center">
<p class="mt-4 text-2xl text-gray-600">theme.primaryColor:</p>
<span class="mt-4 text-3xl font-semibold text-blue-500">{{ theme.primaryColor }}</span>
<p class="mt-4 text-2xl text-gray-600">theme.darkMode:</p>
<span class="mt-4 text-3xl font-semibold text-blue-500">{{ theme.darkMode }}</span>
<button
class="mt-6 rounded-sm bg-blue-500 py-2 px-4 text-base font-medium text-white hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2"
@click="theme.darkMode = !theme.darkMode"
>
{{ `${theme.darkMode ? '取消' : '啟用'}深色模式` }}
</button>
<div class="mt-8">
<NuxtLink to="/">回首頁</NuxtLink>
</div>
</div>
</template>
<script setup>
const appConfig = useAppConfig()
const { theme } = appConfig
</script>
如下圖,我們的首頁取得了 App Config 中的 theme.darkMode
預設為 false
,接著我們切換至 /config
頁面,可以將從 useAppConfig()
解構出的 theme
進行變更,我們使用按鈕來設置 theme.darkMode
為 true
或 false
表示啟用或取消深色模式。當變更完成後,回至首頁,可以發現 theme.darkMode
發生了響應。
Nuxt 3 提供了 Runtime Config 及 App Config 來讓我們將常用或預設設定應用在不同的情境,使用時,我們僅需記得,不能公開的金鑰或敏感訊息,僅放置在 runtimeConfig
中而且不在 public
屬性內,runtimeConfig.public
通常放的是前後端會使用到且不常修改的常數。而 App Config 則是當伺服器端與客戶端需要使用的設置,如主題顏色、是否啟用深色模式等這類可以被使用者調整變動的且需要具有響應性,就可以放置在 appConfig
之中。