SvelteKit での環境変数の使い方

SvelteKit で $env モジュールを使って環境変数をハンドリングする方法について解説しています。

やりたいこと

SvelteKit の環境変数を扱う $env モジュールが便利だったので詳しく紹介します。

Vite の環境変数

SvelteKit は Vite のプロジェクトなので、Vite の環境変数の仕組みを使用することが可能です。Vite の環境変数については こちらの記事 で詳しく解説していますのでよかったらご覧ください。基本的に SvelteKit の環境変数の仕組みのほうが高機能なので、Vite の環境変数ではなく、SvelteKit の環境変数を使うことをお勧めします。なお、SvelteKit ではなく、Svelte だけで SPA を作っている場合は、Vite の環境変数を使うしかないので、繰り返しになりますが こちらの記事 をご参照ください。

SvelteKit の $env モジュール

SvelteKit では Vite の環境変数をラップして以下 4 種類のモジュールとして提供されています。

  • $env/dynamic/private
  • $env/dynamic/public
  • $env/static/private
  • $env/static/public

違いは dynamic or staticprivate or public とです。まずは privatepublic の違いから見ていきます。

private or public

公式ドキュメントでは private

変数名が config.kit.env.publicPrefix で始まらない、かつ、config.kit.env.privatePrefix で始まる変数のみを含んでいます (設定されている場合に限る)。
このモジュールをクライアントサイドコードにインポートすることはできません。

とあり、public

config.kit.env.publicPrefix (デフォルトは PUBLIC_) で始まる変数のみを含んでおり、クライアントサイドのコードに安全に公開することができます。

と記載されています。

まずわかる違いはクライアントサイドに公開されるかどうかです。そしてそれをコントロールするのが config.kit.env.privatePrefixconfig.kit.env.publicPrefix のようです。

publicPrefix?: string;

DEFAULT "PUBLIC_"
クライアントサイドコードに公開されても安全な環境変数に付与される接頭辞です。Vite の環境変数ハンドリングを使用する場合は、別途 Vite の envPrefix を設定する必要があることにご注意ください - ただし、通常この機能を使う必要はありません。

デフォルトでは PUBLIC_ プレフィクスが付いている環境変数が public として扱えるようです。

また Vite の環境変数ハンドリングについて触れられていますが、SvelteKit の $env モジュールと Vite の環境変数ハンドリング (import.meta.env) を併用する場合はプレフィクスの設定方法がそれぞれ異なる注意です。ただ公式ドキュメントに記載の通り両方使う必要があるユースケースはあまり思い浮かびません。最初 Svelte のみで SPA を作っていて、Vite の環境変数を使っていて、その後 SvelteKit に移行したけどフロント部分手を入れたくないのでそのまま Vite の環境変数使っているみたいなケースぐらいでしょうか…。

privatePrefix?: string;

DEFAULT ""
A prefix that signals that an environment variable is unsafe to expose to client-side code. Environment variables matching neither the public nor the private prefix will be discarded completely.

  • Configuration • Docs • SvelteKit デフォルトでプレフィクス無しの環境変数が private として扱えます。Vite は SPA のようなフロントエンドの開発・ビルドを前提としているのでクライアントに公開する環境変数にのみプレフィクスがありましたが、SvelteKit は SSR でサーバーサイドもあるので明示的にプレフィクスを付けるオプションを用意しているのかもしれません。(ただしデフォルトはプレフィクス無し)

dynamic or static

dynamic

このモジュールは、実行中のプラットフォームで定義された、実行時の環境変数へのアクセスを提供します。例えば、adapter-node を使用している場合 (または vite preview を実行中の場合)、これは process.env と同じです。

  • Modules • Docs • SvelteKit とある通り、基本的にプラットフォームの環境変数 (Windows であれば Windows の環境変数) を提供するモジュールです。

試しに以下のようなサーバー処理を用意し、$env/dynamic/private から env をインポートし、console.log() で出力してみます。

/src/+page.server.ts
import type { PageServerLoad } from './$types.js';
import { env } from '$env/dynamic/private'

export const load: PageServerLoad = () => {
  console.log(env)
	return {
		value: "test"
	};
};

ターミナルで npm run dev を実行し、開発サーバーを起動します。ブラウザでアクセス後にサーバー側のターミナルを見てみると、OS の環境変数が出力されていると思います。

実行中のプラットフォームの環境変数が注入されるので、試せていませんが例えば AWS Lambda で動かす場合、AWS Lambda の環境変数を注入したりすることが可能だと思われます。

開発サーバーやデフォルトのビルドでは node サーバーを使用しているので、プラットフォームの環境変数以外に、.env ファイルから独自の環境変数を定義する場合は、static を使う方が良さそうです。

開発中(In dev)は、$env/dynamic には常に .env からの環境変数が含まれます。本番(In prod)では、この動作は使用する adapter に依存します。

static

.env ファイルや process.env から Vite が読み込む 環境変数です。(中略) このモジュールからエクスポートされた値はビルド時に静的に注入され、デッドコードの排除などの最適化が可能になります。

あとコーディングレベルでの大きな違いとして、static はモジュール $env/static/private$env/static/public 以下の直接プロパティとして各環境変数が定義されますが、dynamic はモジュール $env/dynamic/private$env/dynamic/public 以下に env というプロパティがあり、その env 以下に各環境変数が定義されています。

static の場合、

import { PUBLIC_API_URL } from '$env/static/public';

のように直接環境変数毎に分割代入してインポートできますが、dynamic の場合、

import { env } from '$env/dynamic/private';

console.log(env.Path);

のように env を分割代入でインポートした上で、env のプロパティとして各環境変数にアクセスします。

.env ファイルの場所

SvelteKit の $env モジュールに読み込む .env ファイルの場所は Vite の設定とは別に設定する必要があります。また、 Vite の環境変数ハンドリングを使用しない場合は Vite の設定は必要ありません。

SvelteKit の .env ファイルの場所の指定は svelte.config.js で行います。

dir?: string;

DEFAULT "."
.env ファイルを探すディレクトリです。

以下のようにプロジェクトルート直下の env ディレクトリに変更してみます。また private or public で紹介した環境変数のプレフィクスもここで設定することができます。ここでは試しにクライアントに公開可能な環境変数には DANGER_ とプレフィクスを付けてみます。これで DB のパスワードを公開してしまうような事故は無くなるでしょう。

/svelte.config.js
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';

/** @type {import('@sveltejs/kit').Config} */
const config = {
	preprocess: vitePreprocess(),

	kit: {
		adapter: adapter(),
		env: {
			dir: './env', // 追加
			publicPrefix: 'DANGER_',  // 追加
		}
	}
};

環境変数の TypeScript 型補完

SvelteKit で TypeScript で開発するなら Vite の環境変数ハンドリングではなく SvelteKit の $env モジュールを使用したほうがよい最大の理由は TypeScript の型補完です。Vite の環境変数では独自の環境変数については自分で型定義をする必要がありました。SvelteKit はこれも自動でやってくれます。

試しに以下のような .env を用意します。.env ファイルのロケーションや環境変数のプレフィクスは前節での変更を行った前提です。デフォルトの場合は .env ファイルはプロジェクトルートに配置し、環境変数のプレフィクスも PUBLIC_ にしてください。

/env/.env
DANGER_TEXT=TEST

一度ターミナルで npm run dev を実行した上で、./svelte-kit/ambient.d.ts ファイルを見てみてください。$env/dynamic/public$env/static/public 内にしっかり DANGER_TEXT: string という型定義がされていることがわかると思います。また $env/dynamic/private 内には OS の環境変数の型も定義されています。

このように全て自動で型定義をしてくれるのでかなり便利です。SvelteKit は以前紹介した Generated Type 始め、TypeScript 対応がしっかりされていて使いやすいです。

モードの切り替え

Vite の環境変数の仕組みで、独自モードの追加やモードによる環境変数の切り替えがそのまま使えます。詳しくは こちらの記事 をご参照ください。

あとがき

SvelteKit の $env モジュールを使って環境変数を扱う方法を紹介しました。Svelte は全般的に TypeScript サポートが手厚く便利だなと思いました。