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


はじめに

前回、Reactを始める前に環境を整えよう/「npm/yarn」両者対応。という記事で、Reactを書き始める前段階の環境構築に関してまとめました。
その中でWebpackというものが出てきましたが、今回はそのWebpackを使って、「Hello React」をブラウザ上に表示したいと思います。

より詳しくWebpackについて知りたい方はこちらをご参考にしてみたください。
WebpackのWebサイト

Webpackて何?

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

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

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

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. 必要なモジュールをインストールする

続いて、必要なモジュールをインストールします。今回インストールするモジュールは、WebpackReactBabelの3種類です。

$ 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 " > [email protected]" 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
├─ [email protected]
├─ [email protected]
├─ [email protected]
├─ [email protected]
├─ [email protected]
├─ [email protected]
├─ [email protected]
└─ [email protected]
info All dependencies
├─ @webassemblyjs/[email protected]
├─ @webassemblyjs/[email protected]
...
...
✨  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 正規表現まとめ(基礎編)
/.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」両者対応。

おわりに

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