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を使った際に、以下のようなエラーが出ました。
エラー:
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があるオリジン)へのアクセスが許可されていないのが原因で起こったため、プロキシを利用してこのエラーを回避します。
参考:
@nuxt/proxy
のインストールと設定
yarn add @nuxtjs/proxy
nuxt.config.ts
に追記
// 略
modules: [
'nuxt-buefy',
'@nuxtjs/axios',
'@nuxtjs/proxy' // add
],
proxy: {
'/api/': {
target: 'https://zipcloud.ibsnet.co.jp',
changeOrigin: true,
secure: false
}
}
あるいは
proxy: {
'/api/': {
target: 'https://zipcloud.ibsnet.co.jp/api',
pathRewrite: {
'^/api/': '/'
}
}
}
どちらでも通ることは確認しています。
このAPIを使う箇所は以下のように書き換えています。
- before
const { data } = await axios.get(
`https://zipcloud.ibsnet.co.jp/api/search?zipcode=${zipCode}`
);
- after
const { data } = await axios.get(
`http://localhost:3000/api/search?zipcode=${zipCode}`
);
envファイルの作成
このままだと、Local環境とProd環境でBASE_URLが変わるため、エラーが発生します。
そのため環境変数を定義し、 build のタイミングでURLを書き換えるように修正します。
参考:
Nuxt.js ではクライアントサイドとバックエンドサイドで共有される環境変数を定義でき、@nuxtjs/dotenv
を使用すれば、変数を .env
ファイルから context
と process.env
に直接ロードできます。
- インストール
yarn add -D @nuxtjs/dotenv
2. nuxt.config.js
の buildModules
に追加
buildModules: [
`@nuxtjs/dotenv`
],
デフォルトではroot下にある .env
をロードしますが、options で path を指定できます。
buildModules: [
['@nuxtjs/dotenv', {
path: '/path/to/my/global/env/'
}]
]
また、異なる環境のために異なる設定ファイルを override できるとのことです。
以下実装に入ります。
実装
.env
ファイルに以下を追加
BASE_URL = 'http://localhost:3000'
API の URL を環境変数にセットし、Component 内を置き換えます。
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
もあったため、切り分けができなかった可能性?かと推測しました。とりあえず今回はファイルが切り替わることが最終目的のため、ここはスルーします。
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 を以下のように変更します。
"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
は以下のように書き換えます。
dotenv: {
filename: `.env.${process.env.NODE_ENV}`
},
あるいは以下のように設定してもOK.
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での方法もトライしてみます!