VueプロジェクトにStorybookを入れてIE対応にする




# 環境 
*  Vue CLI 3
* Storybook
* IE11以上のブラウザ、Chrome

## ソース
[sugasaki/storybook-vue-firststep-ie11](https://github.com/sugasaki/storybook-vue-firststep-ie11)



# Vueプロジェクトのセットアップ


## Vue CLI のインストール

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

参考:  [Vue CLI 3](https://cli.vuejs.org/)


## プロジェクトの作成

CLI版とGUI版と2通りある


```shell
vue create project-name
# OR
vue ui
```

ここではCLI版`vue create`　のデフォルトで進める

```shell
vue create storybook-vue-firststep-ie11
```

```shell
Vue CLI v3.2.1
┌───────────────────────────┐
│  Update available: 3.4.0  │
└───────────────────────────┘
? Please pick a preset: (Use arrow keys)
> default (babel, eslint)
  Manually select features
  
省略
  
🎉  Successfully created project storybook-vue-firststep-ie11.
👉  Get started with the following commands:
```

## 起動確認

```shell
yarn serve
```

起動すればOK
![image](https://qiita-image-store.s3.amazonaws.com/0/49910/876bf8da-f872-9506-d59d-81f9307fa416.png)



### Storybookを入れる

```shell
npx -p @storybook/cli sb init
```

この処理で、.storybookフォルダと、src/storiesフォルダが作成される

![image](https://qiita-image-store.s3.amazonaws.com/0/49910/c354878a-b49f-281e-f031-4efdb6f70b45.png)


package.jsonに storybookスクリプトが追加されているのを確認

```js:package.json
  "scripts": {
    "storybook": "start-storybook -p 6006",
    "build-storybook": "build-storybook"
```

### Storybookを実行する


```shell
npm run storybook
# or
yarn storybook
```



Storybookが起動すればOK。（この時点ではEdgeやIEでは何も表示されない）
![image](https://qiita-image-store.s3.amazonaws.com/0/49910/ca809293-f93f-756e-c6ed-5f8b987e0e03.png)


#### Vue

StorybookでVueを表示するライブラリを追加

```shell
yarn add --dev @storybook/vue
```


### Add vue, babel-core, and babel-loader

Storybook依存関係を入れる。

```shell
yarn add --dev babel-loader vue-loader vue-template-compiler
yarn add --dev @babel/core babel-preset-vue
```




### Create the NPM script

`package.json`
Storybook起動のためのスクリプトに ` -c .storybook` オプションを追加
 
>ストーリーブックはいくつかの異なる方法で設定できます。 それが、configディレクトリが必要な理由です。 configディレクトリとして.storybookを記載した上記のNPMスクリプトに-cオプションを追加しました。


```js:package.json
{
  "scripts": {
   # Add
    "storybook": "start-storybook -p 6006 -c .storybook",
  }
}
```

詳しくはマニュアル参照
[Storybook for Vue](https://storybook.js.org/basics/guide-vue/#create-the-config-file)



# Story設定ファイル 

表示されたStory画面の設定は`src/stories/index.js`にあります。
以下、便宜上、①と②表記を追加しました。

```js:index.js
import React from 'react';

import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import { linkTo } from '@storybook/addon-links';

import { Button, Welcome } from '@storybook/react/demo';

// ①
storiesOf('Welcome', module).add('to Storybook', () => <Welcome showApp={linkTo('Button')} />);

//②
storiesOf('Button', module)
  .add('with text', () => <Button onClick={action('clicked')}>Hello Button</Button>)
  .add('with some emoji', () => (
    <Button onClick={action('clicked')}>
      <span role="img" aria-label="so cool">
        😀 😎 👍 💯
      </span>
    </Button>
  ));
```



## 解説

### ①部分

```js:index.js
storiesOf('Welcome', module).add('to Storybook', () => <Welcome showApp={linkTo('Button')} />);
```

Storybook画面で表示される左サイドメニュー・Welcomeタブに`to Storybook`項目を追加する。
追加内容は、`@storybook/react/src/demo/Welcome.js`で定義された`Welcomeコンポーネント`を使う。
`Welcomeコンポーネント`にはshowAppという引数が設定されているので、showAppに対して`linkTo('Button')`を渡す。


### ②部分

```js:index.js
storiesOf('Button', module)
  .add('with text', () => <Button onClick={action('clicked')}>Hello Button</Button>)
```

Storybook画面で表示される左サイドメニュー・Buttonタブに`'with text`項目を追加する。

追加内容は、`@storybook/react/src/demo/Button.js`で定義された`Buttonコンポーネント`を使う。
`Buttonコンポーネント`には `children` `onClick` 引数が設定されている。
onClickに対して`@storybook/addon-actions`の`action('clicked')`を渡す。
childrenに対して `Hello Button` を渡す。


```js:index.js
  .add('with some emoji', () => (
```

も同様である。



## コンポーネントのStorybookへの追加

Custom Button を作成する


./src/components/の下に ButtonCustom.jsを作成し、
`./node_modules/@storybook/react/src/demo/Button.js`の内容をコピーします。

ついでに属性もちょっと変えてみます。
以下の例では背景色を青に、文字色を白に変えました。

```js:ButtonCustom.js
import React from "react";
import PropTypes from "prop-types";

const styles = {
  border: "1px solid #eee",
  borderRadius: 3,
  backgroundColor: "#3498db",
  cursor: "pointer",
  fontSize: 15,
  padding: "3px 10px",
  color: "#fff",
  margin: 10
};

const Button = ({ children, onClick }) => (
  <button onClick={onClick} style={styles} type="button">
    {children}
  </button>
);

Button.displayName = "ButtonCustom";
Button.propTypes = {
  children: PropTypes.node.isRequired,
  onClick: PropTypes.func
};
Button.defaultProps = {
  onClick: () => {}
};

export default Button;
```



### ButtonCustomを使う

src/stories/index.js　を編集します。

importを追加。

```js:src/stories/index.js
import ButtonCustom from '../components/ButtonCustom';
```

storiesOfを追加します。

```js:src/stories/index.js
storiesOf("ButtonCustom", module).add("blue back", () => (
  <ButtonCustom onClick={action("clicked")}>Hello Button</ButtonCustom>
));
```

保存してブラウザをリロードします。
以下のようにButtonCustomコンポーネントが表示されればOK

![image](https://qiita-image-store.s3.amazonaws.com/0/49910/86fcde45-7111-5be9-5f7c-abb9d34a2937.png)


## ButtonCustomの色を変更可能にする


CSSを変更できるボタンコンポーネントを作成します。


```js:ButtonCustomBackgroundColor.js
import React from "react";
import PropTypes from "prop-types";

const styles = backgroundColor => ({
  border: "1px solid #eee",
  borderRadius: 3,
  backgroundColor: backgroundColor ? backgroundColor : "#3498db",
  cursor: "pointer",
  fontSize: 15,
  padding: "3px 10px",
  color: "#fff",
  margin: 10
});

const Button = ({ children, onClick, backgroundColor }) => (
  <button onClick={onClick} style={styles(backgroundColor)} type="button">
    {children}
  </button>
);

Button.displayName = "ButtonCustom";
Button.propTypes = {
  children: PropTypes.node.isRequired,
  onClick: PropTypes.func
};
Button.defaultProps = {
  onClick: () => {}
};

export default Button;
```

以下のようにbackgroundColorを指定したタグをストーリーに追加します。

```js
    <ButtonCustomBackgroundColor
      onClick={action("clicked")}
      backgroundColor="#ff0000"
    >
```

以下のようになります。

```js:src/stories/index.js
storiesOf("ButtonCustom", module)
  .add("blue back", () => (
    <ButtonCustom onClick={action("clicked")}>Hello Button</ButtonCustom>
  ))
  .add("red back", () => (
    <ButtonCustomBackgroundColor
      onClick={action("clicked")}
      backgroundColor="#ff0000"
    >
      Button1
    </ButtonCustomBackgroundColor>
  ))
  .add("green back", () => (
    <ButtonCustomBackgroundColor
      onClick={action("clicked")}
      backgroundColor="#00ff00"
    >
      Button2
    </ButtonCustomBackgroundColor>
  ));
```




## 結果

３種類のボタンが出るようになりました。

![image](https://qiita-image-store.s3.amazonaws.com/0/49910/607eed94-ab29-9430-a472-c122455fbc46.png)
![image](https://qiita-image-store.s3.amazonaws.com/0/49910/a119f16e-06d5-dc98-2550-d4a9027bc178.png)
![image](https://qiita-image-store.s3.amazonaws.com/0/49910/bc45c134-c1d5-719b-41fa-619d85457f92.png)


# ソース

今回のソースは以下に保管しました。

[sugasaki/storybook-vue-firststep-ie11](https://github.com/sugasaki/storybook-vue-firststep-ie11)



# IE11対応

## polyfill
`@babel/polyfill`を入れる

```shell
yarn add @babel/polyfill
```

`.storybook/addons.js`の先頭に以下を追記

```js:.storybook/addons.js
import "@babel/polyfill";
```

参考

[Storybook not working in IE11 · Issue #4099 · storybooks/storybook](https://github.com/storybooks/storybook/issues/4099#issuecomment-428190677)



## .babelrc

ルート直下に、`.babelrc` を作成




```js
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false,
        "useBuiltIns": "entry",
        "targets": {
          "ie": "11"
        }
      }
    ]
  ]
}

```


```shell
yarn add babel-preset-es2015
```
これではだめだった


```shell
yarn add @babel/preset-env 
yarn add @babel/polyfill
```






### エンタープライズモード対策

IE11が入っていても、IE5、IE7モードで動作する、「親切な」ありがた迷惑な仕様がデフォルトになっている場合もある。

回避するためには、HTMLの出来るだけ先頭に`<meta http-equiv="X-UA-Compatible" content="IE=edge">` を入れる必要がある。

この一文は`<script>`タグよりも前でなければいけないが、

storybookで、Head内に
manager-head.htmlに記載した追加HTMLは、index.ejsの後に追記される。

/node_modules/@storybook/core/dist/server/templates/index.ejs


###

yarn storybook

node_modules/@storybook/core/dist/server/templates/index.ejs


`<head>`の直下に`<meta http-equiv="X-UA-Compatible" content="IE=edge">`を入れる

```html:index.ejs
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
```


## 

[Add Custom Head Tags](https://storybook.js.org/configurations/add-custom-head-tags/)

### manager
manager-head.html

>Your scripts will run before Storybook’s React UI. Also be aware, that this is an uncommon scenario and could potentially break Storybook’s UI. So use with caution.


###  preview
preview-head.html

>Storybook will inject these tags to the iframe where your components are rendered. So, these won’t be loaded into the main Storybook UI.