Fusion.jsを触ってみる

[Fusion.js](https://fusionjs.com/)とは、Uber社が今年8月に発表したオープンソースのJavaScriptフレームワークで、「プラグインベースのユニバーサルWebフレームワーク」と称されています。2018年10月現在、スターの数はまだ600いくつと応援したくなるフレームワークです。個人的に注目度が高いので触ってみました。

# アプリケーションを動かす
まずは、プログラム全体のエントリーポイントとなるクラスであるfusion-coreとReactを組み合わせたプレーンなFusion.jsアプリケーションを作成してみます。

ディレクトリを作り、必要なパッケージをインストールしていきます。

```
$ mkdir fusion-app
$ cd fusion-app
$ yarn add fusion-core fusion-cli react react-dom
```

`package.json`にスクリプトを追加します。

```package.json
// ...
"scripts": {
    "dev": "fusion dev",
    "test": "fusion test",
    "build": "fusion build",
    "build-production": "fusion build --production",
    "start": "fusion start"
  }
// ...
```

エントリーポイントとなる`src/main.js`を作成します。

```src/main.js
import React from 'react';
import ReactDOM from 'react-dom';
import { renderToString } from 'react-dom/server';
import App from 'fusion-core';

const el = <h1>Hello fusion!</h1>;

const render = el =>
  __NODE__
    ? `<div id="root">${renderToString(el)}</div>`
    : ReactDOM.render(el, document.getElementById('root'));

export default function () {
  return new App(el, render);
}
```

早速アプリケーションを走らせます。

```
$ yarn run dev
```

自動でブラウザが開き`localhost:3000`が立ち上がります。

# Pluginを追加する
前述の通り、Fusion.jsの特徴は**プラグインベース**のフレームワークということで、簡単にカスタムプラグインを作ることができます。お作法通り、簡単なプラグインを作ってアプリケーションに登録してみます。

コンソールにログを出力するだけのプラグインを作成します。

```plugins/console-logger.js
import { createPlugin } from 'fusion-core';

export default createPlugin({
  provides: () => {
    return console.log('Hello from plugin!');
  }
});
```

`src/main.js`に追記して、アプリケーションにプラグインを登録します。

```src/main.js
import ConsoleLoggerPlugin from '../plugins/console-logger';
import App from 'fusion-core';

export default function () {
  const app = new App(...);
  app.register(ConsoleLoggerPlugin);
  return app;
}
```

ターミナルとブラウザの開発コンソールを確認すると、レンダリングのたびにログが出力されるようになります。

# プラグイン利用の拡張
プラグイン利用の拡張として、Tokenという機能を用いたDependency Injection（依存性の注入）があります。DI Tokenをつくることで、Tokenがラベルのような働きをしてプラグイン同士に依存関係を作ることができます。

`plugins/console-logger.js`を一部書き換えます。

```plugins/console-logger.js
import { createPlugin } from 'fusion-core';

export default createPlugin({
  provides: () => {
    return log => console.log(log);
  }
});
```

DI Token登録のしかたは以下です。

```src/main.js
import ConsoleLoggerPlugin from '../plugins/console-logger';
import { LoggerToken } from 'fusion-tokens';
import App from 'fusion-core';

export default function () {
  const app = new App(...);
  app.register(LoggerToken, ConsoleLoggerPlugin);
  return app;
}
```

ここではトークンの名前を`LoggerToken`として登録したので、これがラベルとなって他のプラグインで使うことができるようになります。仮に`logger`が必要なプラグインがあった場合、以下のように`LoggerToken`としてラベリングされたログ出力メソッドをもったプラグイン`ConsoleLoggerPlugin`を呼び出し、`logger`にマッピングして使うことができます。

```plugins/datetime-logger.js
import { createPlugin } from 'fusion-core';
import { LoggerToken } from 'fusion-tokens';

export default createPlugin({
  deps: {
    logger: LoggerToken,
  },
  provides: ({ logger }) => {
    logger(new Date());
  },
});
```

上のプラグインをアプリケーションに登録します。

```src/main.js
import ConsoleLoggerPlugin from '../plugins/console-logger';
import { LoggerToken } from 'fusion-tokens';
import App from 'fusion-core';

export default function () {
  const app = new App(...);
  app.register(LoggerToken, ConsoleLoggerPlugin);
  app.register(DatetimeLoggerPlugin);
  return app;
}
```

再度ターミナルとブラウザの開発コンソールを確認すると、レンダリングのたびに現在日時が出力されるようになります。

まだMiddlewareやMemoizationなど触れていない機能もあるのでおいおいやっていきたい。