画像の読み込みに失敗したときに代替画像を表示する [JavaScript/React]

まずは JavaScript で実装してみます。

<img id="image" src="https://" />
<script>
  const imgEl = document.getElementById("image");
  imgEl.onerror = () => {
    imgEl.onerror = null;
    imgEl.src = "https://placekitten.com/200/200";
  };
</script>

画像の読み込みに失敗したときに onerror が実行されます。

onerror に null を詰めているのは、読み込み失敗時に表示する画像の読み込みに失敗したときに無限ループになってしまうのを防ぐためです。

React でコンポーネントにしてみます。

codesandbox.io

追記:Ref 使わなくても onError={(e) => (e.target.src = "https://placekitten.com/200/200")} で実現できる

GitHub Pages に Google Domains で購入した独自ドメインを設定する

GitHub Pages のドキュメントを読みながら独自ドメインの設定をするだけの話なのですが、この記事では初心者向けにもう少し詳しく解説します。

GitHub Pages サイトのカスタムドメインを設定する - GitHub Docs

用語

記事の中で頻繁に出てくる用語を先に説明しておきます。知っている方は読み飛ばしてください。

Apex ドメイン (ルートドメイン)

例えば Google Domains で "moyashi.com" を購入したとします。この場合、"moyashi.com" が Apex ドメインになります。

サブドメイン

Apex ドメインをさらに分割したものです。

"moyashi.com" が Apex ドメインの場合、 "www.moyashi.com" や "books.moyashi.com" などがサブドメインになります。

"○○.moyashi.com" の "○○" の部分はユーザーが任意の名前を付けることができます。

Aレコード

ドメインIPv4アドレス の関連付けを定義するレコードです。

CNAME

Aレコードで定義されているドメイン名と別名を指定するためのレコードです。

DNSの名前解決では、CNAMEリソースレコードが見つかった場合、ドメイン名を正式名に置き換えて名前解決を継続します。

独自ドメインを設定する

Google Domains でドメインを購入した前提で話を進めます。

Apexドメイン を登録する場合と サブドメイン を登録する場合で手順が異なるので、自分が登録したいドメインの手順を参考にしてください。

Apex ドメインを設定する

1. Google Domains の管理画面で「マイドメイン」から購入したドメインを選択します。

2.「DNS」を選択し、画面を下にスクロールして"カスタム リソース レコード"の設定をします。

  • タイプを 「A」に切り替えます。
  • 名前を「@」にします。
  • 以下の IPアドレスを登録します。ネームサーバーの IPアドレス は変更される可能性があるのでドキュメントを参照してください。
185.199.108.153
185.199.109.153
185.199.110.153
185.199.111.153

f:id:dev-moyashi:20210110221138p:plain

3. DNS レコードが正しく設定されたことを確認する。

dig コマンドを使って DNS レコードが正しく設定されたことを確認しましょう。大体10分ぐらいで反映されます。

$ dig <your domain> +noall +answer

4. GitHubで、サイトのリポジトリにアクセスします。

5.「Settings」を選択し、"Custom domain"の下で、Apex ドメインを入力して「Save」を押します。

f:id:dev-moyashi:20210110221743p:plain

サブドメインを設定する

1. Google Domains の管理画面で「マイドメイン」から購入したドメインを選択します。

2.「DNS」を選択し、画面を下にスクロールして"カスタム リソース レコード"の設定をします。

  • タイプを「CNAME」に切り替えます。
  • 名前にサブドメインを入力します。(今回だと「www」)
  • データに公開中の GitHub Pages のドメインを入力します。(例:kuroppe1819.github.io)

f:id:dev-moyashi:20210110214602p:plain

以上の設定が完了したら追加ボタンを押します。

3. GitHubで、サイトのリポジトリにアクセスします。

4.「Settings」を選択し、"Custom domain"の下で、サブドメインを入力して「Save」を押します。

f:id:dev-moyashi:20210110215854p:plain

HTTPS

HTTPS 暗号化をしたい場合は、「Enforce HTTPS」を有効にしてください。

f:id:dev-moyashi:20210110220146p:plain

CNAME の管理

Custom Domain の設定をすると自動的にCNAMEファイルが生成されます。ローカル環境でコードを修正してgit pushするとCNAMEファイルが削除されてページが 404 を返すようになるのでコミット差分に含めておきましょう。

参考

LilyGo T-Wristband にQRコードを表示してみる

前回の記事の続きです。

Hello world 表示させるだけで終わってしまうのは勿体ないと感じたので TwitterGitHubQR コードを表示してみました。

勉強会に参加すると名刺交換することがあると思いますが、僕は不必要に名刺をバラ撒きたくない人なので、腕に表示した QR コードを共有して名刺代わりに使いたいと思い制作しました。

自分のポートフォリオがある人はそのサイトへの QR コードを表示してみると見てもらえる機会が増えるかもしれません。

ではさっそく作り方の解説をしていきます。

T-wristband に画像を表示する方法

まず画面(LCD)に画像を表示させる方法を調べます。

T-wristbandに使用されているのは ST7735 という TFT LCD です。これは TFT_eSPI というライブラリを使用することで簡単に画像を表示できます。

TFT_eSPI には pushImage 関数があり、この関数の第5引数に画像のHEX値の配列を渡すと、任意の画像を表示させることができます。

/***************************************************************************************
** Function name:           pushImage
** Description:             plot 16 bit colour sprite or image onto TFT
***************************************************************************************/
void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data) {
...

画像の表示方法が分かったので、次に画面の解像度を調べます。 TFT_eSPIwidthheight を実行すると、横幅 80px、縦幅 160px であることが確認できます。

TFT_eSPI tft = TFT_eSPI();
tft.width(); // 80px
tft.height(); // 160px

正方形の画像を画面に2つ表示させたいときは、サイズが80×80の画像を2つ用意すればよいことが分かります。

16bitカラー画像のpixel配列を作る

pushImage 関数の第5引数が uint16_t のポインタになっているため、16bitカラー画像のpixel配列を用意します。

大抵の画像は 16bit (65,536色)以上の色で表現されているため、一度減色してからpixel配列に変換します。僕は LCD Image Converter というソフトウェアを使って変換しました。

変換手順

  1. LCD Image Converter を起動して、Image > Import で変換したい画像を選択します。

  2. Options > Conversion > Imageタブを選択して、設定を Preset: Color R5G6B5Block size: 16bit に変更します。

  3. Show Preview を選択すると 16bitカラー画像のpixel配列が表示されます。

表示されたHEX値をプログラムにコピペします。

QRコードを表示する

やることをざっくりまとめると以下になります。

  1. 80x80の画像を用意する

  2. 画像を16bitカラー画像のpixel配列に変換する

  3. pushImage 関数の第5引数に配列を渡す

表示したものがこちらです。

気軽に外出できるようになったら使ってみようと思います。

今回実装したコード

github.com

プログラミング可能なスマートウォッチ「LilyGO T-Wristband」を手に入れたので Hello world を表示してみる。

プログラミング可能なスマートォッチが販売されたということで何も考えずに即買いしました。

LilyGO T-Wristband

https://pt.aliexpress.com/item/4000527495064.htmlpt.aliexpress.com

2020年1月に AliExpress で購入したのですが、某ウイルスの影響なのか届くのに4ヶ月もかかりました。その後自身のモチベーションの問題で封を開けるのに2ヶ月かかりました。

やっと重い腰を上げてプログラミングしようとしたところ、技適が通っていないことが発覚して心が折れました。でもせっかく購入したので Hello world を表示するところまでやってみようと思います。

※2020年8月10日現在、総務省電波利用ホームページの検索結果 で LilyGO T-Wristband の技適が通っていないことを確認

開発環境

T-Wristband を PCに接続する

まずは以下の動画を見て正しい分解の仕方を学びましょう。

www.youtube.com

環境構築

基本的に公式リポジトリの README の流れに従えばプログラムを書き込むことができるようになります。

僕が購入したのは、9自由度の慣性計測装置(3軸の加速度センサ、3軸のジャイロセンサ、3軸の磁力センサ)が MPU9250 のものでした。

新しいものは LSM9DS1 が搭載されているようです。参照する README が異なるのでご注意ください。

今回は MPU9250 搭載の T-Wristband の README を参照しています。

PlatformIO でプロジェクトを作成する場合は、新規プロジェクト作成画面の Board で Espressif ESP32 Dev Module を選択してください。

各種ライブラリのインストールも PlatformIO で行います。画面に文字列を表示するために TFT_eSPI ライブラリが必要なのでインストールします。

PIO Home から TFT_eSPI をインストールする

画面に Hello world を表示する

Example を参考にして、画面に文字列を表示するプログラムを書きます。技適が通っていないので Wifi 関連のコードは必ず削除してください。

文字列を表示する機能だけを備えたプロジェクトがこちらになります。

github.com

あとはプログラムを書き込むだけです。画面に文字が表示されたら成功です。

追記:QRコードを表示してみる

Hello world を表示するだけでは物足りなかったので GitHubTwitterQRコードを表示してみました。

dev-moyashi.hatenablog.com

Rでパッケージインストール用のディレクトリが作成できないときの対処方法

Rでパッケージをインストールするときは、まず保存先のディレクトリを作成する必要があります。このディレクトリの作成に失敗するとパッケージのインストールを開始することができません。

保存先のディレクトリは作成できているけど、何故かインストールに失敗してしまう...という方はこちらの記事をご覧下さい。

dev-moyashi.hatenablog.com

日本語のディレクトリ、ユーザー名を使用しない

ファイルパスやディレクトリに日本語が含まれている場合、文字化けによってディレクトリが作成できない場合があります。

「Create Package Library」のダイアログに /??/ という表記があれば文字化けしている可能性が高いです。

ユーザー名が文字化けしている場合は、英語のユーザーを新しく作成して「Install Package」を選択してください。

Windows でユーザーを新しく作成する方法はこちらになります。

管理者権限で R Studio を実行する

  1. R Studio を右クリック
  2. 管理者として実行をクリック

f:id:dev-moyashi:20200710225040p:plain
管理者権限で R Studio を実行する

管理者権限で実行すると、インストール先のディレクトリにアクセス可能になります。

この状態で「Install Packages」を選択すると、パッケージのインストールが始まります。

サイボウズに新卒入社してkintone開発チームに配属されてから1年経ったのでふりかえる

こんにちは もやし丸 です。2019年にサイボウズに新卒入社して、kintone開発チームでWebエンジニアとして働いています。

kintone開発チームに配属されてから1年経過したのでふりかえりを書きました。

自分が配属される時期に中途入社された sakito さん、 Nokogiri さん、あおいさんが入社1年をふりかえるブログを書いてて、それを見て触発された感じです。

https://note.com/mki_skt/n/nd11c9fe2ec3fnote.com

nkgr.hatenablog.com

blux.hatenablog.com

shisama_さんも1年ふりかえりブログを書いていたので追記しました:

shisama.hatenablog.com

採用に関する仕事に携わったときに「入社した理由」「入社までにやっていたこと」「入社後どんな仕事をしているのか」をよく質問されるので、それについても触れながらふりかえろうと思います。

目次

入社の経緯

就活中はチームワークの向上に繋がるツールを開発している会社に興味があって、チャットアプリやグループウェアを提供しているところを見ていました。

学生時代にチームでアプリ開発をすることが何度かあったのですが、イケてるツールを導入するだけではチームをうまく回すことができなかったため、ツールの使い方だったり、カスタマーサポートにも力を入れている会社じゃないとチームワークの向上には繋がらない思っていました。

世の中のチームワークを高めることを目的にツールと文化を両方提供している会社を探していたところサイボウズ と出会い、企業理念から本気でチームワークを良くしていきたいということが伝わってきたので最終的にサイボウズ に入社することに決めました。

2017年度のサイボウズ のサマーインターンシップでモバイルコースに参加していたため、ある程度社内の雰囲気を理解していて、働くイメージができていたというのも入社を決めた理由の1つです。

cybozu.co.jp

内定時のスペック(2018年1月)

  • 地方の大学の電気系学科の学部3年生
  • 組み込み系の開発が多少できる
  • Pythonで簡単なスクリプトを書ける
  • Android/iOSの開発が多少できる(SNSアプリを2~3週間ぐらいで作れるぐらいの能力)
    • Android は Kotlin と JavaiOS は Swift4
    • MVC, MVP, MVVM パターンでアプリを作れる
    • 当時は RxKotlin と Databinding を使ったMVVMパターンのアプリを作成していた。

入社までにやっていたこと

Webのことを全然理解していない状態でWebサービスを提供している会社に就職するのは嫌だなあと思っていたので、研究と同時並行でWebの技術の勉強をしていました。

自分はIoT関連の研究をしていて、通信プロトコルの知識を必要とする機会が多かったので、通信周りの話から徐々に学習していきました。

書籍は マスタリングTCP/IP 入門編Real World HTTP Webを支える技術 を読んでました。

2018年の秋頃に Twitter で「Webサイトのリプレース作業を手伝ってくれない?」という話をもちかけられたため、この時期から本格的に HTML/CSS/JavaScript の勉強を始めました。

書籍は よくわかるHTML5+CSS3の教科書JavaScript本格入門徳丸本 を読んでいました。

ネットの教材は Codecademy というサイトを使ったり、ドットインストールを使って勉強していました。気が付いたら500本以上視聴していました。SQLSQLZOO というサイトで勉強しました。

入社してから

1年目

4~5月 (全体研修)

最初はビジネスの人と一緒に全体研修を受けました。

各部署がプロダクトとどのように関わっているのか把握しておくことは大事だし、どうせ数ヶ月後に知りたくなるだろうと考えていたので、2ヶ月間コード書けなくなることに対してそこまでつらい気持ちはありませんでした。

むしろ全体研修のおかげでビジネス側の同期と喋る機会が増えてよかったです。たぶんこの研修がなかったら僕は同期と一言も喋っていなかったと思います。

同期も先輩も優しい人ばかりで、仕事自体は楽しかったのですが、人は人と比較してしまう生き物。スーパーハイスペック人材しかいなかったので、毎日「もうだめだ...おしまいだ....。」と考えながら生きてました。人間性と能力の差に絶望しながら「なんで採用されたのかよくわからんなー」と茫然と考えながら出社する日々を過ごしていました。

また、社内で悪意のあるコミュニケーションをとってくる人が1人もいないことに動揺を隠しきれませんでした。人に優しい人しかいない空間は僕にとっては異常で、しばらくは何か裏があるんじゃないかと思って恐る恐る人と接していました。後に考えすぎだったことを知ります。

開発チーム以外の場所でも HRTの原則 を感じられるところがこの会社の本当にすごいところで、実際そういう文化があるおかげで他部署と連携しやすいんだろうなあと思っています。

note.com

6月 (エンジニア新人研修)

2019年度のエンジニア新人研修は、1週目に必須講義を行い、2週目から興味のある開発チームの仕事を体験するというものでした。

スケジュール

  • 5/27〜5/31(第1週)
    • 必修の講義や演習が中心
    • 空き時間はRFC精読や予習/復習
  • 6/3〜7/12(第2〜7週)
    • チーム体験と選択講義期間
    • 2週間で体験するチームを変えて、合計3チーム

研修の内容は毎年変化していて、2020年度はRFCを読んでHTTPサーバーを実装する研修が復活していました。2019年度は読むだけだったので今年の新人がちょっと羨ましいです。

講義資料のほとんどは Cybozu Inside Out にて公開されています。 blog.cybozu.io

僕は kintone開発チーム、モバイルチーム、生産性向上チームを体験しました。

kintone開発チームとモバイルチームでは kintone の機能実装を行いました。生産性向上チームでは、社内で使われているブラウザ拡張機能の修正/機能追加をしたり、ktlintの導入をしたりしていました。(本当はCI/CD 周りの仕事をしたかったが、僕が体験した週は優先度が低めだった)

チーム体験前は「スキルセット的にモバイルチーム以外の選択肢はないだろうなあ」と思っていたのですが、チーム体験をすることで「意外と他の部署でも仕事ができそうだぞ」ということが分かってきました。そこで、一度持っているスキルのことは忘れて、今後この会社の中でどういう仕事をやりたいのか考え直しました。

当時は"Webの技術に興味がある"、"kintone という製品のコアとなる部分にも積極的に携わっていきたい" という気持ちが強かったため、第1希望を kintone開発チーム にしました。

配属前に面談があったので、現状のスキルセットで仕事を進められるのか不安だという話をしたところ、「これから身に付ければいいよ」と言われてあっさり kintone開発チーム に決まりました。

(なぜかフォロワーが200人増えたツイート)

7月~9月 (つらい時期)

この時期が一番辛かったです。

kintoneはモブプログラミング(以下モブと呼ぶ)で開発が進められていて、"わからないところがあったら遠慮なくモブを止めて質問する"ということになっています。メンバーの認識を揃えることが属人化を防ぐことに繋がるし、メンバーの質問で考慮できていなかった部分を新たに発見できることもあるので、積極的に質問してほしい!という雰囲気を感じます。

blog.cybozu.io

そんなkintone開発チームのモブの中で、僕はほとんど発言できていませんでした。発言してもちょっとよくわからない日本語を話していました。

開発に使っているフレームワークプログラミング言語デザインパターン、kintoneのドメイン知識、仕事の進め方など、とにかく分からないことが多すぎて、僕は何が分からないのか分からない状態になっていました。

いくら質問しやすい環境にいても、わからない部分を言語化できなければ周りの人も何を教えてあげればいいのかわかりません。分からない部分を相手に伝えることができないもどかしさを感じながら開発する日々が続き、精神的につらいと感じることが増えていきました。

7月に開催されたモブプログラミングMeetupで登壇したときは一丁前のことを言ってましたが、実際のところ僕のモブの立ち回りはボロボロでした。

この頃、同じチームに配属された同期はチームの問題点を指摘して改善案を出してたり、社内のハッカソンで新しいプロジェクトを立ち上げていたりしました。その様子を見て自分の力の無さを痛感して落ち込んだし、何より1年後先輩方のようにバリバリ開発できるようになっている姿が全く想像できなくて完全に自信を失っていました。

10月~12月

モブの中で質問できるようにする

言語化する能力が低いということを受け入れ、どうやったらモブを止めて質問できるようになるのか考えてました。

モブの目的は認識を揃えることで、質問はそのための手段です。なので、僕以外の人に僕が分かっていないところを言語化してもらうことで認識を揃えてもいいはずだと考えました。

僕は自分で分からないところを言語化するということを一旦諦めました。そして、分かっていないところを指摘してもらうやり方に変えました。

モブでは「認識があっているか確認させてください。○○という認識であってますか?」ということをよく質問するようにしていました。この質問の仕方だと、認識が間違っている部分をメンバーに指摘してもらって、自分が理解できていない部分を明確にすることができるからです。

また、実装に関する質問を言語化するのもなかなか難しかったので、実装前に図を描いてメンバーに積極的に共有していました。図を描けば最悪"これ"とか"それ"でも伝わりますし、影響範囲が一目でわかるようになります。

こんな感じで間違っているところを教えてもらいやすいように工夫して、なんとか開発チームの中に溶け込んでいきました。

kintoneの開発に必要な最低限度のスキルを身に付ける

kintoneは フロントエンドが Closure Library(中身はJavaScript)、サーバーサイドが Java で書かれています。両方の実装が必要になるタスクは珍しくないため、どちらも実装できるようにしておく必要があります。

当時僕が所属していたチームでは、16時~18時を個人探究時間として使っていいことになっていたので、その時間を利用して kintone に必要な知識のキャッチアップをしていました。

実際にコードを書いた方がわかりやすいので、フロントエンド、サーバーサイドの両方の実装を必要とするインターン生用の課題を拾ってきて、実装しながら kintone の設計や処理の流れについて勉強してました。

社内の勉強会も活発で、この時期に css設計勉強会 と Effective Java勉強会 をやっていたので参加していました。

休日は プロトタイプチェーン、関数内の this が指すもの、変数の巻き上げ、イベントループの仕組み....etc など、 JavaScript の言語仕様について調べていました。

焦らない

同期と一緒に登った赤城山の写真

とにかく焦っていました。

仕事ができるようになるまでの道のりがあまりにも遠く、今後どう立ち回っていけばいいのか考えすぎて眠れない日もありました。

そんなときに同期から登山に誘われました。

山の麓から頂上を見たとき、その道のりはあまりにも遠く見えました。でも、方向を間違えずにペース配分を考えながら進むと、気が付いたら頂上に辿り着いていました。

理想の状態に辿り着きたかったら方向性とペース配分が大事。山がそう教えてくれたような気がします。

家に帰ってきたときには、すでに焦る気持ちは消えていました。

1月~3月 (兼務してた時期)

kintone の新規機能を React + TypeScript で実装するプロジェクトが始まりそうな機運を感じていて、自分もこのプロジェクトに参加したかったので勉強を始めました。

社内で利用されているブラウザ拡張機能を TypeScript に置き換え、ポップアップ画面を React を使って再実装したりしていました。

ただ、趣味開発の時間をこれまで以上に確保することに限界を感じていたので、仕事で React を書く決意をしました。

ちょうど .com共通管理画面 を React + TypeScript で書き換えるプロジェクトが進行中だったので、思い切って兼務してもいいかPMに聞いてみたところ、あっさり承認されたので週1で兼務することになりました。そのため、週4日kintone開発、週1日.com共通管理画面のリプレース という働き方をするようになりました。

他には有志メンバーで サーバーサイドのテストコードの改善(hamcrest → AsserJ移行) を進めたり、Pythonで書かれた開発用の便利ツールの修正をしていました。

2年目

4月~6月 (1人で開発してた時期)

kintone開発 と .com共通管理画面のリプレース作業 を切り替えながらの開発が負担になっていました。

リプレース作業の次の日に1日分のkintone開発の進捗を把握してモブに参加するのはなかなか大変で、仕事の内容を思い出す時間のことも考えると無駄な時間が多いと感じていました。

色々と悩んだ結果、一度 kintoneの新規機能開発 をやめて .com共通管理のリプレース作業 に集中することにしました。ちなみにチームメンバーは僕1人でした。

1日中誰とも喋らずに、ただひらすら黙々とコードを書く日々...久しぶりのぼっち開発はなんだか新鮮な気分でした。技術のことだけ考えていればよかったので最高 of 最高でした。

平日は8時間コードを書き、寝るまでの間は技術系の記事を読み、休日は趣味開発にすべての時間を注いでいました。

趣味で開発していたのは「Flexbox Cheat Site」という Webサイト です。

kuroppe1819.github.io

リリースしてみたら意外と反響がありました。

はてなブックマークのテクノロジー欄でホットトレンド入りを果たし、ブックマーク数は500を超えていました。

はてなブックマーク - 人気エントリー - テクノロジー - 2020年5月25日

リリースしたら社内の技術LT会で発表する!と決めていたので登壇もしました。

その後は検索かけても引っかからなかった内容の記事を書いたり、オライリーのTypeScript本Webパフォーマンスチューニングの本を読んだりしていました。

7月~ (これから)

なんやかんやで kintone開発チーム に戻りました。現在は kintoneの機能を React で開発するプロジェクトに携わっています。

戻った理由は以下の3つです。

  • モブで知識を吸収した方が効率がいい
  • .com共通管理のReact化で学んだスキルを共有できる
  • kintone開発 でぶつかった問題は .com共通管理の開発 でもぶつかることが多いので問題の対処法を一緒に考えたい

今後の方針としては、3ヶ月ごとに kintoneのReact化 と .com共通管理のReact化 を切り替えながら働くことを考えています。

1年をふりかえってみて

自分のできることを模索していた1年間だったなーと思います。

配属された頃はあまりにも仕事ができなくて悩んでいましたが、開発メンバーのサポートのおかげでひよっこWebエンジニアぐらいにはなれたような気がします。

kintoneのドメイン知識もフロントエンドの知識もまだまだ足りないので、これからも精進する所存です。

2年目も頑張るぞー!

cross-envで指定した環境変数がコード上でundefinedになるのをなんとかする

開発用と本番用で表示する View を切り替えたいときに環境変数を使うことがあります。

以下は yarn + webpack + React で環境構築して、環境変数をコードから参照して表示するViewを切り替えている例です。

import React from "react";

function App() {
  return (
    <>
      {process.env.PUBLIC_URL === "/dev" ? (
        <h1>Development</h1>
      ) : (
        <h1>Production</h1>
      )}
    </>
  );
}

ReactDOM.render(
  <App />,
  document.getElementById("root")
);
...
"scripts": {
  "start": "cross-env PUBLIC_URL=/dev webpack-dev-server --hot --config webpack.js"
},
...

yarn run start を実行した時、環境変数 PUBLIC_URL に "/dev" が指定されているため、「Development」が画面に表示されるはずです。しかし、実際に動かしてみると process.env.PUBLIC_URLundefined で「Production」が表示されます。

issue を確認してみたところ、 Webpack DefinePlugin を使うとよさそうだったので利用してみます。

github.com

const webpack = require('webpack');
...
new webpack.DefinePlugin({
  'process.env.PUBLIC_URL': JSON.stringify(process.env.PUBLIC_URL),
}),
...

これで App.js から環境変数を参照することができるようになりました。「Development」が画面に表示されるようになります。

参考