mountains

SvelteKit で環境変数を使う

SvelteKit プロジェクトは Vite を使用しているので、`import.meta.env` から環境変数を参照できます。単に環境変数を参照するだけならば十分です。ですが SvelteKit により提供されている環境変数の仕組みを使用すると、型安全に環境変数を参照できる、公開してはいけない値をクライアントから参照できなくなるなどのメリットを得られます。

SvelteKit プロジェクトは Vite を使用しているので、import.meta.env から環境変数を参照できます。単に環境変数を参照するだけならば十分です。ですが SvelteKit により提供されている環境変数の仕組みを使用すると、型安全に環境変数を参照できる、公開してはいけない値をクライアントから参照できなくなるなどのメリットを得られます。

SvelteKit では以下の 4 つのモジュールから環境変数を参照できます。

型安全な環境変数

SvelteKit では環境変数を $env/{dynamic|static}/{private|public} から参照できます。このモジュールは SvelteKit により自動で型定義が生成されるため、型安全に環境変数を参照できます。

例えば、以下のような .env ファイルを作成します。

API_KEY=1234567890
PUBLIC_API_KEY=0987654321

vite dev または vite build を実行すると、$env モジュールの型定義が生成されます。

.svelte-kit/ambient.d.ts
declare module '$env/static/private' {
	export const API_KEY: string;
  // ...
}
 
declare module '$env/dynamic/private' {
	export const env: {
		API_KEY: string;
    // ...
  }
}
 
declare module '$env/static/public' {
  export const PUBLIC_API_KEY: string;
  // ...
}
 
declare module '$env/dynamic/public' {
  export const env: {
    PUBLIC_API_KEY: string;
    // ...
  }
}

この型定義により $env モジュールから import することで、型安全に環境変数を参照できます。

src/routes/+page.server.ts
import { API_KEY } from '$env/static/private';
 
API_KEY; // string

環境変数名を typo するといったミスもコンパイルエラーとなるので防ぐことができます。

src/routes/+page.server.ts
import { AP_KEY } from '$env/static/private';
// '"$env/static/private"' has no exported member named 'AP_KEY'. Did you mean 'API_KEY'?ts(2724)

例えば環境変数の設定漏れなどにより、実行時に環境変数が存在しない場合には例外が発生します。そのため、process.env のように型が string | undefined とならずに string 型として参照できるのです。

src/routes/+page.server.ts
import { API_KEY } from '$env/static/private';
// "API_KEY" is not exported by "$env/static/private", imported by "src/routes/+page.server.ts".

もし vite dev または vite build を実行しても Cannot find module '$env/static/public' or its corresponding type declarations.ts(2307) とエラーが表示される場合には tsconfig.jsoninclude.svelte-kit/ambient.d.ts を追加してください。

tsconfig.json
{
  "include": [".svelte-kit/ambient.d.ts"]
}

.env ファイル

dev または preview の場合には .env ファイルから環境変数を読み取ります。.env ファイルの形式や読み込みの優先度は Vite の環境変数の仕組みに従います。

.env                # 全ての場合に読み込まれる
.env.local          # 全ての場合に読み込まれ、gitには無視される
.env.[mode]         # 指定されたモードでのみ読み込まれる
.env.[mode].local   # 指定されたモードでのみ読み込まれ、gitには無視される

env 読み込みの優先度 特定のモードの env ファイル(例: .env.production)は、汎用の env ファイル(例: .env)よりも優先されます。 また、Vite の実行時に既に存在している環境変数は最も優先度が高く、.env ファイルによって上書きされることはありません。例えば、VITE_SOME_KEY=123 vite build を実行する場合。 .env は Vite 起動時に読み込まれます。変更した後はサーバを再起動してください。

.env ファイルがプロジェクトのルート以外の場所にある場合には、svelte.config.jskit.env.dir で指定します。

svelte.config.js
/** @type {import('@sveltejs/kit').Config} */
const config = {
  kit: {
    env: {
      dir: '../',
    },
  },
}

$env モジュール

SvelteKit の $env モジュールは「動的/静的」かつ「公開/非公開」の 4 つのモジュールから構成されています。

動的 静的
公開 $env/dynamic/public $env/static/public
非公開 $env/dynamic/private $env/static/private

dynamic/static

dynamic と static の違いは、ビルド時に値が静的に注入されるかどうかです。dynamicenv というオブジェクトを export し、その中に環境変数が格納されます。そのため、以下のように動的に値を取得できます。

src/routes/+page.server.ts
import { env } from '$env/dynamic/private'
 
const envName = "API_KEY"
 
env[envName] // 1234567890

static はビルド時に値が注入されるため、動的に値を取得することはできません。ですが、静的に値を注入されるためデッドコードの排除などの最適化が可能です。そのため、基本的には static を使用することを推奨します。

src/routes/+page.server.ts
import { API_KEY } from '$env/static/private'
 
API_KEY // 1234567890

public/private

public はクライアント側に公開できる値のみが含まれています。そのため、この public モジュールはどんな場所からでも import できます。

クライアントに公開できる値かどうかは、環境変数の先頭に PUBLIC_ がついているかどうかで判断されます。この値は svelte.config.jskit.env.publicPrefix で変更できます。先頭に PUBLIC_ がついていない環境変数は一切モジュールに含まれません。

src/routes/+page.svelte
<script lang="ts">
  import { PUBLIC_API_KEY } from '$env/static/public'
</script>

private はクライアント側に公開してはいけない機密データを含みます。PUBLIC_ がついていないすべての環境変数がこのモジュールから import できます。

private モジュールはサーバー側で実行されるモジュールでのみ import が可能です。クライアント側で import しようとすると以下のようなエラーが発生します。

src/routes/+page.svelte
<scirpt lang="ts">
  import { API_KEY } from '$env/static/private'
  // Cannot import $env/static/private into client-side code
</scirpt>

サーバー側でのみ実行されるモジュールは Server-only modules と呼ばれています。Server-only modules とされるモジュールは以下の 2 つの条件のうちどちらかを満たす必要があります。

  • ファイル名に .server が含まれている (例: +page.server.ts)
  • モジュールが src/lib/server に置かれている (例: src/lib/server/secret.ts)

Server-only modules もまたクライアント側から import することはできません。

src/routes/+page.svelte
<scirpt lang="ts">
  // $lib は src/lib のエイリアス
  import { secrets } from '$lib/server/private'
  // Cannot import $lib/server/secrets.ts into client-side code
</scirpt>

まとめ

  • SvelteKit では型安全に環境変数を参照できる
  • 機密データが含まれる環境変数がクライアント側に公開されることを防ぐことができる

Contributors

> GitHub で修正を提案する
この記事をシェアする
はてなブックマークに追加

関連記事