2019/06/06

Create React Appを少し遠回りしてはじめよう

Reactのボイラープレートとして利用されるCreate React Appを使えばすぐにReactのコードを書いていくことができます。しかし、少し遠回りをして中で何が行われているか見てみましょう!

Create React Appを少し遠回りしてはじめよう

Create React App で始めるReactを理解する

この講義から実際にReactに触れていきます! 前の講義で、vscodenode.jsのインストールがすでに完了していると思いますが、この講義ではReactを始めるときに使用するcreate-react-appというコマンドラインツールを少し掘り下げていきたいと思います。

このコマンドラインツールはfecebookが開発したもので、ワンコマンドでReactを使うことができる環境をセットアップできます。

このツールができるまではReactを使おうとするとモジュールバンドラーやトランスパイラ(後ほど説明するので今はなんのことを言っているかわからなくても問題ありません)の設定が必要でしたが、このツールを使うことでそれらの設定をすっ飛ばしてすぐにReactのコンポーネントを書いていくことができます。

さらにこのツールを利用して開発を効率的に行えますし、ビルド時に最適化も行ってくれます。

これは大変ありがたいことですが、この講義では実際にそのコマンドを使ってセットアップした後に、このツールには何が含まれていて、どんなことをやってくれるのかを実際に見ていきましょう。

遠回りにはなりますが、create-react-appで作ったReactのWebアプリの動作の仕組みがわかることで、何をしているのかわからない部分を減らし、自信を持って開発ができるようになると考えています。


Create React App ではじめたアプリの動作の仕組み

私たちはcreate-react-appを使ってセットアップしたプロジェクトでwebpackbabel,PostCSSなどを意識せず利用していますがそれらを一つづつみていきます。

まずはコマンドを打ってはじめのReactのWebアプリを作成してみましょう!(react-scriptsは3.0.1のバージョンを使っています。)

$ npx create-react-app my-app

また、下記のコマンドを打つことで雛形のアプリを起動して確認することもできます!

$ cd my-app
$ npm run start

(Ctrl + Cで停止できます。 )

create-react-app の雛形

さっそくコンポーネントをガシガシ書いていきたい気持ちを抑えて遠回りしていきましょう。


モジュールハンドラーのwebpackはなにをしてくれているのか

webpack

内部的にwebpackというものを使っていますが、webpackとはウェブコンテンツを構成するファイルをまとめてくれます。一緒に動作をみていきましょう。

まずはmy-appにできたフォルダを確認してみましょう。下記のようなフォルダの構成になっていますよね?

my-app
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│   ├── favicon.ico
│   ├── index.html
│   └── manifest.json
└── src
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── index.css
    ├── index.js
    ├── logo.svg
    └── serviceWorker.js

publicフォルダーからみていきましょう。

public/favicon.icoはスキップします。

public/manifest.jsonはホーム画面へ追加する際に、より細かな指定をするための記述です。 PWAを作成する際にこちらのファイルを記述していくことになると思いますが、今回はReactのWebアプリにフォーカスしたいのでスキップします。

次にpublic/index.htmlを開いてみましょう。
いろいろとコメントがありますが、このファイルのbodyタグにはidrootdivタグしかないことがわかると思います。

これだと真っ白な画面じゃんと思う気持ちを置いておいて、このアプリをビルドしてみましょう。

$ npm run build

ビルドが終わったらもう一度フォルダを確認してみましょう。

buildというフォルダが新たに追加されていると思います。

create-react-appで生成したプロジェクトでビルドを実行するとbuildというフォルダに成果物が出力されることがわかります。

buildフォルダを開いてみると、先ほどpublicフォルダにあったindex.htmlfavicon.ico,manifest.jsonがあることがわかります。これはcreate-react-appの内部の実装を見ればわかるのですが、build時にpublicフォルダーの内容をbuildフォルダにコピーしています。

次にbuild/index.htmlのファイルの内容をみていきましょう。

ビルド時に最適化され無駄な文字が削除されているので、少しみにくいのですがフォーマットして確認すると、先ほどpublicフォルダで確認したindex.htmlと違いをいくつか見つけられると思います。

bodyタグの末尾にscriptタグが挿入されていますね?

なので、ウェブサーバーにbuildフォルダを配置した時に空のdivタグではなく、なにかしらのjsファイルが読み込まれReactのコンポーネントが表示されるのです。

次に、読み込んでいるstatic/js/のファイルを見に行ってみましょう。

下記の2ファイルについて簡単に説明させてください。 (runtime~main.[hash].jsのファイルはwebpackランタイムロジックの小さな塊ですのでスキップしてOKです。

  • [number].[hash].chunk.js

    • このコードはsrcディレクトリ配下でインポートしたnode_modulesのアプリケーション外のライブラリのコードが含まれています。(現時点ではReactのコードが含まれています。)
  • main.[hash].chunk.js

    • このファイルはApp.jsなどのsrcディレクトリ配下のアプリケーションのコードが含まれます。

このようなファイルが生成されるのはwebpackがsrc/index.jsをスタート地点として依存関係の解析を行い、必要なものを最適化しまとめてくれているからです。

そして、さきほどのbodyタグの末尾にscriptタグが挿入されている話に戻りますが、これも実はwebpackのプラグインのhtml-webpack-pluginというものが行っています。

実際、普通にWebアプリを作っている場合は、これらの動作についてはwebpackの中に設定として書かれているため、あまり意識する必要はなく、なんとなくwebpackがいろいろとやってくれているんだな〜と思っていただく程度でOKですが、私たちがアプリケーションを書く際にwebpackの恩恵に直接触れる部分があります。 それはES6モジュールのエクスポートとインポートです。

src/App.jsの最後の行の部分のexport default App;としている部分が、エクスポートのことで、 インポートはsrc/index.jsをみてみてましょう。コードの1行目から5行目に書かれているimport App from './App';と書かれている部分です。

この部分はこのプロジェクトにおいてはwebpack無しでは書くことはできません。 またまた先ほどの話に戻りますが、このプロジェクトはwebpackがsrc/index.jsをスタート地点にしてそれらの依存関係をまとめてstatic/js/....chunk.jsを作成すると言いましたが、実際には依存関係はこのようにインポートとエクスポートで書いていきます。

webpackのことをモジュールバンドラーと説明しましたがイメージがつきましたでしょうか?様々なファイルをまとめてくれるのでモジュールバンドラーです。また、他のファイルを見てもらえればわかりますが、jsファイルだけでなく、css,svgファイルなどもインポートして使うことができます。

また、開発用のwebサーバーにもwebpackのwebpack-dev-serverというものを使っています。

このおかげでコードを書き換えたときに毎回ビルドしなくてもファイルやリソースファイルを更新すると即座に反映してくれる機能をもっています。 実際にwebpack-dev-serverを使った処理を確認してみましょう。

$ npm run start

サーバーが立ち上がりますので、src/App.jsの文字を書き換えて、保存してみましょう。変更がすぐに反映されましたでしょうか?変更するたびに更新されるため、サクサク開発できます。

再度確認ですが、webpackはsrc/index.jsから始まった依存関係をまとめてくれ、その参照をpublic/index.htmlに挿入してくれるということがわかりました。*

また、開発時にはその処理をソースコードに変更があるたびに継続して行なってくれるため、書き換えた内容が即座反映されるということがわかりました。

このようにファイルを分割することができるのでコンポーネントごとにファイルを分け、モジュールとして利用できます。


トランスパイラーのBabelはなにをしてくれているのか

babel

内部的にBabelというものを使っていますが、BabelとはJavaScriptのコードを新しい書き方から古い書き方へと変換するために使われているツールです。

なぜトランスパイルするのか

トランスパイルとはソース・トゥ・ソースコンパイラなどとも言われますが、このケースではJavaScriptをJavaScriptに変換します。

なぜそんなことが必要なのかというと、効率的に開発を行うためです。あまり想像したくないですが、やろうと思えばES6なしでReactのWebアプリを開発することは可能です。 しかし、Babelを使用することでここに書かれているES6という新しいバージョンのJavaScriptの機能を使うことができます。

また、JSXというJavaScriptを拡張した書き方ができます。

最終的にブラウザで動かすことのできるJavaScriptになりますが、Babelでのトランスパイルを前提にすることで、便利な機能や美しい見た目で効率的に開発することが可能になります。

動作をみていきましょう。 例えば下記のようなコードを書いてみましょう。

src/index.js
const log = msg => console.log(msg);
log('Hello Word!')

constというのはES6の機能で一度定義したものに再代入を許可しないという機能があります。また、=>はアローファンクションと言ってfunction式をより短く記述できる、代替構文です。これらは通常ブラウザ上では動きません。

ではビルドしてみましょう。

$ npm run build

さきほど動作を確認しましたが、webpackがバンドルしてくれるので/buildconst=>で検索すればOKです。(constの後に半角スペースを入れないとconstructorがヒットするので注意)

検索にヒットしたのは...chunk.js.mapではないでしょうか?

このファイルはソースマップファイルと言って、コンパイルされた難読化したコードを元のソースコードファイルから参照できるようにするマッピングの目的で利用されるため実行はされません。ということは実行されるjsファイルにconst=>が含まれないということです。

新しい書き方から古い書き方へとトランスパイルされていることが確認できました。 (先ほど書いたconst=>varfunctionに置き換えられています。)

トランスパイルを行うタイミングはwebpackがバンドルするときにjsファイルやReactコンポーネントをロードしますがそのときに変換しています。

(create-react-appのデフォルトの設定ではInternet Explorer 9, 10, 11にはpolyfillというものが必要です。このコースでは目的にしていないため一旦スキップします。)

(create-react-appではES6に加えてここに記載されている機能もサポートしています。)


CSSパーサーのPostCSSはなにをしてくれているのか

postcss

内部的にPostCSSというものを使っていますが、PostCSSはCSSのパーサーでPostCSSプラグインと組み合わせてCSSに変更を加えるツールです。

create-react-appではPostCSSプラグインのAutoprefixerというものを利用しています。 Autoprefixerは必要なCSSベンダープレフィックス(-webkit-や-ms-)を付与してくれます。

これが何をしてくれているのか実際にみていきましょう。

src/App.cssの中に下記のApp-logoというクラスがあります。

.App-logo {
  animation: App-logo-spin infinite 20s linear;
  height: 40vmin;
  pointer-events: none;
}

プロパティとしてCSS3のanimationが使用されています。

先ほどbabelの説明でビルドしたままで結構ですので、 /build/static/css/...chunk.cssを確認してみましょう。 これもwebpackによって最適化されているのでフォーマットしてから確認しましょう。

先ほど確認したApp-logoというクラスが下記のように下記変わっていることが確認できます。

.App-logo {
  -webkit-animation: App-logo-spin 20s linear infinite;
  animation: App-logo-spin 20s linear infinite;
  height: 40vmin;
  pointer-events: none;
}

ベンダープレフィックスが付与されていることが確認できます。

こうすることで開発時にCSSプロパティに応じて必要なベンダープレフィックスなどを意識せず効率的に開発を行うことができます。

この変更が加えられるタイミングもbabelと同様です。webpackがバンドルするときにCSSファイルもロードしますがそのときにベンダープレフィックスを付与しています。


まとめ

簡単にではありましたが、create-react-appで何をしてくれているのかを確認しました。

かえって混乱してしまいましたか?ゆっくり一つずつを理解していけば大丈夫です。そもそもなにを行なっているかを知らないよりは次のステップに進んでいます。

振り返ると、create-react-appはすぐに開発を行うことができるだけでなく、開発が効率的に行えるように、かつブラウザの対応状態などをうまく隠蔽して開発に専念できるような工夫がしてあることがわかりました。

あ、今回はスキップしましたが、上記で紹介したもの以外にもProgressive Web Appを作るためのアセットや、単体テストを行うためのツール、コードの静的解析ツールも入っています。

これ以上の説明は一旦やめておきます。(笑)

それではまた次回。

...

Share