這是 Vue 的一個長年疑問。準確來說是 Single-Page Application SPA 網頁應用,究竟有什麼方式可以取得 runtime 的變數,而不是直接編譯到程式碼中。
內容
起源
由於 SPA 專案在經過編譯 build 後出來的 JS, CSS 和 HTML 檔案,並不需要一台 http 伺服器來運行。換言之,你在沒有 server 的環境下,是沒有辦法讀取 .env 之類的 runtime 設定的。
解決方案
自建 window.configs
由於運行環境是在瀏覽器上,而瀏覽器必然會有一個名為 window 的物件。因此,你可以在 HTML 檔案中的最靠近 <head> 的地方,優先運行一個 config.js 檔案,然後在這個檔案中去存取 runtime config,並存到 window 的物件內。畢竟 JS 是可以憑空塞一個 key 到物件的,你並不需要事先宣告。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
// config.js // fetch data from backend server and should consider CORS issue fetch("{api-route}") .then(response => { if(response.status !== 200) throw new Error("Error while fetching config.json") return response.json() }) .then(config => { window.configs = config }) .catch((e)=>{ console.log("Config loaded", e) }) // fetch JSON file under the directory fetch("./runtime-config.json") .then(response => { if(response.status !== 200) throw new Error("Error while fetching config.json") return response.json() }) .then(config => { window.configs = config }) .catch((e)=>{ console.log("Config loaded", e) }) |
若你是要從後端伺服器拿資料,那會需要注意 CORS 問題。如果你是從網頁的運行目錄下的一個 json 檔拿資料,那你可以在「佈署」階段動態的去生成這個檔案出來,然後一起發佈到網頁伺服器就可以了。
編譯後,於網頁伺服器上運行腳本更動
這點是在編譯時,將動態的值先寫成一個「準備被取代的值字串,而且要和 key 不一樣」。然後在運行網頁伺服器 ( 像 nginx )時,運行一個 shell script,將比對到的值字串換成指定的樣子。
這個方法目前我是沒有成功過的,因為用來比對的 JS 檔案實在太多,而且也會遇上撞名改錯的問題。況且編譯器通常都會對變數名稱作混淆,你也無法確認其生成的字串有無機會撞名。所以以下搜尋到的方法就留給大家參考。
在 Vue 裡面取用
1 2 3 4 5 6 7 8 9 10 11 12 13 |
export const baseApi = window?.configs?.['VITE_APP_BASE_API'] || import.meta.env.VITE_APP_BASE_API export const envName = window?.configs?.['VITE_APP_ENV_NAME'] || import.meta.env.VITE_APP_ENV_NAME export default { baseApi, envName, } // 別忘了宣告 global 有一個自定義的 configs 值 index.html 在 SPA 載入的位置前加上下面的 script <script src="./config.js"></script> |
參考資料
1. Runtime Configuration for SPAs
2. Environment variables for containerized Vue.js applications and how to set them at runtime
3. Javascript frontend configuration at runtime
4. Vue.js runtime environment variables
5. How to use environment variables in your static webapp/SPA?
6. Pass environment variable into a Vue App at runtime