Webpackでリソースファイルを変換し、Hello React!

# **はじめに**
前回、[Reactを始める前に環境を整えよう/「npm/yarn」両者対応。](https://qiita.com/takuyanin/items/8e1442c213c5057a753a)という記事で、Reactを書き始める前段階の環境構築に関してまとめました。
その中でWebpackというものが出てきましたが、今回はそのWebpackを使って、「Hello React」をブラウザ上に表示したいと思います。

より詳しくWebpackについて知りたい方はこちらをご参考にしてみたください。
[WebpackのWebサイト](https://webpack.github.io/)

# **Webpackて何？**
Webpackとは、JavaScripやCSSなどのリソースファイルを1つにまとめたり、JSXのような特殊な記法で書かれたファイルを変換するツールです。
Webアプリ（Webサイト）は、さまざまなリソースファイルから構成されています。**リソースファイルには、JavaScriptやCSSファイルなどいろいろあります**。Webpackを使うと、それらを最適な形に作り替えることができます。

例えば、ホームページを作るためには、HTMLファイルだけでなく、CSSやJavaScript、画像やWebフォントなど、さまざまなファイルを用意する必要がありますよね。こうしたWebで必要なファイルをワンパッケージでまとめてくれる便利なものが`Webpack`です。また、Webpackは複数のJavaScriptファイルをまとめる高機能なモジュールバンドラーであることにより、WebページのHTTPリクエストの数を減らしたりすることができます。
さらに、Webpackは、複数のファイルを１つのメインファイルにまとめてくれるだけではなく、SassやLESSなどの CSSプリプロセッサー言語をコンパイルしてくれます。

つまり、高度なWebアプリケーションを作ろうとする際に非常に役立ちます。

<img width="1383" alt="webpack_module_bundler.png" src="https://qiita-image-store.s3.amazonaws.com/0/269862/f83d477e-b87d-00e2-0eb6-93f9365a51db.png">

# **WebpackでReact/JSXをビルドしてみよう**
早速、React/JSXをWebpackで変換する方法をご紹介します。
WebpackでReact/JSXのコンパイル環境を作る時は、次のような手順で行います。

1. `yarn init`でpackage.jsonを作成する
2. 必要なモジュールをインストールする
3. webpack.config.jsを作成する
4. ソースディレクトリ`src`と出力ディレクトリ`out`などを作っておく。
5. ソースコードを作成し、webpackコマンドでコンパイルする
6. Webサーバー上でコンパイル結果を確認する

## **1. `yarn init`でpackage.jsonを作成する**

webpack-appという名前のプロジェクトを開始するとします。

```
$ mkdir webpack-app
$ cd webpack-app/
$ yarn init
$ ls
package.json
```
`yarn init`実行後にはpackage.jsonが作成されていますね。

## **2. 必要なモジュールをインストールする**

続いて、必要なモジュールをインストールします。今回インストールするモジュールは、`Webpack`と`React`と`Babel`の３種類です。

```
$ yarn add webpack webpack-dev-server react react-dom babel-core babel-loader babel-preset-react babel-preset-env
yarn add v1.12.3
info No lockfile found.
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
warning " > babel-loader@8.0.4" has unmet peer dependency "@babel/core@^7.0.0".
[4/4] 📃  Building fresh packages...
success Saved lockfile.
success Saved 446 new dependencies.
info Direct dependencies
├─ babel-core@6.26.3
├─ babel-loader@8.0.4
├─ babel-preset-env@1.7.0
├─ babel-preset-react@6.24.1
├─ react-dom@16.6.3
├─ react@16.6.3
├─ webpack-dev-server@3.1.10
└─ webpack@4.26.0
info All dependencies
├─ @webassemblyjs/floating-point-hex-parser@1.7.11
├─ @webassemblyjs/helper-code-frame@1.7.11
...
...
✨  Done in 22.30s

$ ls
node_modules/	package.json	yarn.lock
```
`node_modules/`ディレクトリと`yarn.lock`ファイルが作成されましたね。

package.jsonの中身を確認してみましょう。

```package.json
{
  "name": "webpack-app",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "babel-core": "^6.26.3",
    "babel-loader": "^8.0.4",
    "babel-preset-env": "^1.7.0",
    "babel-preset-react": "^6.24.1",
    "react": "^16.6.3",
    "react-dom": "^16.6.3",
    "webpack": "^4.26.0",
    "webpack-dev-server": "^3.1.10"
  }
}
```

## **3. webpack.config.jsを作成する**
変換指示書となる設定ファイルを作ります。
Webpackの機能は豊富なので、実際にWebpackを使う時は、さまざまなオプションを付けます。
しかし、コマンドラインで全てのオプションを指定するのは大変なので、通常は、`webpack.config.js`という設定ファイルを作成し、これを変換指示書として利用します。

webpack.config.jsという名前で保存しておけば、コマンドラインから`webpack`とタイプするだけで変換作業を行うことができます。

```
$ touch webpack.config.js
```

以下のように編集しましょう。

```webpack.config.js
module.exports = {
  entry: './src/main.js',
  output: {
    filename: './out/bundle.js'
  },
  module: {
    rules: [
      {
        test: /.js$/,
        loader: 'babel-loader',
        options: {
          presets: ['react', 'env']
        }
      }
    ]
  }
}
```
このモジュールのルール指定では、WebpackのBabelプラグイン（babel-loader）を利用して、ECMAScriptとReactの変換を行うよう設定します。前回の投稿を読んでくださった方はお気づきかもしれませんが、　先ほどインストールしたモジュールでは`babel-preset-es2015`から`babel-preset-env`に変わっております。
`babel-preset-env`とはなんぞやという方へ、

babel-preset-envとは

> Babel preset that automatically determines the the Babel plugins you need based on your supported environments. Uses compat-table


と書かれています。
要するに、compat-table(ECMAScript 6 compatibility table)を用いて、サポートされている環境に基づいて必要なBabelプラグインを自動で決定するライブラリということらしいです。

便利ですね。

それでは、先ほどの設定について説明しましょう。
`module: { rules: [...] }`のように書くと、どのプラグインで変換を行うかを指定することができます。
そして、プラグインを指定するオブジェクトは、次のように指定してます。

```
{
  test: /ファイルのパターンを指定/,
　　　　loader: "どのプラグインを使うか",
  options: { プラグインのオプション　}
}
```
ファイルのパターンは、正規表現で指定します。正規表現が曖昧な方は下記投稿にまとめてますのでよかったらご参考ください。
[Ruby 正規表現まとめ（基礎編）](https://qiita.com/takuyanin/items/2918ffb3151dcfa88565)
`/.js$/`と書くと拡張子`.js`を持つファイルという意味になりますね。
そして、loaderの指定ですが、今回は、yarnでインストールした`babel-loader`を使うという意味になります。そしてbabel-loaderのオプションとして、"react"と"env"を指定することで、React/JSXの変換を行うことができるようになります。

## **4. ソースディレクトリ`src`と出力ディレクトリ`out`などを作っておく。**

```
$ mkdir src out

$ ls
node_modules/		out/			package.json		src/			webpack.config.js	yarn.lock
```

## **5. ソースコードを作成し、webpackコマンドでコンパイルする**
まず、2つのファイルを作成します。

```
$ touch src/main.js src/Hello.js

$ ls src
Hello.js	main.js
```

```src/main.js
import React from 'react'
import ReactDOM from 'react-dom'
import {Hello} from './Hello'

ReactDOM.render(
  <Hello />,
  document.getElementById('root') // HTMLファイルのid=rootに描画します
)
```

```src/Hello.js
import React from 'react'

export class Hello extends React.Component {
  render() {
    return <h1>Hello React!</h1>
  }
}
```

コンパイルすると`out/bundle.js`というファイルが作成されます（のちにコマンドを実行します）ので、このファイルを読み込む設定をこれから作成するHTMLファイルに記述していきます。

```
$ touch main.html

$ ls
main.html		node_modules/		out/			package.json		src/			webpack.config.js	yarn.lock
```

```main.html
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <div id="root">
    </div>
    <script src="out/bundle.js">
    </script>
  </body>
</html>
```

## **6. Webサーバー上でコンパイル結果を確認する**

少しエラーが出ました。
`webpack.config.js`ファイルを少し編集しましょう。`+`のところを付け加えました。

```webpack.config.js
module.exports = {
  entry: './src/main.js',
  output: {
    filename: './out/bundle.js'
  },
  module: {
    rules: [
      {
        test: /.js$/,
        loader: 'babel-loader',
        options: {
          presets: ['react', 'env']
        }
      }
    ]
  },
+  mode: 'development',
}
```
では、サーバーを起動しましょう（同時にコンパイルも行われます）。

```
$ ./node_modules/.bin/webpack-dev-server
ℹ ｢wds｣: Project is running at http://localhost:8080/
ℹ ｢wds｣: webpack output is served from /
ℹ ｢wdm｣: wait until bundle finished: /main.html
[BABEL] Note: The code generator has deoptimised the styling of "/Users/takuyanin/webpack-app/node_modules/react-dom/cjs/react-dom.development.js" as it exceeds the max of "500KB".
ℹ ｢wdm｣: Hash: a47d5ceabedd756af9a5
Version: webpack 4.26.0
Time: 9802ms
Built at: 11/21/2018 8:56:53 PM
          Asset      Size  Chunks             Chunk Names
./out/bundle.js  1.08 MiB    main  [emitted]  main
Entrypoint main = ./out/bundle.js
[0] multi (webpack)-dev-server/client?http://localhost:8080 ./src/main.js 40 bytes {main} [built]
[./node_modules/ansi-html/index.js] 4.56 KiB {main} [built]
[./node_modules/ansi-regex/index.js] 139 bytes {main} [built]
[./node_modules/loglevel/lib/loglevel.js] 8.45 KiB {main} [built]
[./node_modules/react-dom/index.js] 1.32 KiB {main} [built]
[./node_modules/react/index.js] 189 bytes {main} [built]
[./node_modules/strip-ansi/index.js] 161 bytes {main} [built]
[./node_modules/url/url.js] 22.6 KiB {main} [built]
[./node_modules/webpack-dev-server/client/index.js?http://localhost:8080] (webpack)-dev-server/client?http://localhost:8080 7.78 KiB {main} [built]
[./node_modules/webpack-dev-server/client/overlay.js] (webpack)-dev-server/client/overlay.js 3.58 KiB {main} [built]
[./node_modules/webpack-dev-server/client/socket.js] (webpack)-dev-server/client/socket.js 1.05 KiB {main} [built]
[./node_modules/webpack/hot sync ^\.\/log$] (webpack)/hot sync nonrecursive ^\.\/log$ 170 bytes {main} [built]
[./node_modules/webpack/hot/emitter.js] (webpack)/hot/emitter.js 89 bytes {main} [built]
[./src/Hello.js] 2.21 KiB {main} [built]
[./src/main.js] 454 bytes {main} [built]
    + 24 hidden modules
ℹ ｢wdm｣: Compiled successfully.
```

`localhost:8080/main.html`にアクセスして`Hello React!`が表示されていれば成功です。
注：前回とはwebpack.config.jsの設定が異なるため、localhost:8080にアクセスしても'Hello React!'は表示されません。


以上となります。お疲れ様でした。

# **React関連記事**
[Reactを始める前に環境を整えよう/「npm/yarn」両者対応。](https://qiita.com/takuyanin/items/8e1442c213c5057a753a)

# **おわりに**
上記（前回）の記事の最後に書いたように、Reactアプリを作る手順は、前回のもの（Reactを導入しないもの）と全く変わりないことがご理解いただけるでしょう。
ですので、やはり導入の段階の理解が最初の障壁になるのではと思っております。
逆に、そこを乗り越えてしまえば、Reactの書き方を学ぶことによってサクッとアプリが作れちゃいます。
何かご質問、ご指摘などございましたらコメント欄などにてお願いいたします。