angularは環境変数をenvironment.tsおよびenvironment.prod.tsに定義することでビルド時に読み込み先を振り分けてますが、これだと環境変数をベタ書きしないといけないため、publicリポジトリで管理するような場合にAPI Keyやシークレット等、他の人に見られたらまずいものがある場合にどうしようとなってしまいます。。
いろいろ調べたら、どうにかできたのでその方法を残しておきます。
解決策概要
- ローカル環境では.envをenvironment.tsにマージ
- .envはGit管理に追加しない
- 本番環境(GitHub Pages)ではActions Secretsで定義した変数をenvironment.tsにマージ
これで他の人から見えない変数定義が可能となります
対応
準備
# ts-nodeインストール(後述のバッチ実行用)
npm install --save-dev ts-node
# dotenvインストール
npm install --save-dev dotenv
.env作成
今回はAPI_KEYを隠したい想定で作成します
API_KEY=test
environmentの修正
- environment.tsを直接書き換えても良いですが、リスクがあるので動的に書き換える部分は外出しします
- dynamic.tsに出力する想定でenvironment.tsおよびprod.tsを修正します
- 後述のdynamic.tsへの書き込みにより、.envとマージされることになります
src/environments/environment.ts
import { dynamic } from './dynamic';
export const environment = {
production: false,
dynamic,
};
environmentの書き換えバッチ作成
こいつで.envの内容をdynamic.tsに書き込んでいきます
config/write-env.ts
import * as fs from 'fs';
import { join } from 'path';
import { config } from 'dotenv';
const dotenv = config()?.parsed;
// 一応システムの環境変数でも動かせるようにデフォルトはシステムの環境変数にする
const env = {
apiKey: process.env.API_KEY,
};
// .envが読めた場合は、.envの内容を設定
if (dotenv) {
env.apiKey = dotenv.API_KEY;
}
// dynamic.tsに書き込み
const contents = 'export const dynamic = ' + JSON.stringify(env);
fs.writeFileSync(
join(__dirname, '../src/environments/dynamic.ts'),
contents
);
.gitignore修正
せっかく見えないようにしたので、.envとdynamic.tsはGit管理対象外にします
.env
src/environment/dynamic.ts
package.jsonの修正
-
write-env
を追加し、上記で追加したバッチを呼び出します - startとbuildで、最初にwrite-envを呼ぶようにします
package.json
"scripts": {
"ng": "ng",
"start": "npm run write-env && ng serve --port 8000",
"build": "npm run write-env && ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"write-env": "ts-node -O '{\"module\": \"commonjs\"}' ./config/write-env.ts"
},
ローカル環境はこれでOKです!
GitHub Pagesへのデプロイ
Actions Secretの追加
- GitHubにて「Settings -> Secrets」からActions Secretを登録します
- 今回はAPI_KEYを追加します
デプロイ設定
- 基本の設定は以前に書いた以下の記事の内容となります
- ビルド前に.env作成ジョブを追加します
-
${{ secrets.API_KEY }}
でActions Secretに追加した値を参照できます -
echo API_KEY=$API_KEY >> .env
で.envに出力します
-
github/workflows/deploy.yml
name: Node CI
on:
push:
branches: main
jobs:
build:
runs-on: ubuntu-18.04
strategy:
matrix:
node-version: [12.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: create .env
env:
API_KEY: ${{ secrets.API_KEY }}
run: |
echo API_KEY=$API_KEY >> .env
- name: npm install, build, and test
run: |
npm install
npm run build --if-present -- --prod
npm test -- --watch=false --browsers=ChromeHeadless
cp -a dist/{project name}/index.html dist/{project name}/404.html
env:
CI: true
- name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@3.7.1
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BRANCH: gh-pages
FOLDER: dist/{project name}
CLEAN: true
これでmainブランチにプッシュしたときに自動でGitHub Pagesにデプロイされます!
最後に
結構長いこと気になってたことが解決できました!
これで安心してpublicリポジトリで公開できますね^^