0
1

More than 1 year has passed since last update.

環境変数周りの改善

Last updated at Posted at 2023-08-19

はじめに

Web系のプロジェクトで開発をしていると.env .env.development. .env.testなどにシークレット情報や、環境ごとに異なる設定を書くことが多い

環境変数からデータを読み込めために(言語やフレームワークに関わらず)おおよそ下記のようなファイルを用意する

1 機密情報を格納するためのファイル(.env)の準備

.env
API_KEY='xs9djq4iq'
DEBUG='TRUE'

2 当然.gitignoreで.envをバージョン管理から除外

.gitignore
.env

3 バージョン管理から除外すると.envにどのような値が存在するかの管理が難しくなるので.env.sampleを用意

.env.sample
API_KEY='CHANGE ME'
DEBUG='true'

4 環境変数を取得するコードを書く(下記はnode.jsの場合)

env.ts
const API_KEY: string  = process.env.API_KEY
const DEBUG  : boolean = process.env.DEBUG === true

.envに値を追加するとき

.envenv.ts.env.sampleの3箇所に同じような記述をする必要がある。

.env
API_KEY='xs9djq4iq'
DEBUG='TRUE'
NEW_ENV='xxx'
env.ts
const API_KEY: string  = process.env.API_KEY
const DEBUG  : boolean = process.env.DEBUG === true
const NEW_ENV: string  = xxx
.env.sample
API_KEY='CHANGE ME'
DEBUG='true'
NEW_ENV='Change ME'

辛い点1 タイポ

↓こういうタイポが起きる(ことがある)

.env.sample
NEW_EMV='Change ME'

環境変数周りは、エディターがタイポを検出するのが難しいので、目検になる。辛い。

辛い点2 煩わしい

3箇所に似たような記述したくない。

作ったもの1

.envからTypescriptのコードを自動生成する→煩わしさやタイポリスクが減る

Usage

.env
# this is a comment
str="value"
nospace=nospace

# a few blank lines

is_true=true
is_false=false
num=123
zero=0
str_start_zero=0123
$ deno run cli -A -i 'path to env file' -o 'path to output file' -t 'deno or node'
output.ts
/************************************
* This file is generated by deno-env-codegen
************************************/

const getEnv = (key: string) => {
  const val = process.env[key];
  if (val === undefined) {
    throw new Error(`Environment variable "\${key}" is not defined`);
  }
  return val;
};

const toNumber = (val: string) => {
  return Number(val);
};

const toBoolean = (val: string) => {
  return val === "true";
};

// this is a comment
export const str = getEnv("str");
export const nospace = getEnv("nospace");

// a few blank lines

export const is_true = toBoolean(getEnv("is_true"));
export const is_false = toBoolean(getEnv("is_false"));
export const num = toNumber(getEnv("num"));
export const zejro = toNumber(getEnv("zero"));
export const str_start_zero = getEnv("str_start_zero");

作ったもの2

.env.env.sampleのdiffを表示する→タイポミスの防止& .env.env.sampleの乖離防止

.env
env='env'
env2='env2'
env3='env3'
env_and_sample='env_and_sample-in-env'
env_and_sample2='env_and_sample-in-env2'
.env.sample
sample='sample'
sample2='sample2'
sample3='sample3'
env_and_sample='env-and-sample-in-sample'
env_and_sample2='env_and_sample-in-sample2'
$ deno run --allow-read=. cli.ts .env .env.sample
Keys that exist in .env.sample but not in .env: sample, sample2, sample3
Keys that exist in .env but not in .env.sample: env, env2, env3

課題

  • .envにはあるが、コード中には必要ない値もenv.tsに生成されてしまう。
  • .env.env.sampleの整合性チェックは、結局のところ人間の目に頼ってしまっている
  • cli形式でパッと読み込める形でパッケージ化していない
  • 整合性チェック弱い※

※整合性チェックが弱い件について

「作ったもの2」ではtsのコードを自動生成するという方法を取ったけど、zodみたいなものを利用したスキーマ定義を.envを自動生成する形の方が安全で使いやすいかもしれない。(たとえば、「作ったもの2」だと DEBUG=tureみたいな明らかなタイポでさえも検知できないsrc/env.tsではbooleanのfalseになってしまう)

例)

$ env-gen -i '.env' -o './src/env.ts'
.env
PORT=8080
HOST=localhost
NODE_ENV=development
DEBUG=true
src/env.ts
import z from 'zod'
import process from 'process'

export type Env = typeof env;
export const env = z.object({
    PORT: z.number(),
    HOST: z.string(),
    NODE_ENV: z.enum(["development", "production"]).default('development']),
    DEBUG: z.boolean(),
}).parse(process.env);

みたいに使えた方が安全でメンテナンスしやすいかもしれない(開発の要件にもよる)

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1