iT邦幫忙

2024 iThome 鐵人賽

DAY 27
0
Modern Web

Svelte 的奇妙冒險系列 第 27

[Svelte 的奇妙冒險] Day 27 - 環境變數

  • 分享至 

  • xImage
  •  

今天來介紹 SvelteKit 怎麼使用環境變數(environment variables),所謂環境變數是指我們程式運行所需要的某些設定、參數或敏感資料等等東西存放在程式碼外,方便讓這些變數會隨著環境變化。

SvelteKit 的環境變數共有四種分別是 dynamic/privatedynamic/publicstatic/privatestatic/public,基本上只要記得一個大原則是「client-side 只能使用 public 的環境變數」而 server-side 是所有都能使用。

.env 檔

因為 SvelteKit 是使用 vite 進行打包,所以定義環境變數以及注入環境變數上其實是差不多的,就直接使用 .env 檔案即可,如果有多個 .env 檔案可以使用 --mode 來選擇注入不一樣的 .env 檔。

# in .env
API_KEY=apikey
PUBLIC_API_URL=https://api.example.com

.env 檔的所有變數都可以從 static 取得,接下來在根據變數名稱來決定他是 public 或是 private。預設情況下如果是 PUBLIC_ 開頭的值都會被視為 public ,反之則全部都算是 private

// in day27/+page.server.ts
import { API_KEY } from '$env/static/private';
import { PUBLIC_API_URL } from '$env/static/public';
import type { ServerLoad } from '@sveltejs/kit';

export const load: ServerLoad = () => {
	console.log(API_KEY, PUBLIC_API_URL);
};

會發現 terminal 上的輸出跟我們 .env 的一致

<!--  in day27/+page.svelte -->
<script lang="ts">
	import { API_KEY } from '$env/static/private';
	import { PUBLIC_API_URL } from '$env/static/public';
	console.log(`API_KEY=${API_KEY}`);
	console.log(`PUBLIC_API_URL=${PUBLIC_API_URL}`);
</script>

然後在 +page.svelte (client-side)使用 $env/static/private 就會看到以下錯誤

然後當我把 $env/static/private 刪掉後就能正常運行了。

process.env

那該如何新增 $env/dynamic/(public|private) 呢?基本上就跟我們新增 process.env 一樣直接在指令前新增就好

PUBLIC_API_URL_2=https://api.v2.example.com API_KEY_2=apikey2 pnpm run dev

使用上只要直接 import { env } from '$env/dynamic/private' 然後 SvelteKit 會在 build 的時候幫我們產生 type

// in day27/+page.server.ts
import { env } from '$env/dynamic/private';
import { API_KEY } from '$env/static/private';
import { PUBLIC_API_URL } from '$env/static/public';

import type { ServerLoad } from '@sveltejs/kit';

export const load: ServerLoad = () => {
    console.log(`API_KEY=${API_KEY}`);
	console.log(`PUBLIC_API_URL=${PUBLIC_API_URL}`);
	console.log(`[$env/dynamic/private]API_KEY_2=${env.API_KE}`);
	console.log(`[$env/dynamic/private]PUBLIC_API_URL_2=${env.PUBLIC_API_URL_2}`);
};

我們看 terminal 的輸出可以看到 PUBLIC_API_URL_2undefined ,這是因為他是 PUBLIC_ 開頭的變數,所以就不會被放在 $env/dynamic/private 裡了。

所以只要改用 $env/dynamic/public 即可看到在 CLI 上所輸入的PUBLIC_API_URL_2 的值了

import { env } from '$env/dynamic/private';
import { env as publicEnv } from '$env/dynamic/public';
import { API_KEY } from '$env/static/private';
import { PUBLIC_API_URL } from '$env/static/public';

import type { ServerLoad } from '@sveltejs/kit';

export const load: ServerLoad = () => {
	console.log(`API_KEY=${API_KEY}`);
	console.log(`PUBLIC_API_URL=${PUBLIC_API_URL}`);
	console.log(`[$env/dynamic/private]API_KEY_2=${env.API_KE}`);
	console.log(`[$env/dynamic/private]PUBLIC_API_URL_2=${env.PUBLIC_API_URL_2}`);
	console.log(`[$env/dynamic/public]PUBLIC_API_URL_2=${publicEnv.PUBLIC_API_URL_2}`);
};

那一樣如果我在 +page.svelte 使用 $env/dynamic/private 會跳出錯誤

<script lang="ts">
	import { PUBLIC_API_URL } from '$env/static/public';
	import { env } from '$env/dynamic/private';
	import { env as publicEnv } from '$env/dynamic/public';

	console.log(`PUBLIC_API_URL=${PUBLIC_API_URL}`);
	console.log(`$env/dynamic/public=${JSON.stringify(env, null, 2)}`);
	console.log(`$env/dynamic/private=${JSON.stringify(publicEnv, null, 2)}`);
</script>

<h1>Day 27</h1>

直到我把 import { env } from '$env/dynamic/private' 刪除

該如何選擇用哪一種 env

其實在剛剛的例子中我們會發現即使我們傳進 process.env 的變數依然會可以在 static 被找到,這是因為 SvelteKit 在 build time 時會自動幫我們 merge process.env.env 然後產生 type declaration 。

如果變數名稱一樣會是 process.env 覆蓋掉 .env 的值

所以其實換句話說只要我們能確保 prcoess.env 我們在每個指令/環境都有確實傳入我們該傳入的環境變數,我們依然可以把它當作 static 來 import

同理 .env 檔的環境變數也可以出現在 dynamic

那就產生了兩個疑問「我該選擇使用 prcoess.env 還是 .env 來新增環境變數」以及「dynamic 以及 static 該如何選擇」

  1. 以管理的方便程度來看我會推薦優先使用 .env 來定義環境變數,除非真的是在 server run 時才能確定的環境變數才會建議使用 process.env

  2. 如果可以的話一律推薦使用 static ,因為 dynamic 在 prerender 期間是不能使用的

雖然現在還沒介紹到 prerender ,但可以先想成 SSG 的頁面都不能使用 dynamic 就好。

簡而言之,我自己是覺得 SvelteKit 的環境變數 dynamicstatic 在某些情況下是可以一致的,只是用語意在限制/提醒開發者區分出這兩者,所以我自己的習慣會是 .env 來的一律當作 staticprcoess.env 一律當作 dynamic

我的原因是 .env 上有的一定會出現 $env/* 的 type declaration ,但出現在 $env/* 的type declaration 不一定會出現在 .env ,所以基本上為了方便檢查這件事情我都會建議使用 .env ,畢竟查閱 .env 檔通常會比看 script 還好閱讀吧。


參考資料

source code

demo 站點


上一篇
[Svelte 的奇妙冒險] Day 26 - 進階路由
下一篇
[Svelte 的奇妙冒險] Day 28 - 部署
系列文
Svelte 的奇妙冒險30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言