with IE(JavaScriptのIE11対応)

## はじめに

政府や行政サイトの「IE縛り」に代表されるように、IE汚染国である日本で仕事としてJavaScriptを書く場合、IEと共存するしなければならない場合が多いです。
with コロナならぬwith IEです。

### IE生活様式

- Transpile
- Bundle
- Polyfill

TranspileとBundle は、ES5の書き方で1つのファイルに書いていれば不要です。
エンジニアが不便を我慢すれば必要ない工程ではありますが、そんな我慢はしたくありません。
コロナで言えばマスク、消毒、手洗い、うがい、密を避ける、換気のような個人でできる対策に当たると思います。

Polyfillは、もともとIE11が対応していない機能に対応させるもので、コロナでいえば治療薬ともいえるものだと思いますが、薬なのでリスクもあります。

コロナと違って、みんなでIEやめる合意が取れればIE対応せずに済む世界になるんですが。
河野大臣、ハンコ、書面、FAXに続いて、IE対応不要もお願いします。




## JavaScriptをIE11対応する

### webpackとBabelのインストール

```:terminal
npm install -D webpack webpack-cli babel-loader @babel/core @babel/preset-env 
```


|パッケージ|内容|
|---|---|
|webpack|webpack本体|
|webpack-cli|webpackのコマンドラインツール|
|babel-loader|webpackでBabelを使えるようにする|
|@babel/core|Babel本体|
|@babel/preset-env|指定したブラウザ環境で動作するように変換するプラグイン|

### 設定ファイルの準備

#### package.jsonの編集
package.jsonにビルドコマンドを追加します。

```:package.json
{
 "scripts": {
   "dev": "webpack --mode development",
   "build": "webpack --mode production"
  }
}
```

#### webpack.config.jsの作成
プロジェクトルートにwebpackの設定ファイルのwebpack.config.jsを作成します。
babelでtargetsを指定しないとbabel/preset-envがbrowserslistとの連携を行なってくれるので指定しません。

```:webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          {
            loader: "babel-loader"
          }
        ]
      }
    ]
  }
};
```

#### .babelrc
プロジェクトルートにBabelの設定ファイルの.babelrcファイルを作成します。
※webpack.config.js内に記述することもできます。

```:.babelrc
{
  "presets": ["@babel/preset-env"]
}
```

#### .browserslistrc
プロジェクトルートに対象ブラウザを指定する.browserslistrcファイルを作成します。

```:.browserslistrc
ie 11
```

[.browserslistrcで対象ブラウザを指定する](https://qiita.com/takeshisakuma/items/0bc1c39ee976bd1f52d7)





### Transpile

#### TranspileするJavaScriptの準備

```:src/index.js
window.addEventListener("load", () => {
  alert("InternetExplorer");
});
```

#### Transpile後のJavaScriptを読み込むHTMLの準備

```:dist/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script src="main.js"></script>
</body>
</html>
```

#### ビルド

```:terminal
npm run build
```

####  動作確認
IE11でdist/index.htmlを開いて、JavaScriptが実行できているか確認します。



### polyfillの追加
APIがサポートされていないなど、構文の変換だけでは対応できない機能への対応を行うpolyfillを追加できるようにします。

#### core-jsのインストール

```:terminal 
npm install -S core-js
```

#### .babelrcの変更

```:.babelrc
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "usage",
        "corejs": {
          "version": 3,
          "proposals": false  
        }
      }
    ]
  ]
}
``` 

#### Polyfillを追加するJavaScriptの準備

```:src/index.js
alert(Array.from("InternetExplorer"));
```

#### ビルド

```:terminal
npm run build
```

####  動作確認
IE11でdist/index.htmlを開いて、JavaScriptが実行できているか確認します。

#### regenerator-runtime
必要に応じてregenerator-runtimeを使用します。
(ビルド時にCan't resolve 'regenerator-runtime/runtime'が表示されたとき)

##### regenerator-runtimeのインストール

```:terminal 
npm i -S regenerator
```

##### regenerator-runtimeのインポート

```:JavaScript
import  regeneratorRuntime  from  "regenerator-runtime" ;

//もしくは
//import  "regenerator-runtime / runtime.js" ;
```










## TypeScriptをIE11対応する

### webpackとTypeScriptのインストール

```:terminal
npm install -D webpack webpack-cli typescript ts-loader 
```

table:パッケージ

|パッケージ|内容|
|---|---|
|webpack|webpack本体|
|webpack-cli|webpackのコマンドラインツール|
|typescript|TypeScript本体|
|ts-loader|webpackでTypeScriptを読み込む|



### 設定ファイルの準備
#### package.jsonの編集
package.jsonにビルドコマンドを追加します。

```:package.json
{
  "scripts": {
    "dev": "webpack --mode development",
    "build": "webpack --mode production"
},
```

#### tsconfig.jsonの作成
tsconfigでは.browserslistrcが使えないので、targetでJavaScriptのバージョンを指定します。

```:tsconfig.json
{
  "compilerOptions": {
    "target": "ES5",
    "lib": ["dom", "ES5","ScriptHost"]
  }
}
```



|target|lib省略時に暗黙的に指定されているもの|
|---|---|
|ES5|DOM,ES5,ScriptHost|
|ES6|lib: DOM,ES6,DOM.Iterable,ScriptHost|

※この時点ではlibの記述は不要ですが、後でlibを追加するので先にデフォルトのlibを記述しています。


#### webpack.config.jsの作成

```:webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.ts$/,
        loader: 'ts-loader'
      }
    ]
  },
  resolve: {
    extensions: ['.ts', '.js']
  }
}
```







### Transpile
#### TranspileするJavaScriptの準備
アロー関数のコードをIEで実行できるように変換

```:src/index.ts
window.addEventListener("load", () => {
  alert("InternetExplorer");
});
```

#### Transpile後のJavaScriptを読み込むHTMLの準備

```:dist/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script src="main.js"></script>
</body>
</html>
```

####  ビルド

```:terminal
npm run build
```

####  IE11での動作確認
IE11でdist/index.htmlを開いて、JavaScriptが実行できているか確認します。



### polyfillの追加
APIがサポートされていないなど、構文の変換だけでは対応できない機能への対応を行うpolyfillを追加できるようにします。

#### core-jsのインストール

```:terminal 
npm install -S core-js
```

#### 動作確認用のコードの準備

```:src/index.js
import "core-js";

alert(Array.from("InternetExplorer"));
``` 

#### tsconfig.jsonの変更
libに追加します。

```:tsconfig.json
{
  "compilerOptions": {
    "target": "ES5",
      "lib": ["dom", "ES5","ScriptHost","ES2015.Core"]
  }
}
```

今回はlibに"ES2015.Core"を追加しましたが、コードによって追加する内容は変わります。

##### libの値

- es5
- es6
- es2015
- es7
- es2016
- es2017
- es2018
- es2019
- es2020
- esnext
- dom
- dom.iterable
- webworker
- webworker.importscripts
- scripthost
- es2015.core
- es2015.collection
- es2015.generator
- es2015.iterable
- es2015.promise
- es2015.proxy
- es2015.reflect
- es2015.symbol
- es2015.symbol.wellknown
- es2016.array.includees2017.object
- es2017.sharedmemory
- es2017.string
- es2017.intl
- es2017.typedarrays
- es2018.asyncgenerator
- es2018.asynciterable
- es2018.intl
- es2018.promise
- es2018.regexp
- es2019.array
- es2019.object
- es2019.string
- es2019.symbol
- es2020.bigint
- es2020.promise
- es2020.string
- es2020.symbol.wellknown
- es2020.intl
- esnext.array
- esnext.symbol
- esnext.asynciterable
- esnext.intl
- esnext.bigint
- esnext.string
- esnext.promise

https://github.com/microsoft/TypeScript/tree/master/lib

####  ビルド

```:terminal
npm run build
```

####  動作確認
IE11でdist/index.htmlを開いて、JavaScriptが実行できているか確認します。


#### regenerator-runtime
必要に応じてregenerator-runtimeを使用します。
(ビルド時にCan't resolve 'regenerator-runtime/runtime'が表示されたとき)

##### regenerator-runtimeのインストール

```:terminal 
npm i -S regenerator
```

##### regenerator-runtimeのインポート

```:JavaScript
import  regeneratorRuntime  from  "regenerator-runtime" ;
 
//もしくは
//import  "regenerator-runtime / runtime.js" ;
```





##  環境を作らずにIE11対応する
あまり手をかけずにIE11対応をします。

### Babel
https://babeljs.io/
https://babeljs.io/repl

アクセスしたブラウザ用にTranspileできるようですが、肝心のIE11が非対応のようです・・・・。





### Polyfill
TranspileもBundleも不要で、Polyfillだけ使いたい場合はダウンロードしてきてHTMLから読み込めば使えるようになります。

例：intersectionObserver(https://github.com/w3c/IntersectionObserver/tree/master/polyfill)

```:index.html
<script src="intersection-observer.js"></script>
```

#### Fastly Polyfill

JavaScriptのPolyfillを配信しているサービスです。
※当然ですが、外部から読み込むので、polyfill.ioで障害が発生してしまったらPolyfillは無効になります。

下記URLで必要な機能を検索して、そのPolyfillを使えるURLを取得できます。
https://polyfill-fastly.io/


```:index.html
//ES2019の全polyfill取得
<script src="https://polyfill-fastly.io/v3/polyfill.min.js?features=es2019"></script>
 
//fetch機能だけのpolyfillを取得
<script src="https://polyfill-fastly.io/v3/polyfill.min.js?features=fetch"></script>
```