STICKY NOTES

11ty で env をデフォルト値対応させたり便利に使えるようにする

2023-03-08
2023-03-08
yagasuke
eleven

SUMMARY

Laravel みたいな感じで env() を使いたかったので、node の dotenv をラップして、デフォルト値や bool 型への対応を行う。

環境

  • 2019 の Intel Mac
  • macOS 13.2 (22D49)
  • node v18.14.0(brew でインストール)
  • npm 9.3.1(brew でインストール)
  • @11ty/eleventy: ^2.0.0(package.json)

dotenv の導入

dotenv を入れる必要があるのかよく分かってないけど、.env 使いたかったら入れるみたいなのを読んだので入れる。
公式サイトに記載されている手順でインストールする。

npm install --save dotenv

導入後の package.json の dependencies。

"dependencies": {
  "@11ty/eleventy": "^2.0.0",
  "autoprefixer": "^10.4.13",
  "dotenv": "^16.0.3",
  "postcss": "^8.4.21",
  "postcss-cli": "^10.1.0",
  "tailwindcss": "^3.2.6"
}

ルートディレクトリに .env ファイルを作って key=value 形式で記載すると、JS 内で値が取得できるようになる。
.env はコミットしないので、API キーなどを記述しても公開されなくなるので便利。
コード内で使用している key がわからないと不便なので、.env と同じ階層に env.example を作成して key="" のように key だけ定義しておく。(こっちはコミットする)

# default timezone
TZ=utc

# tokens
STRAPI_API_TOKEN=""

みたいな感じ。

ラッパの作成

11ty の場合、eleventy.config.js による事前のビルドでの使用と、njk の中で Shortcode として使う場合の 2 パターンがあるのでそれぞれ実装する。

eleventy.config.js 用の実装

resources/js/env.js


require('dotenv').config();

function env(key, defaultValue = null)
{
  let value = process.env[key];
  if (['true', 'false'].includes(typeof value === 'string' ? value.toLowerCase() : '')) {
    value = value === 'true';
  }
  return value ?? defaultValue;
}

module.exports = env;

process.env[key] が .env から読み込んでいるところで、指定された key の value が取得できる。

.env から読み込んだ value は、bool 型で記載しても文字列として渡ってくる。
そのため、if (!env('xxx')) {} のような判定をすると true となってしまうので、.env に true とか True とか TRUE みたいに記載されたら bool 型の true になるよう変換する。
上記コードの if 文の判定のところが変換処理になるが、value に対して string 型判定し、文字列の場合 toLowerCase() で小文字にしてから true か false を確認。
一致した場合は value に bool 型として入れ直している。

また、key が見つからない場合にデフォルト値が欲しかったりする場合もあるので、引数に null を初期値とした defaultValue を定義。
.env から value が取れなかった場合は、defaultValue を応答するようにしている。

デフォルト値使いたい場合は、env('xxx', 0) のように呼び出す。

11ty の Shortcode 用の実装

こちらは上記の env.js を読み込んで定義してあげるだけ。

resources/js/11ty-shortcode.js


const prjRoot = process.env.PWD; // プロセス実行元の絶対パス
const jsRoot = `${prjRoot}/resources/js`;

const env = require(`${jsRoot}/env`);

var Shortcodes = Shortcodes || {};
(function (_ns) {

// ...

_ns.env = (key, defaultValue = null) => {
  return env(key, defaultValue);
};

// ...

})(Shortcodes)

module.exports = Shortcodes;

のように実装し、eleventy.config.js で Shortcode として使えるよう登録する。

eleventy.config.js


const shortcodes = require('./resources/js/11ty-shortcodes');

module.exports = (eleventyConfig) => {
  // ...

  setupShortcodes(eleventyConfig);

  // ...
};

function setupShortcodes(eleventyConfig) {
  // ...

  eleventyConfig.addShortcode('_env', shortcodes.env);

  // ...
}

これで .njk などのテンプレートから


{% _env, 'xxx' %}

という形で .env の値を取得できる。

まとめのような感想

  • Laravel で .env というものを知って、11ty 触って dotenv というものがあることを知ってなんとなく仕組みを理解
  • 簡単に外部定義を読み込めてとても便利
  • github actions などでも、secrets に登録した key=value を .env に変換してあげれば CI 環境でも使える

github の件はもっと良い方法があるかもだけど、現状知らないので actions のスクリプトで .env に変換して読み込ませてる。