Nuxt.js の CORS 回避の方法と環境変数の設定方法

## Prologue

外部APIを使おうとしたときに、CORSで引っかかってしまいました。良いきっかけと思い、Nuxt.js での回避方法と、その際 Proxy を使ったため、環境変数を使用してURLをDev環境とProd環境で切り替える方法を調べました。

基本はDocument通りになるため、自身で設定する場合には都度公式を確認することをお勧めします。

## 環境

- macOS: v10.15.5
- node.js: v12.18.2
- terminal: iTerm
- エディタ: VS Code
- パッケージマネージャ: `yarn`

## CORS の回避

外部APIを使った際に、以下のようなエラーが出ました。

エラー: 

``` Shell
Access to XMLHttpRequest at 'https://zipcloud.ibsnet.co.jp/api/search?zipcode=3110105' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
```

CORS policy によってブロックされた、という内容です。

CORSに関しては以下の記事がわかりやすかったです。

参考: https://qiita.com/att55/items/2154a8aad8bf1409db2b

APIを使うオリジンから別のオリジン(APIがあるオリジン)へのアクセスが許可されていないのが原因で起こったため、プロキシを利用してこのエラーを回避します。

参考: 

- https://ja.nuxtjs.org/faq/http-proxy/
- https://github.com/nuxt-community/proxy-module#readme

### `@nuxt/proxy` のインストールと設定

``` 
yarn add @nuxtjs/proxy
```

`nuxt.config.ts` に追記

``` JS
// 略
modules: [
        'nuxt-buefy',
        '@nuxtjs/axios',
        '@nuxtjs/proxy' // add
    ],
    proxy: {
        '/api/': {
            target: 'https://zipcloud.ibsnet.co.jp',
            changeOrigin: true,
            secure: false
        }
    }
```

あるいは

``` JS
  proxy: {
      '/api/': {
          target: 'https://zipcloud.ibsnet.co.jp/api',
          pathRewrite: {
              '^/api/': '/'
          }
      }
  }
```

どちらでも通ることは確認しています。

このAPIを使う箇所は以下のように書き換えています。

- before

``` JS
const { data } = await axios.get(
   `https://zipcloud.ibsnet.co.jp/api/search?zipcode=${zipCode}`
);
```

- after

``` JS
const { data } = await axios.get(
   `http://localhost:3000/api/search?zipcode=${zipCode}`
);
```

## envファイルの作成

このままだと、Local環境とProd環境でBASE_URLが変わるため、エラーが発生します。
そのため環境変数を定義し、 build のタイミングでURLを書き換えるように修正します。

参考:

- https://ja.nuxtjs.org/api/configuration-env/
- https://github.com/nuxt-community/dotenv-module

Nuxt.js ではクライアントサイドとバックエンドサイドで共有される環境変数を定義でき、`@nuxtjs/dotenv` を使用すれば、変数を `.env` ファイルから `context` と `process.env` に直接ロードできます。

1. インストール

``` 
yarn add -D @nuxtjs/dotenv
```

2\. `nuxt.config.js` の `buildModules` に追加

``` JS
buildModules: [
 `@nuxtjs/dotenv`
],
```

デフォルトではroot下にある `.env` をロードしますが、options で path を指定できます。

``` JS
buildModules: [
    ['@nuxtjs/dotenv', {
        path: '/path/to/my/global/env/'
    }]
]
```

また、異なる環境のために異なる設定ファイルを override できるとのことです。
以下実装に入ります。

### 実装

`.env` ファイルに以下を追加

``` JS
BASE_URL = 'http://localhost:3000'
```

API の URL を環境変数にセットし、Component 内を置き換えます。

``` JS
const { data } = await axios.get(
  `${process.env.BASE_URL}/api/search?zipcode=${zipCode}` // After
  // `http://localhost:3000/api/search?zipcode=${zipCode}` // Before
);
```

ファイル名を `.env.development` に変更し、 `nuxt.config.js` に `dotenv` の options を設定します。

この `options` ですが `buildModules` プロパティ内に記載すると ` ✖ Nuxt Fatal Error TypeError: The 'request' argument must be string. Received type undefined` というエラーが出たため、下記の方法で対応しました。

理由はわからないですが、 `buildModules` に `@nuxt/typescript-build` もあったため、切り分けができなかった可能性？かと推測しました。とりあえず今回はファイルが切り替わることが最終目的のため、ここはスルーします。

``` JS
 buildModules: [
   '@nuxt/typescript-build',
   `@nuxtjs/dotenv`
 ],
 dotenv: {
   filename: `.env.development`
 },
```

### Dev環境とProd環境で読み込む設定ファイルを切り替える

参考: https://ja.nuxtjs.org/api/configuration-dev/


`process.env.NODE_ENV` は `nuxt` (`yarn dev`) コマンド実行の際には `development` となるようなので、それを利用します。

`package.json` の script を以下のように変更します。

``` JS
  "scripts": {
    "dev": "nuxt-ts",
    "build": "NODE_ENV=production  nuxt-ts build",
    "start": "nuxt-ts start",
    "generate": "nuxt-ts generate",
    "lint:js": "eslint --ext .js,.vue --ignore-path .gitignore .",
    "lint": "yarn lint:js",
    "test": "jest"
  },
```

`nuxt.config.js` は以下のように書き換えます。

``` JS
dotenv: {
  filename: `.env.${process.env.NODE_ENV}`
},
```

あるいは以下のように設定してもOK.

``` JS
const environment = `.env.${process.env.NODE_ENV}`

export default {
  // 略
  dotenv: {
    filename: environment
  },
```

`yarn build` コマンド実行の際に、環境変数 `NODE_ENV` が `production` に設定され、環境変数ファイルの読み込みは `.env.production` に変更される、という流れになります。

注意点として、`process.env` は利用可能であっても未定義で、 `process.env.***` とすることによって個別にマップされてコンパイル時に変換されます。
そのため、 Debug 等する際には `console.log(process.env.***)` と取るように気を付けてください。
参考: https://ja.nuxtjs.org/api/configuration-env/#processenv--

## Epilogue

公式のドキュメントを追いながら理解を進めることができたので、これまでのなんとなく、を多少解消できたと思います。
ただ、細かい部分や公式で明言されていない部分等は多分こういうことを言っているんだろう...と思って書いた部分もあるため、もし間違いがありましたら教えてください。

機会があればVue.jsでの方法もトライしてみます！