JavaScript
es6
webpack
React

React 入門 - webpack 導入編

React に入門するために webpack で一から開発環境を作ってみた話です

この記事を読むとわかること

  • React の導入前に最低限必要な周辺ツールの概要
  • 周辺ツールを入れるための webpack.config などの記述方法
  • フロントエンドの技術を把握する大変さ

動機

  • React プロジェクトの webpack を最新バージョンに上げたい
  • しかし webpack.config の記述方法が大幅に変わっている
  • さらに人の書いたコードを流用していたため解読できない箇所が多々ある
  • それなら習作を兼ねて一から再入門してみよう!

今回は理解を深めることが目的なので create-react-app のようなツールは使用しません

最低限必要なツールとは

以下のような要件が満たされる程度を想定しています :

  1. ビルドできる
    • npm モジュールを利用できる
    • コードの依存関係を解決できる
  2. スタイルシートや画像なども含めてビルドできる
    • SCSS でスタイルシートを記述できる
    • 小さな画像は data URI スキームで .js ファイルに埋め込める
  3. 開発中はファイル変更時に画面を自動でリロードできる
    • 確認するブラウザが複数個になっても全て自動でリロードできる
    • 開発ビルドと本番ビルドで設定を切り替えられる
  4. ビルド後のコードを適切な単位で分割できる
    • 巨大な .js ファイルが生成されるのを防げる
    • 必要なファイルを必要なタイミングで取得できる
  5. ビルド後のコードを圧縮できる
    • 生成される .js ファイルを難読化できる
    • 分割されたファイルから重複を取り除ける

一つ白状すると、ここまでは React とは何の関係もありません :innocent:

作業リポジトリ

これらの要件を満たすための実装内容と、本来の趣旨である React の導入方法については、SPA Starter リポジトリの Pull Requests から確認できます

それぞれのプルリクで具体的に何が実装されているのか、順番に追ってみましょう

ビルドの準備

#1 はビルドできるだけの最小構成です。
最小ではありますが、すでに以下のようないくつかの大切な機能を確認することができます :

  • 外部ライブラリ lodash への依存を解決できること
  • ビルドの出力先 ./distoutput.path によって設定できること
  • HtmlWebpackPlugin によってテンプレート index.html を外に切り出せること
  • そして npm run build でビルドできること

スタイルシートと画像の追加

#2 では以下の機能が追加されています :

スタイルを適用できるようになって、少しだけアプリケーションらしい形になってきました。SCSS を扱えるようになったのも現代的な感じがします。ただ、この時点ではまだ毎回ビルドしなければ確認できないので、残念ながら実用性はありません。

開発サーバの導入

#3 には以下のような内容が含まれています :

  • express による開発用サーバの追加
  • webpack-hot-middleware による自動リロード (hot reloading) の設定
  • npm run 時に環境変数を切り替えるために better-npm-run を追加
  • webpack-merge によって開発用と本番用の webpack.(dev|prod) を分割
  • clean-webpack-plugin によってビルド前に出力先を初期化
  • デバッグログ用の debug モジュール追加

ようやく自動リロードが実現されました。ファイルを変更するたびに独りでに画面が更新されるのはとても快適です。ビルド結果の最適化を除けば、もうなかなかの実用性があると言えるでしょう。

同時に、このあたりから webpack の設定ファイルが邪悪の片鱗を見せてくるようになります。設定が腐っていくのを防ぐためにも、適宜整理していきたいところです。

バンドルの分割

#4 ではファイルを分割して出力するための設定を加えています :

  • webpack.optimize.CommonsChunkPlugin によるファイル分割の設定
    • ./node_modules 配下のコードを vendor.[hash].js としてまとめる設定
    • webpack のブートストラップ処理を manifest.[hash].js としてまとめる設定
  • dynamic import によってファイルを遅延読み込みさせるサンプルコードの追加

import の単位を工夫することで「最初に開くページではスクリプトの読み込みを最小限にする」といった最適化を加えられるようになりました。また、たとえば滅多に更新されないライブラリと頻繁に変わるドメインロジックのファイルを分ければ、ブラウザキャッシュの効率化を図ることもできます。

ちなみに、この分割によって生じたそれぞれのファイル群はチャンク (chunk) とも呼ばれています。

出力結果の圧縮

#5 に含まれる内容 :

これらの設定を適用すると人にはほとんど読めないコードが出力されるようになります。そのため、もしもビルドによってどのようなコードが出力されているのか目視で確認したくなった場合、この設定を解除する必要があります。

React の導入

#6 でついに念願の React 導入に辿り着きました :

  • ブラウザで React を使うために reactreact-dom モジュールを追加
  • コンポーネントを hot reloading させるために module.hot.accept の記述を追加
  • JSX 記法をパースするために babel-plugin-transform-react-jsx の設定を追加
  • dynamic import を babel 経由でも利用できるように babel-preset-stage-0 の設定を追加

興味深いことに、今回は babel を使っていながら ES5 への変換は省いています。
2017-12 現在では (対象のブラウザを限定できるなら) ES6 のままで問題なく動かせるためです。

終わり

おつかれさまでした :tada:

これで SPA Startergit clone してから npm install するだけで、すぐに React による開発を始められるようになりました。もう複雑怪奇な webpack.config や各種ツールの導入について悩む必要はありません。create-react-app のようなブラックボックスに頼る必要もありません。暗号めいた謎の設定も残っていないので、今後のバージョンアップで立ち往生することもないでしょう。

以上。快適な React 開発を!