👊

Vue/CLI と Nuxt.js で IE11 と戦うための知識

2021/09/26に公開

令和も3年だというのに、仕事でどうしても Internet Explorer 11 と戦わなければならないこと、あると思います。
IE 11 への対応は巷の記事で様々取り扱われていますが、どうも情報が古かったり、とっ散らかってる印象がありました。

そこで、最新の Vue 2.x の環境はどうなんだろう?と思い、Vue/CLI と Nuxt.js の最新バージョン(2021-09-22時点)の Babel によるトランスパイルと Polyfill についてまとめました。

正直、IE 11 について記事を書くのはこれが最後にしたいですね。

今後、可能な限り各 OSS のアップデートに合わせて記事を更新するようにしたいと考えています。
実際の動作や公式ドキュメントとの齟齬がありましたら、コメントにてご教示いただけますと幸いです。

前提知識

  • Babel
  • トランスパイル
  • Polyfill

これらについては、本記事では説明しません。
私が参考にした中では、下記の記事が一番わかりやすかったです。

Babelによるトランスパイルの挙動について理解する - Qiita

上記の記事の更新日は2018年と少し古めなので、Babel自体の使い方などについてはBabel 公式ドキュメントも併せてご参照ください。

Vue/CLI のトランスパイルと Polyfill について

検証したバージョン

  • vue: 2.6.14
  • @vue/cli: 4.5.13

検証結果

1. browserslist を見て、その対象のブラウザ向けのトランスパイルと Polyfill を提供してくれる

こちらはVue/CLI の公式ドキュメントに記載がありました。

Vue/CLI を使う場合は、browserslist に IE 11 を含むように追加しましょう。

browserslistrc
defaults
IE 11

npx browserslistで対応させるブラウザの一覧が表示できます。

2. node_modules/ 配下のモジュールはトランスパイルされない

Vue/CLI はデフォルトでは、npm install でインストールされた node_modules/ 配下のモジュールをトランスパイルしません。

そのため、node_modules/ 配下の特定のモジュールをトランスパイルしたい場合、vue.config.js を以下のようにして対応できます。

vue.config.js
module.exports = {
  transpileDependencies: [
    // can be string or regex
    'my-dep',
    /other-dep/
  ]
}

参考:@vue/cli-plugin-babel - Vue CLI

3. modern モードでモダンブラウザとレガシーブラウザ(フォールバック用)の2種を分けてビルドできる

package.json
{
  "script": {
    "build:modern": "vue-cli-service build --modern"
  }
}

これは調査をして初めて知りましたが、Vue/CLI には modern モードというビルドモードが存在します。

モダンモードのビルドは、レガシーブラウザ用のトランスパイルや Polyfill を含むソースコードを、モダンブラウザに読み込ませないビルド方法です。

ビルドコマンドに --modern を追加すると、ビルド結果として以下のファイルが生成されます。

  • app.*.js
  • app-legacy.*.js
  • chunk-vendors.*.js
  • chunk-vendors-legacy.*.js

-legacyがファイル名についているものは、レガシーブラウザ用のトランスパイルと Polyfill が含まれます。

ビルドで生成された index.html の中でそれぞれの .js ファイルを script タグで読み込みますが、モダンブラウザ向けの script タグには type="module" が付与され、レガシーブラウザ向けの script タグには nomodule が付与されます。

こうすることで、モダンブラウザとレガシーブラウザで読み込む .js ファイルを分岐させています。

Nuxt.js のトランスパイルと Polyfill について

検証したバージョン

  • vue: 2.6.14
  • nuxt: 2.15.8

検証結果

1. 常に IE 9 までのトランスパイルと Polyfill の提供をしてくれる

Nuxt.js の公式ドキュメントに記載の通り、ブラウザ向けには IE 9 をターゲットにしたトランスパイルと Polyfill を提供してくれるようです。

2. node_modules/ 配下のモジュールはトランスパイルされない

Vue/CLI と同様に、node_modules/ 配下のモジュールはトランスパイルされません。

トランスパイルしたい場合は、nuxt.config.js の build オプションを以下のように指定します。

nuxt.config.js
build: {
  transpile: [({ isLegacy  }) => isLegacy && "{トランスパイルしたいモジュール名}"],
}

この isLegacy といパラメーターは、後述の modern プロパティで登場するレガシーブラウザ向けのビルドの際に使われるパラメーターです。
modern プロパティを使うと、レガシーブラウザ向けのビルドのみモジュールがトランスパイルされるようになります。

個人的な感覚ですが、Nuxt を使って IE 11 で構文エラーになるときは、だいたい外部のモジュールがトランスパイルされてない気がします。

外部モジュールはものによりますが、IE 11 をサポートしていたり、サポートしていないけどトランスパイルすれば使えたり、トランスパイルしても使えなかったりします。
各モジュールのドキュメントをご参照ください。

3. modern プロパティでモダンブラウザとレガシーブラウザ(フォールバック用)の2種を分けられる

package.json
{
  "script": {
    // server (SSR)の場合
    "build:modern": "nuxt build --modern=server",
    "start:modern": "nuxt start --modern=server",
    // clinet (SPA・SSG)の場合
    "generate:modern": "nuxt generate --modern=client"
  }
}

ブラウザ向けの場合、nuxt generate--modern=clientを指定すると、 2. にあった build プロパティの isLegacy が変化します。

4. browserslist は見てはいるけど、Vue/CLI とは違い babel のデフォルトの設定には影響しない

こちらは手元で検証した結果、browserslist を指定によらず、ビルド結果に変化が見られませんでした。

browserslist で最新の Chrome だけを指定しても、トランスパイルされるし、Polyfill も提供されるようです。

まとめ

Vue 2.x で IE 11 に対応するとき色々嘆いてたけど、Vue/CLI と Nuxt.js は割と CLI 側で結構なんとかしてくれるし、しっかり知識を持って臨めばなんとかなる。

そろそろ IE 11 とは縁を切って業務でも Vue 3.x を使いたいものです。

Discussion