#webpack
#React
#babel
#flow
#eslint

Babel, webpack, flow & eslintを使ってReactの開発環境を構築する

目的

Reactとは何ぞやという概念的な記事や実際の書き方を説明した記事は多い。
しかし、Reactでアプリケーション開発を実際にするにあたって具体的にどうすればいいのかという情報は断片的で初心者には全体像が掴めない。

例えば、モジュールバンドラーが必要だと知っている人は、webpackを設定する記事を調べれば分かるが、そもそもReactの開発環境の構築にそれが必要だと知らなければその記事にたどり着くことはできない。
Reactというフレームワークをインストールしさえば動かせるというものではなく、また動いたとしても実際の開発ではflowやeslintを使うことが多い。実際の開発環境は様々なライブラリが協働しているのが常である。

これらの背景を踏まえて、この記事では
Reactの開発環境を実際に0から構築する過程を通じて、開発環境では何が使われているかという全体像と、
それらの設定はどうすればいいかを経験的に理解すること

を目的としている。

したがって、全体像の構成要素ごとに詳細な説明はしない。むしろ掘り下げる必要性自体に気づくことを目指している。

全体の流れとしては、

  • Node.jsのインストール
  • Yarnの使い方
  • webpackの設定
  • Babelの設定
  • Reactのインストール
  • eslintの設定
  • flowの設定

について順を追って説明する。

環境

利用したバージョン

> node -v
v8.11.1

> yarn info webpack version
4.7.0

> yarn info eslint version
5.0.0-alpha.2

> yarn info flow-bin version
0.71.0

ファイル構成

react-experiment
│  .babelrc
│  .eslintrc
│  .flowconfig
│  .node-version
│  package.json
│  webpack.config.js
│  yarn.lock
└─ src
    ─ index.js
    ─ sub.js
└─ dist
    ─ bundle.js
    ─ index.html

Node.jsのインストールとバージョン指定

Node.jsとは

  • JavaScriptをサーバーサイドで実行するための環境
  • パッケージのインストール、ビルド、テストなどの実行環境としても使われる

nodenv

nodenvとは?
nodenvとはNode.jsのバージョンを管理するためのツール。
指定のバーションをインストールしたり、利用するバージョンを切り替えたりできる。

他にはndenvやnodebrewなどがあるが、nodenvは.node-versionファイルを参照して、そこに記載されたバージョンに自動で切り替えてくれるので便利だったためこちらを利用。

実際のインストール方法はこちらの記事を参考にした。
Nodenv環境を用意する - Qiita

nodenvでnode.jsをインストールする

// すでにnodebrewを使っている場合はパスを外す(でないとそちら優先されることがある)
// 今回は8.11.1を使用するためにインストール
nodenv install 8.11.1
nodenv rehash
// ローカル環境で利用するバージョンを指定する
nodenv local 8.11.1
// バージョンの確認
nodenv version
=> 8.11.1
node -v
=> 8.11.1

Yarn

Yarnとは?

Yarnとはパッケージマネジャーの一つ。
概要を理解するために押さえておくべきなのは、package.jsonとyarn.lockの二つ。依存関係とバージョン | Yarn

  • package.json: インストールしたパッケージのバージョンなどが管理されている
  • yarn.lock: 直接編集することはないが、パッケージ自体が依存しているパッケージ(サブパッケージ)も含めて管理されている

基本的なコマンド

まずプロジェクトの新規作成をする。

yarn init

主に使うのはyarn addコマンド。yarn add | Yarn

Yarnはパッケージへの依存関係をグループ化して管理する。
主に利用されるのは、dependenciesdevDependenciesの二つ。
詳しくはこちらのページを参照されたし。

yarn add <pachage...>dependenciesとしてインストールされる。

これれは通常の依存関係か、もしくはコードの実行時に必要なもの(例えば React または ImmutableJS など)です。

yarn add <pachage...> [--dev/-D]devDependenciesとしてインストールされる。

これらは開発用の依存関係です。開発ワークフローのどこかで必要で、コードの実行時には必要のない依存関係です(例:Babel もしくは Flow)。

versionの指定方法

package.jsonに記載されるパッケージのバージョン。
Versions of dependencies | Yarn
Caret Ranges (^) はゼロ以外の最初の桁の数字を上げない限りのバージョンアップを許す。
^2.3.1 => >=2.3.1 < 3.0.0
^0.5.1 => >=0.5.1 < 0.6.0
^0.0.7 => >=0.0.7 < 0.0.8

webpack

webpackとは?

JavaScriptやHTML, CSSはブラウザ上で描画されるために処理、実行される。
この辺りの仕組みの概要を知りたければこちらの本の前半の章を読むと分かりやすい。
Webフロントエンド ハイパフォーマンス チューニング | 久保田 光則 | 工学 | Kindleストア | Amazon

そのためには、サーバにあるJavaScriptなどのファイルをロードする必要がある。
しかし、これらのファイルは通常複数あり、全てファイルを読み込み、処理をするとユーザは延々と待ち続けることになる。そのために、それらのファイル(モジュール)をまとめて一つにし、ブラウザ(JavaScriptエンジンなど)が実行しやすいようにビルドしたファイルを作る必要がある。それを実現するのがモジュールバンドラー。

そしてwebpackはアクセスしたページで利用されているファイルを読み込み一つのファイルにすることができる。

しかし、昨今ではフロントエンドの担う役割は年々増大しており、それに伴ってフロントエンドの占めるコードの割合も増大しているので、それを1つのファイルに落とし込むとなると、ファイルサイズはかなりのものになります。(中略) そのファイルを初回アクセス時にユーザーに読み込ませるとなると、無関係のコードも含まれる1つのファイルの読み込みを、ユーザーは延々と待たされることになります。(中略) 理想はアクセスしたページに依存関係のあるコードだけが含まれるファイルが読み込まれ、初期ローディングが必要最小限に抑えられることでしょう。これらの問題を解決するために既存のモジュール・バンドラーを拡張することも試みられたそうですが、目的を果たすことができずwebpackを開発するに至ったことが記されています。
これから始めるwebpack - webpackの基礎知識 | CodeGrid

webpackの設定をする

主にこの記事を参考にした。サルでもわかるwebpack 4.5入門 - 古い情報に騙されずに学ぼう - ICS MEDIA

webpackをインストールする

yarn add -D webpack webpack-cli

webpack.config.jsを設定する
複数のJavaScriptファイルを集約したJavaScriptファイルをエントリーポイントという。

module.exports = {
  // エントリーポイント
  entry: `./src/index.js`,

  // ビルドされた実行ファイルの出力設定
  output: {
    //  出力ファイルのディレクトリ名
    path: `${__dirname}/dist`,
    // 出力ファイル名
    filename: 'bundle.js'
  },
};

webpackでバンドルしてみる

JavaScriptのバンドルファイルを作る

// ./src/index.js
import { hello } from './sub';
hello();

// ./src/sub.js
export function hello() {
  alert('Hello World');
}

実際にビルドされたファイル。
設定でモードを選ぶことでソースマップ(どこのソースコードから作られたか)などの情報も付与して出力することができる。
デフォルトだと本番用に圧縮された状態で出力される。

実際にビルドしてみる。

> yarn run webpack
Hash: 302f700e2ea67728f905
Version: webpack 4.7.0
Time: 259ms
Built at: 2018-05-05 17:19:47
    Asset       Size  Chunks             Chunk Names
bundle.js  587 bytes       0  [emitted]  main
Entrypoint main = bundle.js
[0] ./src/index.js + 1 modules 91 bytes {0} [built]
    | ./src/index.js 40 bytes [built]
    | ./src/sub.js 51 bytes [built]

./dist/bundle.jsに出力される。

// ./dist/bundle.js 
!function(e){var r={};function t(n){if(r[n])return r[n].exports;var o=r[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=e,t.c=r,t.d=function(e,r,n){t.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:n})},t.r=function(e){Object.defineProperty(e,"__esModule",{value:!0})},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,"a",r),r},t.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},t.p="",t(t.s=0)}([function(e,r,t){"use strict";t.r(r),alert("Hello World")}]);

Babel

Babelとは?

ECMAScriptのトランスパイラ。flowTypeやJSX、ECMAScript2015 (ES6) などのソースコードをサポートしていないブラウザが存在するので、実行できるように取り除いたり、それ以前の書き方に変換したりすることができる。
こちらのページで試すことができる。
そして、これらが変換された後にwebpackがバンドルする。

flowtype付きのES2015の記法を使って書いたもの。

// @flow

const inc = (x: number):number => { x + 1 };

const newArray: Array<numebr> = [...[1, 2, 3], 4, 5];

それらがES2016以前の書き方に変換される。

"use strict";

var inc = function inc(x) {
  x + 1;
};

var newArray = [1, 2, 3].concat([4, 5]);

Babelを使う

主にこの記事を参考にした。最新版で学ぶwebpack 4入門 - BabelでES2017環境の構築(React, Vue, Three.js, jQueryのサンプル付き) - ICS MEDIA

インストールする

yarn add -D babel-core babel-loader babel-preset-env babel-preset-react

webpack.config.jsを設定する

// webpack.config.js
module.exports = {
  ...

  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          {
            // Babelを利用する
            loader: 'babel-loader',
            options: {
              presets: [
                ['env', { 'modules': false }]
              ]
            }
          }
        ]
      }
    ]
  }
};

React

reactをインストールする

yarn add react react-dom

webpackの設定をする

// webpack.config.js
module.exports = {
  ...
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          {
            loader: 'babel-loader',
            // Babel のオプションを指定する
            options: {
              presets: [
                ['env', { 'modules': false }],
                // React の JSX を解釈
                'react'
              ]
            }
          }
        ],
        // node_modules は除外する
        exclude: /node_modules/,
      }
    ]
  }
};

babelの設定をする

// .babelrc
{
  "presets": ["react"]
}

webpack-dev-serverを使う
まずインストールする。

yarn add -D webpack-dev-server

webpackで起動させるサーバの設定を行う。

// webpack.config.js
module.exports = {
  entry: `./src/index.js`,

  ...

  devServer: {
    port: 3000,
    contentBase: 'dist'
  },

  module: {
    ...
  }
};

yarn run webpack-dev-serverhttp://localhost:3000/にアクセスすると表示されるようになる。

実際に書いてみる

// ./src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import HelloMessage from './sub';

class App extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello React!</h1>
        <HelloMessage
          message="with Babel & webpack"
        />
      </div>
    );
  }
}
ReactDOM.render(<App />, document.getElementById('react-root'));

// ./src/sub.js
const HelloMessage = (props) => {
  <h3>{props.message}</h3>
};
export default HelloMessage;

// ./dist/index.html
<!doctype html>
<html lang="en">
  <body>
    <div id="react-root"></div>
    <script src="/bundle.js"></script>
  </body>
</html>

表示される!

スクリーンショット 2018-05-05 17.57.46.png

eslint

eslintとは、JavaScritpやJSXの構文チェッカーのこと。
この記事などを見て設定をした。
ESLint 最初の一歩 - Qiita

インストールする。

yarn add -D eslint eslint-plugin-react

.eslintrcファイルでチェック時のルールを設定することができる。

// .eslintrc
{
  "parser": "babel-eslint",
  "plugins": [
    "flowtype",
    "react"
  ],
  "settings": {
    "flowtype": {
      "onlyFilesWithFlowAnnotation": true
    }
  },
  "parserOptions": {
    "sourceType": "module",
      "ecmaFeatures": {
      "jsx": true
    }
  },
  "env": {
    "browser": true,
      "node": true
  },
  "rules": {
    "quotes": [2, "single"],
      "strict": [2, "never"],
      "react/jsx-uses-react": 2,
      "react/jsx-uses-vars": 2,
      "react/react-in-jsx-scope": 2
  },
  "extends": [
    "eslint:recommended",
    "plugin:react/recommended",
    "plugin:flowtype/recommended"
  ]
}

flow

インストールと実行
JavaScritpを型定義するためのもの。こちらのサイトに従ってインストールできる。Installation | Flow

yarn add -D flow-bin
yarn run flow init
yarn run flow

基本設定
.flowconfigでバージョン指定や、チェック対象のファイルを指定できる。

// node_module以下はチェック対象外にする
[ignore]
.*/node_modules/.*

トランスパイル時に型定義されたコードを取り除く
balel-preset-reactにflowの型定義を取り除くプラグインが含まれている。

babelrcの設定をする。

// .babelrc
{
  "presets": ["react"],
}

eslintに型定義されたコードを通す
この記事を参考にした。flowの始め方 - Qiita

eslintと連携するにはbabel-eslinteslint-plugin-flowtypeをインストールする必要がある。
そうでないとeslintで引っかかる。

yarn add -D eslint-plugin-flowtype babel-eslint

.eslintrc.jsに以下を追加する。

//.eslintrc.js
{
  parser: 'babel-eslint',
  extends: ['plugin:flowtype/recommended'],
  plugins: ['flowtype'],
  settings: {
    flowtype: {
      onlyFilesWithFlowAnnotation: true,
    },
  },
  ...
}

flowを使って型定義をする。

// @flow

import React from 'react';

type Props = {
  message: string
};

const HelloMessage = (props: Props) => {
  return <h3>{props.message}</h3>;
};
export default HelloMessage;

参考