11
5

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.

FORKAdvent Calendar 2018

Day 21

babel-plugin-transform-runtimeだとIE11でVuexが使えない

Last updated at Posted at 2018-12-20

Vueでアプリを開発する際、規模にかかわらずイベントバスがめんどい拡張性を担保するため、
基本的にVuexをインストールしています。
状態管理で幸せになれる便利なVuexライブラリですが、「IE11でVuex使えない!」というケースがあるので、原因と対策をまとめてみました。

webpackを使用していることを前提としています。
また、検証用に使用したvue-cli(2.9.6)でインストールされるbabelが6系のものだったので、
babel関連のモジュール名も6系のものに合わせています。
7系を使っている場合はbabel-XXX
を**@babel/xxx**に読み替えてください。

##IE11のエラー
IE11でVuexが動いていない場合、ブラウザ表示が真っ白になって(何も表示されず)、コンソールで以下のエラーが吐かれるかと思います。

SCRIPT5022: [vuex] vuex requires a Promise polyfill in this browser.

どうやら、IE11でvuexを使うにはPromiseのポリフィルが必要なようです。

##結論
いきなり結論ですが、上記のエラーの通り、Promiseのポリフィルを入れることでIE11にVuexを対応させることができます。
が、タイトルの通りbabel-plugin-transform-runtimeだとVuexライブラリ内のPromiseが変換されません。

ちなみに、**vue-cli(3.x)**ではBabel7およびpreset-envによるポリフィル注入がサポートされているため、デフォルトでIE11でもVuexが動作していることが確認できました。

言い換えると、

  • vue-cli 3.xではなくvue-cli 2.xでプロジェクトを作成した
  • ES2015+の関数をbabel-polyfillではなくbabel-plugin-transform-runtimeでトランスパイルしている
  • そもそもES2015+(Promise)のpolyfillをどこにも置いていない

といった場合にIE11でVuexが使えないケースが起こりうるのではないかと思います。

##原因
Vuexライブラリでは内部的にPromiseが使用されています。
(actionsがPromiseを返す、とかそのあたりだと思う)

IE11はPromiseをサポートしていないため、Promiseって知らないからポリフィル入れてね、とエラーが出るわけですね。

###transform-runtimeだとダメな理由

transform-runtime はグローバルにpolyfillを置くものではありません(グローバル汚染しないなどの利点があります)。
ES2015+の関数があれば、JSファイルごとに必要な箇所を書き換えるよ、という静的解析するものなので、
node_modulesであるVuexライブラリ内部のPromiseに関しては変換の対象外となってしまいます。

babelの設定に関しては以下の記事が参考になります。

##対処と検証
まずは実際にIE11でVuexが使えない環境を再現します。

検証用プロジェクトの作成

今回検証のために**vue-cli(2.9.6)**を使ってプロジェクトを作りました。

Vue.js を vue-cli を使ってシンプルにはじめてみる」を参考にさせていただきました。

生成された.babelrcを見ると、pluginsに"transform-runtime"が使用されているようです。

{
  "presets": [
    ["env", {
      "modules": false,
      "targets": {
        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
      }
    }],
    "stage-2"
  ],
  "plugins": ["transform-vue-jsx", "transform-runtime"],
  "env": {
    "test": {
      "presets": ["env", "stage-2"],
      "plugins": ["transform-vue-jsx", "transform-es2015-modules-commonjs", "dynamic-import-node"]
    }
  }
}

プロジェクトを作成したら、Vuexをインストールします。

npm i -S vuex

つぎに、ストアのインスタンスを新規作成します。

/src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    hoge: 'Storeのhogeです'
  }
})

export default store

作成したストアを/src/main.jsで読み込みます。

/src/main.js.diff
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'

+ import store from './store'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
+ store,
  components: { App },
  template: '<App/>'
})

プロジェクト作成時にHelloWorld.vueが作成されていると思うので、ここにStoreの情報を表示するよう変更します。

/src/components/HelloWorld.vue.diff
<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
-     msg: 'Welcome to Your Vue.js App'
+     msg: this.$store.state.hoge
    }
  }
}
</script>

Vuexが使えていれば、以下のh1タグ内にStoreのhogeが表示されすはずです。

/src/components/HelloWorld.vue
<template>
  <div class="hello">
    <h1>{{ msg }}</h1> //ここに表示されるはず

下記コマンドを叩いてlocalhostで確認します。

npm run dev

ChromeなどPromiseをサポートしているブラウザでは、問題なく下記のように表示されるかと思います。
vue-cli-test - http___localhost_8080_.png

IE11は何も表示されず、例のエラーが表示されます。
vue-cli-test - http___localhost_8080_IE.png

###IE11でVuexを使えるようにする
前置きが長くなりましたが、いよいよ本題です。
以下の2つのやり方のいずれかで対処することができました。

1. es6-promiseをimportする方法

es6-promiseをインストールします。

npm i -D es6-promise

main.jsにes6-promiseをimportします。
注意点として、storeのimport文より前に記述してください。

/src/main.js.diff
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'

+ import 'es6-promise/auto'
import store from './store'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  store,
  components: { App },
  template: '<App/>'
})

2. babel-polyfillをバンドル時に結合する方法

babel-polyfillをインストールします。

npm i -D babel-polyfill

webpack.base.conf.jsを修正して、main.jsをバンドルする際にbabel-polyfillを結合します。

/build/webpack.base.conf.js.diff
module.exports = {
  context: path.resolve(__dirname, '../'),
  entry: {
-   app: './src/main.js'
+   app: ['babel-polyfill','./src/main.js']
  },

同時に、.babelrc"transform-runtime"は不要になるはずなので、こちらを削除します。

{
  "presets": [
    ["env", {
      "modules": false,
      "targets": {
        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
      }
    }],
    "stage-2"
  ],
- "plugins": ["transform-vue-jsx", "transform-runtime"],
+ "plugins": ["transform-vue-jsx"],
  "env": {
    "test": {
      "presets": ["env", "stage-2"],
      "plugins": ["transform-vue-jsx", "transform-es2015-modules-commonjs", "dynamic-import-node"]
    }
  }
}

結果

vue-cli-test - http___localhost_8080_IEOK.png

無事、IE11でもVuexが使用できるようになりました。

参考

下記を参考にしました。

:christmas_tree: FORK Advent Calendar 2018
:arrow_left: 20日目 git cloneできない時の調べ方と対策 〜AWS CodeCommit/Mac OSの場合〜 @izanari
:arrow_right: 22日目 Apache(php-fpm + Apache 2.4)で何を設定すればいいのかわからなかったので調べてみた @Kodak_tmo

11
5
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
11
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?