Nuxt3 設定值的正確儲存方式

最近又有專案要交付,要把專案部屬到客戶測試機,這次是使用 docker compose 的方式佈署多個容器,只是在處理時就發現前端的 Nuxt3 專案有一個小小的問題:API 連結是寫在 .ts 檔案中。

以上面提到的「API 連結」為例,這個設定值除了部屬的時候以外幾乎不會修改,但是重點就是部屬的時候需要修改,如果寫死在程式中,那怕寫在一個獨立的檔案中,發布後要修改都很麻煩。所以最好的方式就是使用框架的設定值功能,方便從程式碼外部將設定值傳入。

以 Nuxt3 來說,設定值應該要寫在 nuxt.config.ts 的 defineNuxtConfig 中,可以很方便的使用 useRuntimeConfig 讀取設定值。要修改時就算是專案發布後也可以使用 .env 檔案或是設定環境變數的方式來更改設定值的內容。

在 defineNuxtConfig 定義設定值

在下面的程式碼中增加了 runtimeConfig ,在這裡面定義了 apiSecret 和 public.apiBase 這兩個設定值。除了這兩個設定值外還可以自己增加,只是因為安全性考量,只有在 public 區塊中的設定值才有辦法在網頁中讀取的到,其他的設定值例如 apiSecret 則是只有在 server 中可以被讀取。
    
export default defineNuxtConfig({
    devtools: {
        enabled: true
    },
    runtimeConfig: {
        apiSecret: 'my-api-key',
        public: {
            apiBase: 'https://www.ruyut.com',
        },
    }
})
    

另外設定值還有一個限制,就是只能是可以被序列化的資料,例如 function, Set, Map 都不能。

讀取設定值

在網頁中讀取 public 設定值

剛建立完 Nuxt3 專案會有 app.vue ,我們直接在這裡練習:
    
<script setup>
const runtimeConfig = useRuntimeConfig()

console.log(`apiSecret: ${runtimeConfig.apiSecret}`)
console.log(`apiUrl: ${runtimeConfig.public.apiBase}`)
console.log(`runtimeConfig: ${JSON.stringify(runtimeConfig)}`)
</script>
    

取得的資料如下:
    
apiSecret: undefined
apiUrl: https://www.ruyut.com
runtimeConfig: {"public":{"apiBase":"https://www.ruyut.com"},"app":{"baseURL":"/","buildAssetsDir":"/_nuxt/","cdnURL":""}}
    

和一開始提到的一樣,在網頁中沒有辦法取得到 public 以外的資料,所以 apiSecret 是 undefined

在 Server 中讀取全部設定值

例如在之前 Nuxt3 建立 API 這篇文章中介紹的 server 中就可以讀取到全部的資料。 先依據上面的文章建立好 server/api/users.ts 檔案後,可以在裡面讀取到設定值:
    
export default defineNuxtConfig({
    devtools: {
        enabled: true
    },
    runtimeConfig: {
        apiSecret: 'my-api-key',
        public: {
            apiBase: 'https://www.ruyut.com',
        },
    }
})
    

替換 port 開啟下面的網頁後就會取得 API 的回應內容
    
    http://localhost:3000/api/users
    

回應結果如下:
    
{
  "apiSecret": "my-api-key",
  "apiBase": "https://www.ruyut.com",
  "runtimeConfig": {
    "app": {
      "baseURL": "/",
      "buildAssetsDir": "/_nuxt/",
      "cdnURL": ""
    },
    "nitro": {
      "envPrefix": "NUXT_",
      "routeRules": {
        "/__nuxt_error": {
          "cache": false
        },
        "/_nuxt/builds/meta/**": {
          "headers": {
            "cache-control": "public, max-age=31536000, immutable"
          }
        },
        "/_nuxt/builds/**": {
          "headers": {
            "cache-control": "public, max-age=1, immutable"
          }
        }
      }
    },
    "public": {
      "apiBase": "https://www.ruyut.com"
    },
    "apiSecret": "api_secret_token"
  }
}
    

可以正常讀取到資料!

修改設定值

使用 .env 檔案變更設定

可以在 nuxt.config.ts 檔案的旁邊建立一個 .env 檔案,在裡面就可以變更設定值:
    
NUXT_API_SECRET=aaa.bbb.ccc
NUXT_PUBLIC_API_BASE=https://google.com
    

只是格式不太一樣,前面一定要使用 NUXT_ 開頭,然後其他的部分使用全部大寫加上底線('_') 分隔的 SCREAMING_SNAKE_CASE 命名方式,重新啟動服務(例如 npm run dev)後就會讀取到新的值了
    
{
  "apiSecret": "aaa.bbb.ccc",
  "apiBase": "https://google.com",
  "runtimeConfig": {
    "app": {
      "baseURL": "/",
      "buildAssetsDir": "/_nuxt/",
      "cdnURL": ""
    },
    "public": {
      "apiBase": "https://google.com"
    },
    "apiSecret": "aaa.bbb.ccc"
  }
}
    

(已省略部分 JSON 資料)

使用環境變數變更設定

上面提到筆者這次部屬是使用 docker compose ,在執行容器時可以往服務內注入環境變數,以上面的設定值為例,假設是執行 docker 好了,可以使用下面的方式注入環境變數:
    
docker run -d --name my_container -p 3000:3000 -e "NUXT_API_SECRET=aaa.bbb.ccc" -e "NUXT_PUBLIC_API_BASE=https://google.com" my_docker_image
    



參考資料:
Nuxt - Runtime Config

留言