React.js Advent Calendar 2015 17日目の記事です。
Reactベースでプロジェクトを始めようと思うと、Boilerplateとしてreact-starter-kitやreact-static-boilerplateが見つかります。これらはReact以外のツールやライブラリを大量に利用している為、事前知識がないと何がどう動いているのか、何から調べれば良いのかを把握するのが難しかったりします。
この記事では、個人的にプロジェクト構成を作り始める前にざっくりと知っておきたかったと思う事前知識と、その学習リソースについてまとめようと思います。
2015年にWebフロントエンド開発トレンドについてキャッチアップをさぼっちゃったなー、という方がモダンな環境でReact開発をスタートする一助になれば嬉しいです。
以下、ES2015, Babel, Webpack, Fluxについて順に触れていきます。
ES2015 / ES6: ECMAScriptの新しい標準
ECMAScript 2015 (ES2015)は2015年6月に策定された新しいECMAScript標準です。ES6 Harmonyとしても知られていた為、未だにES6と呼ばれることもあります。細かいものも含めると多くの新仕様がありますが、従来の言語仕様 (ES5)と比べると、例えば以下のような重要な差異があります。
- class構文の導入
- arrow構文の導入
- let, constの導入
- import文によるモジュール読み込み
- Promiseの導入
個人的にザッと重要な変更を把握するのに速習ECMAScript6: 次世代の標準JavaScriptを今すぐマスター!が非常に読みやすく役に立ちました。
新しい標準が出てくるとブラウザの対応状況が気になってきますが、各ブラウザのES2015対応はまだまだです(ブラウザ対応状況)。しかしBabelを使うことで、ブラウザの互換性を気にすることなくES2015の多くの機能を利用することができます。
参考
Babel: ES2015なコードをES5に変換して使う
**Babel**のウェブサイトに行くと、Babel is a JavaScript compiler. Use next generation JavaScript, today.
と書いてありますが、要はES2015で書かれたコードをES5(従来のJavaScript)コードに変換してくれます。CoffeeScriptやTypeScriptみたいな挙動ですが、対象としているのが独自仕様からJavaScriptへの変換ではなく、最新仕様のJavaScriptから従来仕様へのJavaScriptへの変換になっています。ブラウザのES2015対応状況はまだまだですが、Babelを使うことでES2015の仕様を先取りしてコードを書きつつ、最終的に従来のブラウザで動作するJavaScriptファイルを得ることができます。
Babelの主な目的はECMAScriptの最新・次期標準(ES2015やその先のES201x)をカバーすることですが、それ以外にもReactを利用する上で非常によく使われる拡張記法である**JSX**にも対応していたり、更にPluginとしてその他の変換も記述できたりします。
BabelとReactを使ってプロジェクトを始めていくチュートリアルとしては、React.js Essentialsが非常に参考になりました。また余談ですが、Atomを使っている方はlanguage-babelを使うとES2015やJSXの構文に対応できます。
Babelがあるから安心!ということでES2015やJSXを使ってコードを書きまくった後に、JSファイル群をBabelで変換し、使ってるライブラリなども読み込みつつ最終的に実行可能なJSファイルを作ってくれるのがWebpackです。
参考
Webpack: 依存性解決とバンドル処理を自動化してくれるビルドツール
Webpackの役割を一言で表すのは難しいのですが、ビルドツールの一種だと思っていただくと分かりやすいです。Webpackは主に、ファイルの前処理と依存性の解決を行った上で、最終的にブラウザ上で実行されるJS / CSS / 画像ファイル等のアセットをバンドルしてくれます。以下に公式ウェブサイト上の概念図を引用します。
1. ファイルの前処理
例えばES2015で記述したJavaScriptファイルは、ブラウザ上で実行するためにはBabelで前処理する必要があります。他にもSASSやLESSを使ってスタイルを記述している際には最終的にそれらをCSSに変換する必要があります。Webpackではこれらの変換をバンドルの前処理として自動化することができます。
また、前処理として行えるのは変換だけではなく、例えばESLintでJSファイルを前処理することでLintが通らなかったら警告を出したりビルドを中断したりすることもできます。
2. 依存性の解決
Reactを使うか使わないかに関わらず、 SPA(Single Page Application)を作っているとサードパーティが提供するJS / CSSライブラリを利用したり、自身のソースコードも1つの巨大なJSファイルを書くというよりは色々なコンポーネントに分割されたソースコード群を管理することになると思います。
Webpackは各ファイルが他のどのライブラリやファイルに依存しているかを自動的に解決してくれます。それにより、ReactやBootstrapなどの外部ライブラリなどを利用しても、最終的にブラウザが読み込むアセットファイルにそれらすべてをバンドルしてくれます。
ところで、Webpackはこれらの依存ライブラリをnode_modules
ライブラリなどから読み込んで、最終的な出力ファイルにすべて埋め込んでくれます。そのため、従来ではバックエンドの依存性はpackage.json
に記述しnpmで、フロントエンドの依存性はbower.json
に記述しbowerで管理していましたが、最近はすべてnpmでまとめて管理するのがメジャーになってきました。
3. アセットのバンドル
Webpackは依存性を解決し、必要なファイルを前処理した上で、最終的にブラウザで実行可能なファイルを生成します。一番分かりやすい例としては、プロジェクト内のJSファイル、依存している外部ライブラリのJSファイルなどをすべてまとめてきて1つのJSファイルを生成できます。HTMLファイルからはそのJSファイルを1つ読み込むだけでアプリケーションが動作します。
GruntやGulpでファイルを結合するのと違う点として、Webpackはrequireやimportといった外部リソースの読み込みを自動的に処理するために、最終的なJSファイルにWebpackのランタイムも埋め込んでいたりします。
また、大規模なSPAになるとアプリケーション規模や依存するライブラリ規模も大きくなってくるため、すべてを1つのファイルにまとめてしまうと読み込みに時間がかかってしまう等の問題があります。そのため、Webpackではアプリケーションを1つのファイルにバンドルするだけではなく、いくつかのファイルに分割し、アプリケーションを実行していく中で必要になった部分だけを読み込んでいく、といった方法にも対応しています(公式ドキュメントのcode splittingを参照)。
Babel, SASS, LESSを使ってファイルをトランスパイルしたり、CSS内のimportなどを解決するとった処理は、**[loader]
(https://webpack.github.io/docs/loaders.html)**という仕組みで定義されます。色々なloaderは公式ドキュメントの[list of loaders](https://webpack.github.io/docs/list-of-loaders.html)に大量に記載してありますが、よく使われるloaderとして例えば以下のものがあります。
loader | 役割 |
---|---|
babel-loader | BabelでJSファイルを変換する。 |
sass-loader | SASSファイルをCSSに変換する。 |
eslint-loader | JSファイルをESLintして違反していたら警告を出力する。 |
css-loader | CSSファイルを読み込んで, 内部のimportやurl()などの依存性を解決する。 |
さて、Webpackもセットアップして、さぁReact使ってバリバリコード書くぞ!と思うと、大体のReactを使ったプロジェクトはFluxというアーキテクチャに沿って設計されているため、この概念を理解しないと全体設計が難しいです。
参考
Flux / Redux: アプリ状態管理の見通しを良くするアーキテクチャ
**Flux**はユーザインタフェースを開発する上でのアーキテクチャで、特定の実装を指すわけではなくMVCのようなコンセプトを置き換えるものです。Reactを使う上でFluxを採用しなければいけないわけではないですし、逆にFluxを採用してもReactを使わなければならないということでもありませんが、ReactベースのプロジェクトはFluxを採用しているケースが多いと思います。
Fluxの概要については公式ドキュメントが詳しいですが、MVCなどの既存の概念に詳しい方は以下の図を見るとイメージしやすいかもしれません(公式ドキュメントから引用)。
ユーザの操作などを起点にActionが生成され、 Dispatcher経由でそれがStore(アプリケーションの状態を管理)を更新し、その更新がViewに反映される、という流れがFluxの基本的な考え方になります。ReactはStoreの状態をViewと同期するために利用されます。
Flux自体はアーキテクチャなので、それを採用した様々なフレームワーク実装があります。有名なところだとFluxを提案しているFacebook自身がその参考実装を公開しています。また、2015/12/17現在のGitHub Star数を見てみると、**Redux**が頭ひとつ抜けているようです。様々なFlux実装については、色々なフレームワークが進化してきた流れをまとめたこちらの記事が非常に参考になります。また、各フレームワークのテイストを比較するにはこちらも参考になります。
Reduxは上図のようなFluxのアーキテクチャと完全に同じではないのですが、公式ドキュメントでRedux evolves the ideas of Flux, but avoids its complexity by taking cues from Elm.
と記載されているように、Flux実装の一つとしてReactと共に利用されることが多いフレームワークです。
Reduxのコンセプトは公式ドキュメントにまとまっていますが、アプリケーション全体で状態をImmutableな形で一元管理することで、状態変更を管理しやすくすることを目標としています。
参考
おわりに
ということで、過去、個人的に調べるのに時間がかかった部分について、詳細というよりは導入としてコンセプトを覚えていただくための説明を書いてみました。各セクションの最後に参考リンクを貼っておきましたので、実際に勉強をすすめる際には使っていただければ幸いです。