Vue CLI3 を使って、IE11でも動作するWeb Componentsを作ってみた



# TL;DR: 
標準OSがWindows7 、標準ブラウザはIE11という環境はまだまだ残っていると思います。
既存システムの機能追加の際にコンポーネント志向にしたいけれども、React, Vue, Angularにはできないような環境にIE11でも動作するWeb Componentsはどうでしょうか？
作り方をメモしました。



# Setup

## Installation

まずはVue CLI3のインストールから

[Installation | Vue CLI 3](https://cli.vuejs.org/guide/installation.html)


```shell
npm install -g @vue/cli
# OR
yarn global add @vue/cli
```

完了したらVersionを表示してインストール完了チェック

```shell
vue --version
```

`vue serve` `vue build`を使うためにアドオンを追加

```shell
npm install -g @vue/cli-service-global
```



## Vueプロジェクト作成

### vue create

vue create コマンドでプロジェクトを作成する。

```
vue create first-component
```

以下のようにプリセットを使うか、マニュアルで作成するか選択を促される。

```shell
Vue CLI v3.2.1
? Please pick a preset: (Use arrow keys)
> default (babel, eslint)
  Manually select features
```

ひとまずここはデフォルトのプリセット(babel, eslint)を使う。
しばらく待つと完了する。

```shell
🎉  Successfully created project first-component.
👉  Get started with the following commands:

 $ cd first-component
 $ yarn serve
```



### プロジェクト起動確認

yarn serveコマンドで起動する。

```shell
cd first-component
yarn serve --open
```

以下のような画面が出たら成功してる。

<img src='https://qiita-image-store.s3.amazonaws.com/0/49910/6d3852b9-ba68-3559-9ec9-532d39005dda.png' width='300px' /> 


### Using the GUI

以下コマンドでGUIベースで確認等ができるようだが、ここでは割愛する。

```
vue ui
```



# web-component化

それでは実際にweb-component化をやってみよう。

## 1. ビルドコマンドの変更


とはいえ、難しいことはなく、package.jsonのbuildを以下のように変更する。

```js:package.json
  "scripts": {
    "build": "vue-cli-service build",
  },

    ↓ 
  "scripts": {
    "build": "vue-cli-service build --target wc --name my-first-component",
  },

```

※ `my-first-component`は自由な名前に置き換えてよい。


## 2. ビルド

`yarn run build`コマンドでコンポーネントを作成する

```shell
yarn run build
```

しばらく待つとdistフォルダ配下にコンポーネントが作成される。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/49910/51dc8b66-6566-a68d-6645-f5eb09b128e5.png)


## 3. ビルド結果確認
demo.htmlの中身は以下になっていて、`<my-first-component>`タグだけで構成されている。

```html:demo.html
<meta charset="utf-8">
<title>my-first-component demo</title>
<script src="https://unpkg.com/vue"></script>
<script src="./my-first-component.js"></script>

<my-first-component></my-first-component>
```


demo.htmlをChrome等のブラウザで開いてみると`<my-first-component>`タグだけで当初に起動確認した画面が表示されるはずである。

※ IE、Edgeでは表示されない。（まっしろ画面になる）

<img src='https://qiita-image-store.s3.amazonaws.com/0/49910/6d3852b9-ba68-3559-9ec9-532d39005dda.png' width='300px' /> 





# IE11、Edge対応

IE11でもWeb Componentを使うことが目的でしたが、[VueのWeb Componentsの説明には](https://cli.vuejs.org/guide/build-targets.html#web-component)以下のようにIE11に非対応とはっきり書いてあります。

>Note on Compatibility
>Web Component mode does not support IE11 and below.  [More details](https://github.com/vuejs/vue-web-component-wrapper#compatibility)


さらに[Vue.js における次のイテレーションの計画 - IE11 サポート](https://jp.vuejs.org/2018/10/01/plans-for-the-next-iteration-of-vue-js/#IE11-%E3%82%B5%E3%83%9D%E3%83%BC%E3%83%88)にもIE11には今後サポートと書いてあります。（2018.12.27現在）

> TL;DR: サポートされる予定ですが、Vue 2.x と同じリアクティブ制限を持つ別のビルドになります。


さて、どうしたものかというところで、Babelとpolyfillの登場です。

## babel


### 1. babel/coreの追加

```shell
yarn add --dev @babel/core @babel/cli
```



### 2. babel pluginモジュールの追加

モジュールを追加します。

追加モジュールは以下

*  babel-plugin-transform-custom-element-classes
*  babel-plugin-transform-es2015-shorthand-properties
*  babel-plugin-transform-es2015-template-literals
*  @babel/plugin-transform-arrow-functions
*  @babel/plugin-transform-regenerator


```shell
yarn add --dev babel-plugin-transform-custom-element-classes babel-plugin-transform-es2015-shorthand-properties babel-plugin-transform-es2015-template-literals @babel/plugin-transform-arrow-functions @babel/plugin-transform-regenerator
```


### 3. babel.config

babel.config.jsに以下のようにプラグインを使うように追加します。

```js:babel.config.js
module.exports = {
  presets: [
    '@vue/app',
  ],
  plugins: [
    'transform-custom-element-classes',
    'transform-es2015-shorthand-properties',
    'transform-es2015-template-literals',
    "@babel/plugin-transform-arrow-functions",
    "@babel/plugin-transform-regenerator"
  ]
}
```


### 4. prebuildの追加

package.jsonのscriptsに`prebuild`を追加します。
これにより、`vue-wc-wrapper.js`のES6形式をIE11でも実行可能なJSに変更します。

```js:package.json
  "scripts": {
    ...
    "prebuild": "babel node_modules/@vue/web-component-wrapper/dist/vue-wc-wrapper.js -o node_modules/@vue/web-component-wrapper/dist/vue-wc-wrapper.js",
    
    "build": "vue-cli-service build --target wc --name my-first-component",
    ...
    
  },
```



例えば

```
const camelize = str => {...}

は以下のように変換されます
var camelize = function camelize(str) {};
```


### 5. ビルド

`yarn run build`コマンドでビルドします。

```shell
yarn run build
```

dist配下にコンポーネントとdemo.htmlが作成されます。


## polyfill

IE11で実行可能な形にビルドできましたが、このままでもIE11では動作しないので、polyfillを読み込みます。

demo.htmlに以下を追加します。

```html
<script src="https://unpkg.com/core-js-bundle@3.0.0-alpha.1"></script>
<script src="https://unpkg.com/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
<script src="https://unpkg.com/vue"></script>
```

以下のようになります。

```html:demo.html
<meta charset="utf-8">
<title>my-first-component demo</title>
<script src="https://unpkg.com/core-js-bundle@3.0.0-alpha.1"></script>
<script src="https://unpkg.com/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
<script src="https://unpkg.com/vue"></script>
<script src="./my-element.js"></script>

<my-element></my-element>
```

## 実行

IE11で起動すると以下の画面が表示されます。

<img src='https://qiita-image-store.s3.amazonaws.com/0/49910/6d3852b9-ba68-3559-9ec9-532d39005dda.png' width='300px' /> 



必要に応じてdemo.htmlを以下のように変えてもよいでしょう。

```html:demo.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>my-first-component demo</title>
    <script src="https://unpkg.com/core-js-bundle@3.0.0-alpha.1"></script>
    <script src="https://unpkg.com/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
    <script src="https://unpkg.com/vue"></script>
    <script src="./my-first-component.js"></script>
</head>

<body>
    <my-first-component></my-first-component>
</body>
</html>
```

## 確認用フォルダ作成

distはビルドの度に再作成されるので、確認用フォルダを作成してみます。
dist-previewフォルダを作成し、index.htmlを作成

```html: index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>my-first-component demo</title>
    <script src="https://unpkg.com/core-js-bundle@3.0.0-alpha.1"></script>
    <script src="https://unpkg.com/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
    <script src="https://unpkg.com/vue"></script>
    <script src="../dist/my-first-component.js"></script>
</head>

<body>
    <my-first-component></my-first-component>
</body>
</html>
```



# リポジトリ

ソースは↓のStep１に置きました。

[sugasaki/vue-cli3-webcomponent](https://github.com/sugasaki/vue-cli3-webcomponent)


# 参考

[Build Targets | Vue CLI 3](https://cli.vuejs.org/guide/build-targets.html#web-component)

[IE Support · Issue #31 · vuejs/vue-web-component-wrapper](https://github.com/vuejs/vue-web-component-wrapper/issues/31)