フロントエンドの未来の話

## 前置き
会社の勉強会資料になります（6/16発表）

フロントエンドの未来の話というか、色々なライブラリの紹介です

ほとんどが5月上旬くらいに書いた資料なので、
それ以降に変化があったライブラリについては、追記という形で資料の中にコメント入れてます

---

## モジュールバンドラーの未来

モジュールバンドラーとは簡単に言うと、JavaScriptのビルドツールのことです

最近はフロントエンドでも、機能ごと・共通化などの理由によって、JSファイルを分けてコーディングをするので、
最終的にそれをまとめて、1個のJSにする必要がある

その時に使われるのが、モジュールバンドラー

---

有名どころのツール

みんな大好き`webpack`

後は、rollupとかbrowserifyとか

ですが、、

---

これからの時代は

<font color="Red">**fuse-box**</font>

https://github.com/fuse-box/fuse-box

---

## fuse-boxとは
webpackと同様なモジュールバンドラー

### 設定ファイルがシンプル

webpack.configの例　↓

```js:webpack.config.js
module.exports = {
  entry: [
    './src/index.html',
    './src/main.ts'
  ],
  output: {
    path: `${__dirname}/dist`,
    filename: 'app.js'
  },
  devServer: {
    port: 4445
  },
  devtool: 'source-map',
  module: {
    rules: [
      {
        test: /\.tsx$/,
        use: 'ts-loader',
        exclude: /node_modules/
      },
      {
        test: /\.html$/,
        use: 'html-loader',
        exclude: /node_modules/
      },
      {
        test: /\.scss$/,
        use: [
          'css-loader',
          'sass-loader'
        ]
      },
      {
        test: /index.html$/,
        use: 'file-loader?name=[name].[ext]'
      }
    ]
  }
};
```

これをfuse-boxで書くと　↓

```js:fuse.js
const fsbx = require('fuse-box');

const fuseBox = fsbx.FuseBox.init({
  homeDir: 'src/',
  sourcemaps : true,
  outFile: './dist/app.js',
  plugins: [
    [
      fsbx.SassPlugin({ outputStyle: 'compressed' }),
      fsbx.CSSPlugin({})
    ],
    fsbx.TypeScriptHelpers(),
    fsbx.JSONPlugin(),
    fsbx.HTMLPlugin({ useDefault: false })
  ]
});

fuseBox.devServer('>main.ts **/*.html', {
  port: 4445
});
```

シンプル！！

--- 

## fuse-boxの特徴として
・TypeScriptはデフォルトサポート
⇒公式に「FuseBox loves typescript」って書いてる

・HotModuleReplacement(HMR)はデフォルトサポート
⇒画面を再描画しなくても、コードの変更をブラウザに反映してくれるやつ

・なんとかloaderとか色々インストールしなくていい
⇒fuse-box内製のプラグインを使う

・めっちゃ速い！

---

### webpackの場合

<img width="427" alt=" 2017-05-10 15.42.44.png" src="https://qiita-image-store.s3.amazonaws.com/0/168197/603cce9d-b442-5fb6-a7d9-e3bb463fa221.png">

バンドル後が620kbくらいのファイルだと

初回ビルドが
1529ms

差分ビルドが
441ms

---

### fuse-boxの場合

<img width="321" alt=" 2017-05-10 15.46.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/168197/5f71488c-b459-1743-5a52-ffc222c8288a.png">
<img width="337" alt=" 2017-05-10 15.46.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/168197/f6b8a4a4-e071-3e1d-deb7-f3a642dfc594.png">

初回ビルドが
426ms!!!

差分ビルドが
17ms!!!!1

超速い
なんかバンドル後のファイルも軽くなってる（255.9kb）

5/11追記
fuse-box2.0がリリースされました
https://medium.com/fusebox/fusebox-2-0-the-beast-reborn-e4ec0443b782
・更にパフォーマンスを向上させた
・メソッドチェインで設定を書けるようにした
・新しいプラグインの追加
・ドキュメントの更新
など
後、fuse-box2.0は「The beast reborn（生まれ変わった獣）」って言ってます

---

## まとめ
実務で使うのは、まだ厳しいかもしれません
私はあまりがっつり使ってませんが、バグがけっこう多いとのこと

ドキュメントとかは、当時はまだ充実していない感じでしたが
今はリリースして半年くらい経ってるので、多少充実しているはず

5/11追記
fuse-box2.0が出たタイミングでサイトも一新されたので、使いやすくなってるかも！

---

## デザインの未来
今のフロントエンドの開発は`Sketch`でデザインして、それ見ながらコンポーネント設計して作るのが最近のトレンド

`Sketch`はエンジニアがデザインを作りやすくすることを意識している気がする
Photoshopよりも難易度が低くシンプルな為、デザインデビューしたエンジニアも増えたはず

しかし、、

---

 「俺達はReactからSketchをレンダリングする」 by Airbnb

<font color="Red">**React Sketch.app**</font>

https://github.com/airbnb/react-sketchapp
※β版

---

つまり、SketchでUI作ってからコーディングするとは逆のアプローチ
Reactから作って、Sketch上にレンダリングするというやり方

使い所で言えば、例えば本番データなどをSketch上にレンダリングすることが容易にできるようになると思う

---

## まとめ
使い所が難しい

react-sketchappのgithub上でも斬新な使い方を募集してるので、
思いついた方がいらっしゃったら、教えてあげてください

---

## Vue.jsの未来
Vue.js十分小さいんだけど、さらにコンパクトなやつないかなー
Reactで言うpreact的なやつ
※preactとは、Reactの最低限の部分だけ残してたサブセット的ライブラリ

ゲーム作りたいから、軽さと速さにこだわりたい！

---

安心してください！

<font color="Red">**Moon**</font>

がありますよ！

https://github.com/KingPixil/moon

---

Moonとは、Vue.jsのサブセット的ライブラリ
まだバージョン0.9
当初はpreactを目標として開発していた

以下のライブラリのサイズ比較を見ても、相当軽い

<img width="164" alt=" 2017-05-11 15.53.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/168197/1e53514f-3675-5ff2-ca97-eceb0065e3a7.png">

以下はTODOアプリの速度ベンチマーク
100項目追加・完了・削除の速度ベンチマーク？

<img width="431" alt=" 2017-05-11 15.58.56.png" src="https://qiita-image-store.s3.amazonaws.com/0/168197/cc75092a-c505-81df-3a54-850e38054884.png">

Vue.jsに依存はしていないので、Moon単体で動く

IE9以降がPolyfill無しで動く

---

## まとめ
preactもMoonも使ったことないので、紹介程度に留めますが
見た感じVue.jsのサブセットというよりかは、
「Vue.jsと似たAPIを提供している、軽量のまったく別のライブラリ」
と言った方が正しいかもしれません

---

## Reactの未来

Reactの現行のバージョンは15系なのですが、ここにきて実は

Reactの内部のコードが大きく書き直されていることをご存知でしょうか？

---

そうです！

<font color="Red">**React Fiber**</font>

です！

https://github.com/facebook/react/tree/master/src/renderers
（fiberが置いてあるコード、この直下のdomとかnativeとかの下にそれぞれfiberコードが配置されている）

---

大幅なバージョンアップになりました
こちらは先日のF8というイベントで紹介されています

Facebookは、
Reactの既存バージョンと完全な後方互換性を保ち、
DOMのレンダリング性能の大幅な改善などを行っている
（非同期でのレンダリングができる）

### 大まかなスケジュール
v15.5.x
現在の最新バージョン
<font color="Red">※6/13にv15.6が出たのですが、この資料の中ではv15.5が最新として進めさせてください</font>

v16
今年の夏頃リリース予定
このバージョンのデフォルトはまだ同期レンダリング
15.5と後方互換性があり

v17
未定
このバージョンでデフォルトで非同期レンダリングとなる

---

## 今やること（v15.5でやっておくこと）
Reactのバージョンアップを怠らずにやっていれば、v15.5へのバージョンアップ時に
システムが動かないレベルのエラーが出ることは無いと思う

ただし、`React.PropTypes`と`React.createClass`を使っているとログに警告が出ているはず
これらの機能はv16では、削除される機能
それを予め、v15.5の段階で教えてくれている

依存ライブラリも含めて、削除予定の機能を使っていると警告を出すので
この警告が消えたタイミングがv16へ移行する準備が整ったということになる

なので自分のシステムでは早めに対応しておき、依存ライブラリは対応されるのを待ちましょう

・React.PropTypes
私のチームでは、`prop-types.PropTypes`に置き換えました
ただし、型チェックはTypeScriptやFlowなどを使うのが推奨されているようです

・React.createClass
こちらは私のチームでは使ってなかったのですが、使っている場合は
class構文などで置き換えることが推奨されているようです

---

見てほしいサイト
http://blog.koba04.com/post/2017/04/25/a-state-of-react-fiber/
https://html5experts.jp/shumpei-shiraishi/23265/

こちらのページにとても詳しく・分かりやすく書いてあります
実際に使う前の予習として、夏までに読んでおきましょう

個人的に面白いなーって思った新機能は
renderの戻り値を文字列や配列で返せる点
React(JSX)経験者には分かると思うが、返却する要素が複数あった場合に
divタグで囲んで、無理やり１つの要素するという作業が無くなる

---
　
<img width="606" alt=" 2017-06-13 19.27.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/168197/c22ba75d-9563-201e-ff75-daea89b3b553.png">

---

## 動作サンプル

https://koba04.github.io/react-fiber-resources/examples/

---

## コード最適化の未来
皆さんも酔っぱらいながら、コード書くとだいたいこんな感じになると思います

```js:sample.js
(function () {
   function hello() { return 'hello'; }
  function world() { return 'world' }
          global.s = hello() + ' ' + world()
})();




(function () {
  function fibonacci(x) {
      return x <= 1 ? x : fibonacci(x - 1) + fibonacci(x - 2);
  }
      global.x = fibonacci(23)
})();

(function(){
  function fib(x) {
    return x <= 1 ? x : fib(x - 1) + fib(x - 2);
  }
      var x = Date.now()
  if (x === 0) x = fib(10);
     global.result = x;
})();
```

ESLintもプンプン:anger:です

<img width="566" alt=" 2017-05-11 16.55.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/168197/ec810cce-4dd7-6745-209d-9067dbf06c9f.png">

普通だと1個1個エラー見ながら直すと思うのですが、、、

---

そこに

<font color="Red">**Prettier**</font>

をドーーン！

https://github.com/prettier/prettier

---

## Prettierとは
前回の[勉強会](http://qiita.com/kurosame/items/183a93bcc39d4c8c27d5#eslint%E3%81%AE%E5%B0%8E%E5%85%A5)でも少し話しましたが、JSのコードフォーマッタです
Go言語やってる人は、gofmtみたいなものと思ってください

### インストール
```
yarn global add prettier
```
今回は試すだけなので、globalで入れてる

### 実行
```
prettier --write src/sample.js
```
※writeを付けないと、ファイルを上書きせずに結果だけコンソール上に出す

### 結果
```js:sample.js
(function() {
  function hello() {
    return "hello";
  }
  function world() {
    return "world";
  }
  global.s = hello() + " " + world();
})();

(function() {
  function fibonacci(x) {
    return x <= 1 ? x : fibonacci(x - 1) + fibonacci(x - 2);
  }
  global.x = fibonacci(23);
})();

(function() {
  function fib(x) {
    return x <= 1 ? x : fib(x - 1) + fib(x - 2);
  }
  var x = Date.now();
  if (x === 0) x = fib(10);
  global.result = x;
})();
```

すごく綺麗になりました

---

まだだ、、
まだ終わらんよ！！

---

さらに

<font color="Red">**Prepack**</font>

をドーーン！！

https://github.com/facebook/prepack

---
## Prepackとは
・Facebook製のJSをAOT（事前）コンパイルするツール
・その際にコードの最適化を行う
・今年のGWらへんで公開されたばっかりのツール

### インストール
```
yarn global add prepack
```
今回は試すだけなので、globalで入れてる

### 実行
```
prepack src/sample.js --out src/output.js
```

※先程のPrettier結果後のsample.jsを読み込み、コードを最適化してoutput.jsで出す

### 結果
```js:output.js
(function () {
  s = "hello world";
  x = 28657;

  var _$0 = Date.now();

  if (typeof _$0 !== "number") {
    throw new Error("Prepack model invariant violation: " + _$0);
  }

  result = _$0 === 0 ? 55 : _$0;
})();
```

比較用　↓
Prepackする前のやつ

```js:sample.js
(function() {
  function hello() {
    return "hello";
  }
  function world() {
    return "world";
  }
  global.s = hello() + " " + world();
})();

(function() {
  function fibonacci(x) {
    return x <= 1 ? x : fibonacci(x - 1) + fibonacci(x - 2);
  }
  global.x = fibonacci(23);
})();

(function() {
  function fib(x) {
    return x <= 1 ? x : fib(x - 1) + fib(x - 2);
  }
  var x = Date.now();
  if (x === 0) x = fib(10);
  global.result = x;
})();
```

sは文字列が連結された状態になってる！
xは計算された状態になってる！
resultもかなり最適化されて、エラー処理も追加されてる！
functionも1個になってる！

すごいね:+1:

---

## ESLintとPrettierが喧嘩せずに動いてほしいです

ESLint側でPrettierを設定しましょう
以下のプラグインを設定してあげることで、ESLintのルールとしてPrettierを追加できる

```
yarn add prettier eslint-plugin-prettier eslint-config-prettier --dev
```

```json:.eslintrc
{
  ・・・
  "extends": [
    "prettier"
  ],
  "plugins": [
    "prettier"
  ],
  ・・・
}
```

webpackにもeslint-loaderを設定しておく

```js:webpack.config.js
module.exports = {
  ・・・
  module: {
    rules: [
      {
        test: /\.js$/,
        use: 'babel-loader',
        exclude: /node_modules/
      },
      {
        test: /\.js$/,
        use: 'eslint-loader',
        exclude: /node_modules/,
        enforce: 'pre'
      },
    ]
  }
  ・・・
}
```

先程のコードをwebpackで実行

```
webpack
```

```js:先程の酔っぱらいコード.js
(function () {
   function hello() { return 'hello'; }
  function world() { return 'world' }
          global.s = hello() + ' ' + world()
})();




(function () {
  function fibonacci(x) {
      return x <= 1 ? x : fibonacci(x - 1) + fibonacci(x - 2);
  }
      global.x = fibonacci(23)
})();

(function(){
  function fib(x) {
    return x <= 1 ? x : fib(x - 1) + fib(x - 2);
  }
      var x = Date.now()
  if (x === 0) x = fib(10);
     global.result = x;
})();
```

エラーがだいぶ減りましたね

<img width="504" alt=" 2017-05-11 18.58.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/168197/8cba853a-ca59-579f-2573-0a956ebd7996.png">

つまり、Prettierされたものに対して、ESLintが走っているということです
残ったエラーはPrettierでは対応できないESLintエラーなので、手動で直しましょう

---

## PrepackがES6以降で書いたやつでも動いてほしいです
PrepackはES6の変換に対応していない
[公式](https://prepack.io)のロードマップを見ると、ES6に対応するのはまだ先だと思うので
Prepackで実行する前に、Babel等でトランスパイルしてあげる必要がある

今回はbabel-loaderを装備したwebpackにPrepackを組み込んでみる
`prepack-webpack-plugin`というプラグインを利用する

```
yarn add prepack-webpack-plugin --dev
```

```js:webpack.config.js
const path = require('path')
const PrepackWebpackPlugin = require('prepack-webpack-plugin').default

module.exports = {
  entry: [
    path.join(__dirname, '../src/sample')
  ],
  output: {
    path: path.join(__dirname, '../dist'),
    filename: 'bundle.js',
    publicPath: '/'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: 'babel-loader',
        exclude: /node_modules/
      },
    ]
  },
  plugins: [
    new PrepackWebpackPlugin()
  ]
}
```

先程のコードをES6のアロー関数にしてwebpackで実行

```
webpack
```

```js:先程の酔っぱらいコード・アローバージョン.js
(() => {
   function hello() { return 'hello'; }
  function world() { return 'world' }
          global.s = hello() + ' ' + world()
})();




(() => {
  function fibonacci(x) {
      return x <= 1 ? x : fibonacci(x - 1) + fibonacci(x - 2);
  }
      global.x = fibonacci(23)
})();

(() => {
  function fib(x) {
    return x <= 1 ? x : fib(x - 1) + fib(x - 2);
  }
      var x = Date.now()
  if (x === 0) x = fib(10);
     global.result = x;
})();
```

成功しました

<img width="284" alt=" 2017-05-11 19.17.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/168197/1f429c00-8426-fa0e-8e71-423a02fdd5f0.png">

Prepackもされた！
アロー関数もfunctionに変換された！

```js:bundle.js
(function () {
  s = "hello world";
  x = 28657;

  var _$0 = Date.now();

  if (typeof _$0 !== "number") {
    throw new Error("Prepack model invariant violation: " + _$0);
  }

  result = _$0 === 0 ? 55 : _$0;
})();
```

---

## Prepackの速度に関して
いつものwebpackに加えて、Prepackをするので
当然ビルドする速度は落ちるのですが、どのくらい違うのか見てみました

使用するコードは、先程のコード

<img width="381" alt=" 2017-05-11 19.22.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/168197/1cf12268-d843-4303-3b53-f5a701cfd548.png">

だいぶ遅い
けど、ファイルサイズを見てもかなり最適化されたのは分かる

そのうち速度は改善されるかもしれませんが、、
今後、速度に問題が残れば、ローカル開発時にはPrepackを使わずに、
本番やステージングにてPrepackを適用するというやり方になるかもしれません

ちなみにPrettierは速いよ！

---

## おまけ
①AtomやVimでもPrettier使いたい！

あるよ！

Atom
https://github.com/prettier/prettier-atom
Vim
https://github.com/heavenshell/vim-prettier

他にもあるかも
保存した時にPrettierが走る感じ
てかエディタがPrettierに対応していたら、設定するべき！

---

②CSS置いていかれてない？？

Prettier for CSS
https://github.com/stylelint/stylelint/issues/2532

こちらのstylelintのissuesでも盛り上がってますが、Prettierが良すぎたので、
Prettier並のCSSコードフォーマッタが出る日も近いかもしれません

5/20追記
こんなプルリク上がってた
Initial CSS support
https://github.com/prettier/prettier/pull/1636

6/2追記
PostCSS経由でのCSS/SCSS/LESSに対応された:tada:
https://github.com/prettier/prettier/releases/tag/1.4.0

---

## まとめ
Prettierは実用で使えるレベルだと思う
エディタが対応していたら、入れてみたらどうでしょうか
不安ならESLintも併用しておけば、品質に関しては担保できる

Prepackはこれからが期待されるツール
事前に計算処理をコンパイルの段階でやっておくことで、ブラウザで実行時のパフォーマンスアップが大いに期待できる
Prepackが単体で動いて、ES6以降の変換もできて、速く動いたら、かなり熱いコンパイルツールですね

---

## さいごに
いくつかライブラリやツールを紹介しましたが、気になったものはありましたでしょうか？

正直どれも使わなくても、やっていけるのですが、、
気になったライブラリを見つけたら、軽く使って検証する癖を付けておくと、
今後システム選定をする際に、選択肢が増えて、良い判断ができ、より良いシステム開発ができると思います

---

## おまけ
以下は話そうと思ったけど、調べる前に資料が大きくなったので、削りました
簡単に概要だけ紹介だけしときます

### ReactXP
Microsoft製のクロスプラットフォーム開発用ライブラリ
例えばReactNative使っていても、プラットフォームごとに個別に実装が必要なUI部分はある
ReactXPは抽象なクロスプラットフォーム層を用意し、そこにView定義・スタイル・アニメーションを定義しておけば
各プラットフォームで共有できるようにしている
（継承とか、オーバーライド的なことをやるのだろうか？）

ReactとReactNativeをサポートしているので、WebもNativeもいける

https://github.com/Microsoft/reactxp

---

### Weex
アリババ製のVue.js構文のサポートしているNativeアプリのフレームワーク
Vue.js版ReactNativeのようなものだと思う

https://github.com/alibaba/weex

6/13追記
こちらの勉強会でWeexについて話されるみたいなので、聞いてきます
https://vuejs-meetup.connpass.com/event/58071/?utm_campaign=&utm_source=notifications&utm_medium=email&utm_content=title_link

---

### Relay（&GraphQL）
Facebook製のReactでデータ駆動型プログラムを実現するライブラリ

https://github.com/facebook/relay

先日のF8でも既存のRelayに新機能＋パフォーマンス改善を行った
「Relay Modern」という新しいRelayが発表された

Relayを使うとサーバサイドから取得したデータをReactのpropsに渡すことが簡単にできるようになる
つまり、以下のことをRelayが全て行う
・アクションを検知
・GraphQLを使って、サーバへリクエスト
・サーバからのレスポンスをpropsに設定

※GraphQLを簡単に説明
RESTに比べて、直感的にリクエストを投げれる
以下はそれぞれのリクエストの例

REST
`GET /users?id=1`

GraphQL

```
{
  users(id: "1") {
    id
    name
    email
  }
}
```

RESTもGraphQLもレスポンスは以下となる

```json
{
  "users": [
    {
      "id": 1,
      "name": "hoge",
      "email": "hoge@example.com"
    },
    {
      "id": 1,
      "name": "foo",
      "email": "foo@example.com"
    }
  ]
}
```

以下はRelayの公式の例

```
class HelloApp extends React.Component {
  render() {
    const {hello} = this.props.greetings;
    return <h1>{hello}</h1>;
  }
}

HelloApp = Relay.createContainer(HelloApp, {
  fragments: {
    greetings: () => Relay.QL`
      fragment on Greetings {
        hello,
      }
    `,
  },
});
```

第1引数のHelloAppはコンポーネント
第２引数はGraphQLを使って取得するデータ

コンポーネントで使うサーバサイドのデータが宣言的に取得できる
（必要なものだけ宣言して取れる）

5/19追記
v1.0.0リリースされた