Webpack+BabelでReactを使ってみる

モジュールバンドラWebpackJavaScriptコンパイラBabelをインストールし、UIライブラリReactを使ってみる。

環境

Ubuntu 14.04.4 LTS 64bit版

$ uname -a
Linux vm-ubuntu64 3.19.0-25-generic #26~14.04.1-Ubuntu SMP Fri Jul 24 21:16:20 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 14.04.4 LTS
Release:        14.04
Codename:       trusty

$ nodejs --version
v4.4.2

$ npm --version
2.15.0

Node.js、npmのインストール

Webpack、Babel、ReactはどれもJavaScriptで書かれているため、まずはJavaScriptエンジンであるNode.jsとパッケージマネージャnpmをインストールする。 Ubuntuの場合、公式のパッケージリポジトリを利用するとよい。

$ curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -
$ sudo apt-get install -y nodejs

ディレクトリの作成

まず、スクリプトを置くディレクトリを作成する。

$ mkdir helloreact
$ cd helloreact

次に、npm initコマンドでnpmのコンフィグファイルであるpackages.jsonを生成する。

$ npm init -y
Wrote to /home/user/tmp/helloreact/package.json:

{
  "name": "helloreact",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

Webpack、Babel、Reactのインストール

作成したディレクトリ以下にWebpack、Babel、Reactをインストールする。

$ npm install --save-dev webpack babel-loader babel-core babel-preset-react babel-preset-es2015
$ npm install --save react react-dom

コンフィグファイルの準備

実際にスクリプトを書く前に、npmとWebpackそれぞれのコンフィグファイルを準備する。

まず、npmのコンフィグファイルpackage.jsonを編集し、npmからWebpackを実行できるようにする。

{
  "name": "helloreact",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "rm -rf scripts/*.js && webpack",
    "watch": "rm -rf scripts/*.js && webpack -w"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-core": "^6.7.6",
    "babel-loader": "^6.2.4",
    "babel-preset-es2015": "^6.6.0",
    "babel-preset-react": "^6.5.0",
    "webpack": "^1.12.15"
  },
  "dependencies": {
    "react": "^15.0.1",
    "react-dom": "^15.0.1"
  }
}

ここで、buildはWebpackで最終的なJavaScriptファイルを生成するコマンド、watchはファイルの書き換えられたタイミングごとにbuildを行うコマンドである。

次に、Webpackのコンフィグファイルwebpack.config.jsを作成し、Babelで./src/app.js./scripts/bundle.jsコンパイルするよう指定する。

module.exports = {
  entry: "./src/app.js",
  output: {
    path: __dirname + "/scripts",
    filename: "bundle.js"
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: "babel-loader",
        query: {
          presets: ["react", "es2015"]
        }
      }
    ]
  }
};

ここでは、presetsでReactとES2015を扱えるようにしている。

最後に、コンパイル前のソースを置くディレクトリとコンパイル後のファイルを置くディレクトリを作成する。

$ mkdir src scripts

文字数カウンタを書いてみる

準備ができたので、実際にスクリプトを書いてみる。 ここでは、簡単な文字数カウンタを行うページを作ることにする。

まず、コンパイルされたJavaScriptを読み込んで実行するHTMLファイルを作成する。

<!-- index.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"/>
    <title>Hello, React!</title>
  </head>
  <body>
    <div id="content"></div>
    <script type="text/javascript" src="scripts/bundle.js"></script>
  </body>
</html>

次に、Reactを使いテキストボックスへの入力に合わせて文字数を表示するスクリプトを書く。

// src/app.js
import React from "react";
import ReactDOM from "react-dom";

var WordCountBox = React.createClass({
  getInitialState: function() {
    return {text: ""};
  },
  handleTextChange: function(e) {
    this.setState({text: e.target.value});
  },
  render: function() {
    return (
      <div className="wordCountBox">
        <h1>Hello, React!</h1>
        <textarea rows="8" cols="80" placeholder="Type something..." autoFocus="true" onChange={this.handleTextChange}>
          {this.state.text}
        </textarea>
        <p>Count: {this.state.text.length}</p>
      </div>
    );
  }
});

ReactDOM.render(
  <WordCountBox />,
  document.getElementById("content")
);

ここで、冒頭のimport文はBabelでモジュールをincludeする構文である。 上のコードは、テキストボックスのonChangeハンドラでWordCountBoxコンポーネントのstateを更新する。 ここで、JSXではHTMLにおけるプロパティ名(class、onchange)ではなくDOMにおけるプロパティ名(className、onChange)を用いることに注意する。

コンパイルして表示してみる

npm経由でWebpackを実行し、上のスクリプトJavaScriptコードにコンパイルしてみる。

$ npm run build

> helloreact@1.0.0 build /home/user/tmp/helloreact
> rm -rf scripts/*.js && webpack

Hash: eca136dc8b77e7b77879
Version: webpack 1.12.15
Time: 4646ms
    Asset    Size  Chunks             Chunk Names
bundle.js  687 kB       0  [emitted]  main
    + 166 hidden modules

Python等を用いてWebサーバを起動した後、ブラウザでindex.htmlにアクセスした際のスクリーンショットを示すと次のようになる。

$ python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...

f:id:inaz2:20160411052752p:plain

適当にテキストボックスに文字列を入力すると、入力するたびに文字数カウンタが更新されることが確認できる。

関連リンク