32
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

axiosで叩くAPIのホストを環境変数に基づいて変える(Webpack/Vue CLI3)

Last updated at Posted at 2019-03-07

ごめんなさい最初に書いたやり方やっぱりそんなにイケてないです
下の方に追記したdotenv使う方法が一番よさげでした

ダメな例

Hello.vue
<template>
  <div>
    {{ response }}
  </div>
</template>

<script>
import axios from 'axios'

export default {
  name: 'hello',
  data () {
    return {
      response: '',
    }
  },
  mounted () {
    axios.defaults.baseURL =
      process.env.VUE_APP_ENV === 'production' ? 'http://localhost:8001'
      : process.env.VUE_APP_ENV === 'staging' ? 'http://localhost:8002' 
      : 'http://localhost:8003'
    this.$axios.get('/get.json').then(response => (this.info = response))
  }
}
</script>
ビルド時
$ export VUE_APP_ENV=production
$ npm run build

ビルドされたjsファイルにstagingやdevelopment用のAPIのホスト名も書かれてしまうのでこれはNG

ってことで以下のやり方にしましょう

いい例

vue.config.js
const webpack = require('webpack')
module.exports = {
  configureWebpack: {
    plugins: [
      new webpack.DefinePlugin({
        'VUE_APP_API_ENDPOINT': JSON.stringify(
          process.env.VUE_APP_ENV === 'production' ? 'http://localhost:8001'
          : process.env.VUE_APP_ENV === 'staging' ? 'http://localhost:8002'
          : 'http://localhost:8003'
        )
      })
    ]
  },
Hello.vue
<template>
  <div>
    {{ response }}
  </div>
</template>

<script>
import axios from 'axios'

export default {
  name: 'hello',
  data () {
    return {
      response: '',
    }
  },
  mounted () {
    axios.defaults.baseURL = VUE_APP_API_ENDPOINT
    this.$axios.get('/get.json').then(response => (this.info = response))
  }
}
</script>

もしくは

これでもいい

vue.config.js
module.exports = {
  chainWebpack: config => {
    config
      .plugin('web-component-options')
      .use(require('webpack/lib/DefinePlugin'), [{
        'VUE_APP_API_ENDPOINT': JSON.stringify(
          process.env.VUE_APP_ENV === 'production' ? 'http://localhost:8001'
          : process.env.VUE_APP_ENV === 'staging' ? 'http://localhost:8002'
          : 'http://localhost:8003'
        )
      }])
  }
}

参考資料

Vue CLI3は2系に比べるとWebpackの設定が隠されてて苦労しました

セキュリティ意識と給料は高いに越したことはないですね

追記

上記だと動作は問題ないけどLinterが
VUE_APP_API_ENDPOINTが未定義だよって怒るので結局dotenvがいいのかもしれない

dotenvで環境ごとに切り替える方法

.env.[mode]というファイルを用意する

例えば

  • .env.development => developmentモードの時に読み込まれる
  • .env.staging => stagingモードの時に読み込まれる
  • .env.production => productionモードの時に読み込まれる
  • .env => モード関係なく読まれる(共通の項目を書くといい)

下に貼ったリンクの公式ドキュメント見るとdevelopment/production/testだけが取り上げられてるけどstagingもいけるみたい

ただ、環境変数NODE_ENVdevelopment/productionのどちらかにしとかないとビルド時の設定が変わるらしい(optimizedとか)

modeの指定

servebuildの時に--mode developmentとかってしてやればいいけど

$ npm run server --mode development

だと引数をちゃんと拾ってくれないので

$ ./node_modules/.bin/vue-cli-service serve --mode staging

と叩くか、もしくはpackage.jsonにスクリプトを追加する

package.json
.
.
.
  "scripts": {
    "serve:dev": "vue-cli-service serve --mode development",
    "serve:stg": "vue-cli-service serve --mode staging",
    "serve:prd": "vue-cli-service serve --mode production",
    "build:dev": "vue-cli-service build --mode development",
    "build:stg": "vue-cli-service build --mode staging",
    "build:prd": "vue-cli-service build --mode production",
    "lint": "vue-cli-service lint"
  },
.
.
.

環境変数の制約

基本定数にはプレフィックスVUE_APP_をつけなきゃいけないけど
NODE_ENVは許されるっぽい

以上を踏まえてどうしたらいいのかっていうと

1. 下記ファイルを作成

  • .env.development
  • .env.staging
  • .env.production
  • .env

2. 下記ファイルを修正

  • package.json

3. vueソース内ではprocess.env.VUE_APP_API_ENDPOINTをはめ込む

こんな感じかな

.env
# 共通の設定を書く
VUE_APP_COMMON=common
.env.development
# developmentの設定を書く
NODE_ENV=development
VUE_APP_API_ENDPOINT=http://localhost:3000
.env.staging
# stagingの設定を書く
NODE_ENV=production
VUE_APP_API_ENDPOINT=http://stg.api-server-domain
.env.production
# productionの設定を書く
NODE_ENV=production
VUE_APP_API_ENDPOINT=http://api-server-domain
package.json
.
.
.
  "scripts": {
    "serve:dev": "vue-cli-service serve --mode development",
    "serve:stg": "vue-cli-service serve --mode staging",
    "serve:prd": "vue-cli-service serve --mode production",
    "build:dev": "vue-cli-service build --mode development",
    "build:stg": "vue-cli-service build --mode staging",
    "build:prd": "vue-cli-service build --mode production",
    "lint": "vue-cli-service lint"
  },
.
.
.
Hello.vue
<template>
  <div>
    {{ response }}
  </div>
</template>

<script>
import axios from 'axios'

export default {
  name: 'hello',
  data () {
    return {
      response: '',
    }
  },
  mounted () {
    axios.defaults.baseURL = process.env.VUE_APP_API_ENDPOINT
    this.$axios.get('/get.json').then(response => (this.info = response))
  }
}
</script>

NODE_ENVについては

modeオプションとは別に、明示的に定義しないと
stagingはNODE_ENV=developmentとしてビルドされてしまうため
NODE_ENV=productionで定義してる

ローカルでビルドした結果を確認したい時には
.env.developmentNODE_ENV=productionにしたりしなきゃいけないだろうから
全部NODE_ENV=productionでもいいかも

それなら.env.developmentにだけNODE_ENVを書かずに
npm scriptsでexportしちゃうとか

package.json
.
.
.
  "scripts": {
    "serve:dev": "export NODE_ENV=development; vue-cli-service serve --mode development",
    "serve:stg": "vue-cli-service serve --mode staging",
    "serve:prd": "vue-cli-service serve --mode production",
    "build:dev": "export NODE_ENV=production; vue-cli-service build --mode development",
    "build:stg": "vue-cli-service build --mode staging",
    "build:prd": "vue-cli-service build --mode production",
    "lint": "vue-cli-service lint"
  },
.
.
.

いっそのことstgもprdもNODE_ENVはnpm scriptsに書いた方がいい気がしてきた

ってことで
これでlinterに文句は言われず、ビルドされたjsにも他環境の情報が載らないのでこっちの方がよさげですね

他にいい方法あったら教えてくださいフロントエンドの神様

参考記事

- https://cli.vuejs.org/guide/mode-and-env.html#environment-variables

32
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?