React
dotenv

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のファイル内容はこんな感じ。

YOUTUBE_API_KEY=hogehogehugahuga485732

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

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

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);
});

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

{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に、次のような一文があることを発見。

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を使えるようにお膳立てしてくれているので、それに任せればいいということ。

改修後のコード

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

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);
});
REACT_APP_YOUTUBE_API_KEY=hogehogehugahuga485732

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

(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)

最後に

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