Reactにおける環境変数を設定について、ようやく理解したので原因と共にまとめてみる_100DaysOfCodeチャレンジ38日目(Day_38:#100DaysOfCode)


## はじめに

これまでRailsでdotenvを使っていたので、同じ感覚で使えるだろと思い、今回の個人開発Reactでも採用することに。

ところが、どうも設定がうまくいかず、一時期ずっと悩んでいました。

つい最近、ようやく問題が解決したので、原因となっていた問題と共にアウトプットとして記事に残します。

また、この記事はTwitterで人気のハッシュタグ#100DaysOfCodeをつけて、
100日間プログラミング学習を続けるチャレンジに挑戦した38日目の記録です。

## 動作環境

* react-scripts: 1.1.4

## 前提条件

`create-react-app`でReactプロジェクトを立ち上げていること

## 今までの設定方法

下記のdotenv公式サイトを参考に、READMEにならってプロジェクト直下に`.env`を作成しました。

https://github.com/motdotla/dotenv

当時のdotenvのファイル内容はこんな感じ。

```env
YOUTUBE_API_KEY=hogehogehugahuga485732
```

で、dotenvで設定したファイルを次のようにコンポーネントで読み込んでました。

ここでは、`youtube-api-search`のAPIキーをdotenvで管理しようとしていました。

```react
import React, { Component } from "react";
import YTSearch from "youtube-api-search";
import dotenv from "dotenv";

const API_KEY = dotenv.config(process.env.YOUTUBE_API_KEY);
console.log(API_KEY);

YTSearch({ key: API_KEY, term: "水族館" }, function(data) {
  console.log(data);
});
```

結果、コンソールで次のようなエラーが発生していました。

```javascript
{error: TypeError: fs.readFileSync is not a function
    at Object.config (http://localhost:3000/static/js/b…}
xhr.js:115 GET https://www.googleapis.com/youtube/v3/search?part=snippet&key=%7B%22error%22:%7B%7D%7D&q=%E6%B0%B4%E6%97%8F%E9%A4%A8&type=video 400 ()
xhrAdapter @ xhr.js:115
(anonymous) @ dispatchRequest.js:15
dispatchRequest @ dispatchRequest.js:11
Promise.then (async)
../node_modules/axios/lib/axios.js.module.exports @ axios.js:40
axios.(anonymous function) @ axios.js:66
../node_modules/youtube-api-search/index.js.module.exports @ index.js:17
./src/components/Youtube/youtube_search_bar.js @ youtube_search_bar.js:9
__webpack_require__ @ bootstrap cce4570accfe85501067:678
fn @ bootstrap cce4570accfe85501067:88
./src/App.js @ App.css?9a66:26
__webpack_require__ @ bootstrap cce4570accfe85501067:678
fn @ bootstrap cce4570accfe85501067:88
./src/index.js @ index.css?f255:26
__webpack_require__ @ bootstrap cce4570accfe85501067:678
fn @ bootstrap cce4570accfe85501067:88
0 @ registerServiceWorker.js:117
__webpack_require__ @ bootstrap cce4570accfe85501067:678
(anonymous) @ bootstrap cce4570accfe85501067:724
(anonymous) @ bootstrap cce4570accfe85501067:724
index.js:2178 {data: {…}, status: 400, statusText: "", headers: {…}, config: {…}}
```

どうやら、dotenvに設定したはずの、APIキーの値が読みこまれていないようです。

## 解決に向けてやったこと

* dotenvリポジトリのcloseされたissueの中から、関連したものがないか検索してみる
* create-react-appのソースコードを読んでみる

いくつか検索していくうちに、create-react-appの[Users Guide](https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#adding-development-environment-variables-in-env)に、次のような一文があることを発見。

>Note: this feature is available with react-scripts@0.5.0 and higher.

>To define permanent environment variables, create a file called .env in the root of your project:

>`REACT_APP_SECRET_CODE=abcdef`

>Note: You must create custom environment variables beginning with REACT_APP_. Any other variables except NODE_ENV will be ignored to avoid accidentally exposing a private key on the machine that could have the same name. Changing any environment variables will require you to restart the development server if it is running.

ここによると、create-react-appで作成したプロジェクトでdotenvを使用する場合、prefixに`REACT_APP_`をつける必要があるとのこと。

ということは、もしやcreate-react-app自体に、すでにdotenvが組み込まれているのでは？

ソースコードを調べてみると。。

```packages/react-scripts/config/env.js

var dotenvFiles = [ 
 `${paths.dotenv}.${NODE_ENV}.local`, 
 `${paths.dotenv}.${NODE_ENV}`, 
```

すでに`env.js`があるじゃないですか！

つまり、わざわざ`dotenv.config(process.env.YOUTUBE_API_KEY);`のように書かなくても、create-react-appでは、すでにdotenvを使えるようにお膳立てしてくれているので、それに任せればいいということ。

## 改修後のコード

というわけで、最終的に動くようになったコードがこちら。

```react
import React, { Component } from "react";
import YTSearch from "youtube-api-search";

const API_KEY = process.env.REACT_APP_YOUTUBE_API_KEY;
console.log(API_KEY);

YTSearch({ key: API_KEY, term: "水族館" }, function(data) {
  console.log(data);
});
```

```env
REACT_APP_YOUTUBE_API_KEY=hogehogehugahuga485732
```

これでコンソールでもエラーは出ずに、無事API経由で値を取ることができました！

```javascript
(5) [{…}, {…}, {…}, {…}, {…}]
0
:
{kind: "youtube#searchResult", etag: ""XI7nbFXulYBIpL0ayR_gDh3eu1k/5XPZmUCd7jo1pdJ1-CDdosFeI-Y"", id: {…}, snippet: {…}}
1
:
{kind: "youtube#searchResult", etag: ""XI7nbFXulYBIpL0ayR_gDh3eu1k/0UIYPKhKX74Bsl8caKN0h2CyjnI"", id: {…}, snippet: {…}}
2
:
{kind: "youtube#searchResult", etag: ""XI7nbFXulYBIpL0ayR_gDh3eu1k/Kq9VGmwBXKns6SFyEP9eOBvDYoU"", id: {…}, snippet: {…}}
3
:
{kind: "youtube#searchResult", etag: ""XI7nbFXulYBIpL0ayR_gDh3eu1k/dgrrAw4tSfS0I0Tm_3HAWMZikC4"", id: {…}, snippet: {…}}
4
:
{kind: "youtube#searchResult", etag: ""XI7nbFXulYBIpL0ayR_gDh3eu1k/9cZ31PrsKQHnbREvITl_0hnheMY"", id: {…}, snippet: {…}}
length
:
5
__proto__
:
Array(0)
```

## 最後に

答えは常に公式リファレンスと公式リポジトリに書いてある。