/home/by-natures/dev*

データ界隈で働くエンジニアとしての技術的なメモと、たまに普通の日記。

2023/06/15 Webアプリ開発中: Create React App への環境変数の渡し方

1ヶ月近くブログ更新できていなかったのですが、ここしばらくは一からWebアプリを作ってみようと思い立って業務が終わってからずっと開発をしていました。ようやく最低限の機能開発と、ローカルとAWSでの差異を加味した環境構築が終わったのでブログにまとめてみます。

作りたいのは簡単な体調管理システムで、睡眠記録、その日行ったこと、気分や体調などを記録することで傾向を確認したり、ある程度データが溜まったら機械学習をさせて特徴量の分析をさせたいと思っています。武井壮さんが Youtube で解説されているようなものを想定しています:

武井壮の体調管理法その1 - YouTube

日時から天気や気圧情報なんかも外部APIを使ってデータを追加することもできそうです。

データの性質的に個人情報に該当しますし、健康情報という意味では要配慮個人情報にも該当する可能性があるかな…と思い、一般公開は予定していません。

ごく簡単ですが開発の最初にER図でどういうデータを記録しようかを検討しました:

体調管理システムのER図

以下の内容を学ぶことを裏目標としています:

  • 一からのWebアプリ開発(Node.js + React)
  • Docker でコンテナ化し、AWS ECS 上でサービス稼働させる
  • AWS は Terraform で構成管理
  • ローカル、AWSでどちらも動くように環境差異を吸収する

どれも業務で使ったことはあるのですが、すでに環境が出来上がってから参画することが多かったので、一から全部自分で構築するのは実は初めてです。特にフロントエンドの開発は何年もやっていないので本当に久しぶりです。

ChatGPT や GithubCopilot も活用しています。まだ業務で利用する許可が得られていない企業も多いと思いますが、特に環境構築初期に曖昧な疑問を ChatGPT にぶつけられるのが非常に助かりました。生成されたコードは割と間違っていることも多いのですが、どういったライブラリがあるかを知って公式ドキュメントを辿るきっかけにしたり、実装方針のあたりをつけるには十分でした。

ハマったところを書き出してみます。今日は環境変数について。

コンテナに環境変数を渡す

環境差異を吸収するために、ローカルでは localhost, AWS 上では ELB のドメイン名上で動くようにしたかったのですが、Create React App はビルド時に環境変数を埋め込んでしまうため、動作環境の環境変数を読み込んでくれません。

create-react-app.dev

The environment variables are embedded during the build time. Since Create React App produces a static HTML/CSS/JS bundle, it can’t possibly read them at runtime. To read them at runtime, you would need to load HTML into memory on the server and replace placeholders in runtime, as described here. Alternatively you can rebuild the app on the server anytime you change them.

この記載の通り、ECS のタスク定義の environment は読みこみませんでした。最適解かは分かりませんが、docker-compose.yml に args として環境変数を渡し、Dockerfile でそれをENV に与えることでうまくイメージ構築ができました:

version: '3'
services:
  my-server:
    ...
  my-client:
    image: ${REPO_NAME}/my_client:${TAG}
    build:
      context: ./client
      dockerfile: Dockerfile
      args:
        - "REACT_APP_MY_SERVER_URL=${REACT_APP_MY_SERVER_URL}"
    depends_on: 
      - my-server
    ports:
      - 80:80
FROM node:18.16-slim as build-deps

ARG REACT_APP_MY_SERVER_URL
ENV REACT_APP_MY_SERVER_URL=${REACT_APP_MY_SERVER_URL}

ビルドで読み込む環境変数を明示的に分けることでそれぞれの環境に適したイメージが構築でき、 process.env.REACT_APP_LILYCHUM_SERVER_URL で環境変数を参照できます:

$ docker-compose --env-file ./.env_local build
$ docker-compose --env-file ./.env_aws build