マイクロフロントエンドで使われている技術について

# 今回の記事について

マイクロフロントエンドにおいてどのような技術が使われているかを実例を交えながら紹介します。
2018年時点で実現方法は以下の2択。

- ifameを使う方法
- Web Components(Custom Elements)を使う方法


ただ、2019年に掲載された[Micro Frontends](https://www.martinfowler.com/articles/micro-frontends.html) によれば、

- Server-side template composition
- Build-time integration
- Run-time integration via JavaScript

の3つが追加されていた。
この３つの中で推奨されていたのがRun-time integration via JavaScriptだった。

今回は

- ifameを使う方法
- Web Components(Custom Elements)を使う方法
- Run-time integration via JavaScript

を紹介します。

残りの

- Server-side template composition
- Build-time integration

は次回以降に紹介します。

また、[マイクロフロントエンドの実現方法](https://qiita.com/tmiyajima/items/daa75bf6f8dd8f7bc9e1) もしくは[Micro Frontends](https://www.martinfowler.com/articles/micro-frontends.html)にも載っています。


# iframeを使う方法

## 概要
条件に応じてsrc属性を更新する方法。

### 長所 
- わかりやすい
- スタイルやグローバル関数が干渉しない

### 短所
- ほかの手法と比べて描画が遅い
- 柔軟性が低い

## ソースコード例

```html
<html>
  <head>
    <title>Feed me!</title>
  </head>
  <body>
    <h1>Welcome to Feed me!</h1>

    <iframe id="micro-frontend-container"></iframe>

    <script type="text/javascript">
      const microFrontendsByRoute = {
        '/': 'https://browse.example.com/index.html',
        '/order-food': 'https://order.example.com/index.html',
        '/user-profile': 'https://profile.example.com/index.html',
      };

      const iframe = document.getElementById('micro-frontend-container');
      iframe.src = microFrontendsByRoute[window.location.pathname];
    </script>
  </body>
</html>
```

（[Micro Frontends](https://www.martinfowler.com/articles/micro-frontends.html)より） 



## 実例
Spotifyが以前ifameを用いてマイクロフロントエンドに取り組んでいた。（現在はすべてReact Reduxに移行）


# Web Components(Custom Elements)を使う方法
## 概要
React,Angular,Vue.jsなどで作られたSPA に対してそれぞれ Custom Elements を媒介に Micro Frontends を載せることができる。
各フレームワークの対応状況は [Custom Elements Everywhere](https://custom-elements-everywhere.com/) というサイトで確認することができる。Reactは100％対応できていない項目がある。

### 長所

- HTMLの標準技術で実現できる
- ブラウザの対応状況も改善され、IE以外のブラウザではほぼ対応している
![burauzataou.png](https://thinkings.qiita.com/files/4de28f90-c062-56f1-daed-00f6546a49e9.png)


### 短所

- フレームワークの対応状況が良くはない



## ソースコード例

### React内でWeb Componentsを使う場合

```javascript
class HelloMessage extends React.Component {
  render() {
    return <div>Hello <x-search>{this.props.name}</x-search>!</div>;
  }
}
```
### Web Components内でReactを使う場合

```javascript
class XSearch extends HTMLElement {
  connectedCallback() {
    const mountPoint = document.createElement('span');
    this.attachShadow({ mode: 'open' }).appendChild(mountPoint);

    const name = this.getAttribute('name');
    const url = 'https://www.google.com/search?q=' + encodeURIComponent(name);
    ReactDOM.render(<a href={url}>{name}</a>, mountPoint);
  }
}
customElements.define('x-search', XSearch);
```


### プレーンなHTMLを使う場合
[フロントエンドエンジニアは Micro Frontends の夢を見るか](https://engineering.mercari.com/blog/entry/2018-12-06-162827/)の 「Micro Frontends の実現方法」に書かれています。

# Run-time integration via JavaScript
## 概要
各マイクロサービスのコンポーネントを描画する関数を`<script>`で読み込み、
条件に応じて動的に画面描画する方法。

### 長所

- 柔軟
- コンポーネントが修正されても、コンテナアプリケーションのビルド・デプロイは不要

### 短所
- バンドルが重複しやすい

## ソースコード例

```html
<html>
  <head>
    <title>Feed me!</title>
  </head>
  <body>
    <h1>Welcome to Feed me!</h1>

    <!-- These scripts don't render anything immediately -->
    <!-- Instead they attach entry-point functions to `window` -->
    <script src="https://browse.example.com/bundle.js"></script>
    <script src="https://order.example.com/bundle.js"></script>
    <script src="https://profile.example.com/bundle.js"></script>

    <div id="micro-frontend-root"></div>

    <script type="text/javascript">
      // These global functions are attached to window by the above scripts
      const microFrontendsByRoute = {
        '/': window.renderBrowseRestaurants,
        '/order-food': window.renderOrderFood,
        '/user-profile': window.renderUserProfile,
      };
      const renderFunction = microFrontendsByRoute[window.location.pathname];

      // Having determined the entry-point function, we now call it,
      // giving it the ID of the element where it should render itself
      renderFunction('micro-frontend-root');
    </script>
  </body>
</html>
```

# 参考

- [マイクロフロントエンドの実現方法](https://qiita.com/tmiyajima/items/daa75bf6f8dd8f7bc9e1) 
- [Micro Frontends](https://www.martinfowler.com/articles/micro-frontends.html)

# 次回

Web Components(Custom Elements)を使う方法を詳しく