前置き
会社の勉強会資料になります(6/16発表)
フロントエンドの未来の話というか、色々なライブラリの紹介です
ほとんどが5月上旬くらいに書いた資料なので、
それ以降に変化があったライブラリについては、追記という形で資料の中にコメント入れてます
モジュールバンドラーの未来
モジュールバンドラーとは簡単に言うと、JavaScriptのビルドツールのことです
最近はフロントエンドでも、機能ごと・共通化などの理由によって、JSファイルを分けてコーディングをするので、
最終的にそれをまとめて、1個のJSにする必要がある
その時に使われるのが、モジュールバンドラー
有名どころのツール
みんな大好きwebpack
後は、rollupとかbrowserifyとか
ですが、、
これからの時代は
fuse-box
fuse-boxとは
webpackと同様なモジュールバンドラー
設定ファイルがシンプル
webpack.configの例 ↓
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で書くと ↓
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の場合
バンドル後が620kbくらいのファイルだと
初回ビルドが
1529ms
差分ビルドが
441ms
fuse-boxの場合
初回ビルドが
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
React Sketch.app
https://github.com/airbnb/react-sketchapp
※β版
つまり、SketchでUI作ってからコーディングするとは逆のアプローチ
Reactから作って、Sketch上にレンダリングするというやり方
使い所で言えば、例えば本番データなどをSketch上にレンダリングすることが容易にできるようになると思う
まとめ
使い所が難しい
react-sketchappのgithub上でも斬新な使い方を募集してるので、
思いついた方がいらっしゃったら、教えてあげてください
Vue.jsの未来
Vue.js十分小さいんだけど、さらにコンパクトなやつないかなー
Reactで言うpreact的なやつ
※preactとは、Reactの最低限の部分だけ残してたサブセット的ライブラリ
ゲーム作りたいから、軽さと速さにこだわりたい!
安心してください!
Moon
がありますよ!
Moonとは、Vue.jsのサブセット的ライブラリ
まだバージョン0.9
当初はpreactを目標として開発していた
以下のライブラリのサイズ比較を見ても、相当軽い
以下はTODOアプリの速度ベンチマーク
100項目追加・完了・削除の速度ベンチマーク?
Vue.jsに依存はしていないので、Moon単体で動く
IE9以降がPolyfill無しで動く
まとめ
preactもMoonも使ったことないので、紹介程度に留めますが
見た感じVue.jsのサブセットというよりかは、
「Vue.jsと似たAPIを提供している、軽量のまったく別のライブラリ」
と言った方が正しいかもしれません
Reactの未来
Reactの現行のバージョンは15系なのですが、ここにきて実は
Reactの内部のコードが大きく書き直されていることをご存知でしょうか?
そうです!
React Fiber
です!
https://github.com/facebook/react/tree/master/src/renderers
(fiberが置いてあるコード、この直下のdomとかnativeとかの下にそれぞれfiberコードが配置されている)
大幅なバージョンアップになりました
こちらは先日のF8というイベントで紹介されています
Facebookは、
Reactの既存バージョンと完全な後方互換性を保ち、
DOMのレンダリング性能の大幅な改善などを行っている
(非同期でのレンダリングができる)
大まかなスケジュール
v15.5.x
現在の最新バージョン
※6/13にv15.6が出たのですが、この資料の中ではv15.5が最新として進めさせてください
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タグで囲んで、無理やり1つの要素するという作業が無くなる
動作サンプル
コード最適化の未来
皆さんも酔っぱらいながら、コード書くとだいたいこんな感じになると思います
(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もプンプンです
普通だと1個1個エラー見ながら直すと思うのですが、、、
そこに
Prettier
をドーーン!
Prettierとは
前回の勉強会でも少し話しましたが、JSのコードフォーマッタです
Go言語やってる人は、gofmtみたいなものと思ってください
インストール
yarn global add prettier
今回は試すだけなので、globalで入れてる
実行
prettier --write src/sample.js
※writeを付けないと、ファイルを上書きせずに結果だけコンソール上に出す
結果
(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;
})();
すごく綺麗になりました
まだだ、、
まだ終わらんよ!!
さらに
Prepack
をドーーン!!
Prepackとは
・Facebook製のJSをAOT(事前)コンパイルするツール
・その際にコードの最適化を行う
・今年のGWらへんで公開されたばっかりのツール
インストール
yarn global add prepack
今回は試すだけなので、globalで入れてる
実行
prepack src/sample.js --out src/output.js
※先程のPrettier結果後のsample.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する前のやつ
(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個になってる!
すごいね
ESLintとPrettierが喧嘩せずに動いてほしいです
ESLint側でPrettierを設定しましょう
以下のプラグインを設定してあげることで、ESLintのルールとしてPrettierを追加できる
yarn add prettier eslint-plugin-prettier eslint-config-prettier --dev
{
・・・
"extends": [
"prettier"
],
"plugins": [
"prettier"
],
・・・
}
webpackにもeslint-loaderを設定しておく
module.exports = {
・・・
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.js$/,
use: 'eslint-loader',
exclude: /node_modules/,
enforce: 'pre'
},
]
}
・・・
}
先程のコードをwebpackで実行
webpack
(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;
})();
エラーがだいぶ減りましたね
つまり、Prettierされたものに対して、ESLintが走っているということです
残ったエラーはPrettierでは対応できないESLintエラーなので、手動で直しましょう
PrepackがES6以降で書いたやつでも動いてほしいです
PrepackはES6の変換に対応していない
公式のロードマップを見ると、ES6に対応するのはまだ先だと思うので
Prepackで実行する前に、Babel等でトランスパイルしてあげる必要がある
今回はbabel-loaderを装備したwebpackにPrepackを組み込んでみる
prepack-webpack-plugin
というプラグインを利用する
yarn add prepack-webpack-plugin --dev
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
(() => {
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;
})();
成功しました
Prepackもされた!
アロー関数もfunctionに変換された!
(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をするので
当然ビルドする速度は落ちるのですが、どのくらい違うのか見てみました
使用するコードは、先程のコード
だいぶ遅い
けど、ファイルサイズを見てもかなり最適化されたのは分かる
そのうち速度は改善されるかもしれませんが、、
今後、速度に問題が残れば、ローカル開発時には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に対応された
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もいける
Weex
アリババ製のVue.js構文のサポートしているNativeアプリのフレームワーク
Vue.js版ReactNativeのようなものだと思う
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でデータ駆動型プログラムを実現するライブラリ
先日の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もレスポンスは以下となる
{
"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はコンポーネント
第2引数はGraphQLを使って取得するデータ
コンポーネントで使うサーバサイドのデータが宣言的に取得できる
(必要なものだけ宣言して取れる)
5/19追記
v1.0.0リリースされた