React入門 - Part2: Browserify/Reactify/Gulpを使う

More than 3 years have passed since last update.

前回作成したhelloworldはブラウザでJSXTransformerを読み込みオンラインでjsにコンパイルしていました。実行時にChromeのデベロッパーツールに表示されるように、予めJSXはコンパイルすることが推奨されています。コンパイルの方法は、jsxコマンドを使う方法、 BrowserifyReactifyを使う方法、最後にGulpのタスクでまとめる方法を順番に試してみます。


Getting Startedの復習

作成したhelloworld.jsxを少し修正してコンポーネントを作り構成してみます。ディレクトリ構成は以下です。

$ cd ~/react_apps/helloworld/

$ mkdir src dist
$ mv helloworld.jsx src/
$ tree .
.
|-- dist
|-- index.html
`-- src
`-- helloworld.jsx

Nameコンポーネントは作成時にプロパティを指定しています。nameプロパティは{this.props.name}として参照できます。


~/react_apps/helloworld/src/helloworld.jsx

var Name = React.createClass({

render: function() {
return (
<span>{this.props.name}</span>
);
}
});
var HelloWorld = React.createClass({
render: function() {
return (
<div>
<h1>Hello, world!</h1>
<Name name="Masato" />
</div>
);
}
});
React.render(
<HelloWorld />,
document.getElementById('example')
);

jsxファイルのパスも変更します。


~/react_apps/helloworld/index.html

<!DOCTYPE html>

<html>
<head>
<title>Hello World</title>
<script src="http://fb.me/react-0.12.2.js"></script>
<script src="http://fb.me/JSXTransformer-0.12.2.js"></script>
<script type="text/jsx" src="./src/helloworld.jsx"></script>
</head>
<body>
<div id="example"></div>
</body>
</html>

SimpleHTTPServerを起動します。

$ python -m SimpleHTTPServer 8080

Dockerコンテナで作業しているので、ngrokでトンネルします。

$ docker run -it --rm wizardapps/ngrok:latest ngrok 172.17.1.157:8080

ブラウザから確認します。ngrokのURLはランダムです。

http://684baaf0.ngrok.com


jsxコマンドを使う

Browserfyを使う前に、Getting Startedに書いてあるjsxコマンドを試してみます。react-toolsをnpmでインストールします。

$ npm install -g react-tools

jsxコマンドでsrcディレクトリにあるjsxファイルを、buildディレクトリにJavaScriptとしてコンパイルします。ファイルの拡張子をjsxにしているので、-xフラグの指定が必要です。

$ cd ~/react_apps/helloworld/

$ jsx -x jsx src/ dist/
built Module("helloworld")
["helloworld"]

jsファイルのロードをbodyに移動します。JSXTransformerも予めjsにコンパイルして不要になったので削除します。


~/react_apps/helloworld/index.html

<!DOCTYPE html>

<html>
<head>
<title>Hello World</title>
<script src="http://fb.me/react-0.12.2.js"></script>
</head>
<body>
<div id="example"></div>
<script src="./dist/helloworld.js"></script>
</body>
</html>

ngrok経由でトンネルして、ブラウザで確認します。

http://684baaf0.ngrok.com/


BrowserifyとReactifyを使う

Browserifyブラウザ上でもNode.js用モジュールを使えるようにするライブラリです。ReactifyはJSX用のtransform moduleです。npmコマンドを使い、プロジェクトのディレクトリにBrowserify と Reactifyをインストールします。

$ cd ~/react_apps/helloworld

$ npm install react browserify reactify

jsxファイルでNode.jsと同じようにreactモジュールをrequireします。


/react_apps/helloworld/src/helloworld.jsx

var React = require('react');

var Name = React.createClass({
render: function() {
return (
<span>{this.props.name}</span>
);
}
});
var HelloWorld = React.createClass({
render: function() {
return (
<div>
<h1>Hello, world!</h1>
<Name name="Masato" />
</div>
);
}
});
React.render(
<HelloWorld />,
document.getElementById('example')
);

requireでモジュールを読み込んでいるので、index.htmlファイルからreact.jsのロードを削除します。


~/react_apps/helloworld/index.html

<!DOCTYPE html>

<html>
<head>
<title>Hello World</title>
</head>
<body>
<div id="example"></div>
<script src="./dist/helloworld.js"></script>
</body>
</html>

browserifyコマンドに-tフラグでreactifyモジュールを指定し、jsxファイルをjsにコンパイルします。生成されたhelloworld.jsをscript要素でロードすると、ブラウザでもNode.jsのモジュールが使えるようになります。コンパイルされたjsファイルはrequireしたreactモジュールもまとめて1つのファイルになっています。

$ browserify -t reactify src/helloworld.jsx > dist/helloworld.js

ngrok経由でトンネルして、ブラウザで確認します。

http://684baaf0.ngrok.com/


Gulpを使う

Gulpは手続き型で設定ファイルを記述する、タスクランナー&ビルドツールです。Gulpを使うため、少しリファクタリングします。

$ cd ~/react_apps/helloworld-gulp

$ tree .
.
|-- dist
|-- gulpfile.js
|-- index.html
`-- src
|-- main.js
`-- view.jsx

npmコマンドでGulpをグローバルにインストールします。

$ npm install -g gulp

npmコマンドでモジュールをローカルにインストールします。gulpはローカルのプロジェクトにインストールされたモジュールを使います。

$ npm install gulp react browserify reactify vinyl-source-stream

gulpfile.jsを作成します。reactifyでtransformしたjsファイルは、./dist/app.jsに出力されます。


~/react_apps/helloworld-gulp/gulpfile.js

var gulp = require('gulp');

var browserify = require('browserify');
var source = require("vinyl-source-stream");
var reactify = require('reactify');

gulp.task('browserify', function(){
var b = browserify({
entries: ['./src/main.js'],
transform: [reactify]
});
return b.bundle()
.pipe(source('app.js'))
.pipe(gulp.dest('./dist'));
});


helloworld.jsxファイルをリファクタリングして、main.jsとview.jsxファイルに分割します。


~/react_apps/helloworld-gulp/src/main.js

var React = require('react');

var view = require('./view.jsx');
React.renderComponent(
view(),
document.getElementById('content')
);


view.jsxは、HelloWorldコンポーネントをmodule.exportsに代入して公開して、main.jsから参照できるようにします。


~/react_apps/helloworld-gulp/src/view.jsx

var React = require('react');

var Name = React.createClass({
render: function() {
return (
<span>{this.props.name}</span>
);
}
});
var HelloWorld = React.createClass({
render: function() {
return (
<div>
<h1>Hello, world!</h1>
<Name name="Masato" />
</div>
);
}
});
module.exports = HelloWorld;

index.htmlでは、gulp browserifyタスクで1つにコンパイルした./dist/app.jsファイルをロードします。


~/react_apps/helloworld-gulp/index.html

<!DOCTYPE html>

<html>
<head>
<title>Hello World</title>
</head>
<body>
<div id="content"></div>
<script src="./dist/app.js"></script>
</body>
</html>

gulp browserifyタスクを実行してJSXのコンパイルとrequireしたモジュールなどをまとめます。

$ gulp browserify

[13:47:57] Using gulpfile ~/react_apps/helloworld-gulp/gulpfile.js
[13:47:57] Starting 'browserify'...
[13:47:59] Finished 'browserify' after 2.03 s

ngrok経由でトンネルして、ブラウザで確認します。

http://684baaf0.ngrok.com/


package.jsonを作成する

新しい環境でも同じモジュールがインストールできるように、package.jsonを作成してプロジェクトの情報を記述しておきます。最初にマニュアルでインストールしたnode_modulesを削除します。

$ cd ~/react_apps/helloworld-gulp

$ rm -fr node_modules/

npm initコマンドを実行して、対話的にpackage.jsonを作成します。GitHubのリポジトリも自動で入れてくるので、入力した値はauthorだけでpackage.jsonファイルを作成できました。

$ npm init

This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sane defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (helloworld-gulp)
version: (1.0.0)
description:
entry point:
test command:
git repository: (https://github.com/masato/helloworld-gulp.git)
keywords:
author: Masato Shimizu
license: (ISC)
About to write to /home/docker/react_apps/helloworld-gulp/package.json:

{
"name": "helloworld-gulp",
"version": "1.0.0",
"description": "",
"main": "",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/masato/helloworld-gulp.git"
},
"author": "Masato Shimizu",
"license": "ISC",
"bugs": {
"url": "https://github.com/masato/helloworld-gulp/issues"
},
"homepage": "https://github.com/masato/helloworld-gulp"
}

Is this ok? (yes) yes

前回は--save-devフラグを付けませんでしたが、package.jsonのdevDependenciesに設定が書かれるように、npm installするときは--save-devを忘れずつけます。

$ npm install --save-dev gulp react browserify reactify vinyl-source-stream

package.jsonを確認すると、devDependenciesが追加されました。


~/react_apps/helloworld-gulp/package.json

...

"devDependencies": {
"browserify": "^8.0.2",
"gulp": "^3.8.10",
"react": "^0.12.2",
"reactify": "^0.17.1",
"vinyl-source-stream": "^1.0.0"
}
}

package.jsonをリポジトリに追加して、GitHubにpushしておきます。


git cloneし直す

GitHubにpushしたリポジトリを別のディレクトリにcloneして動作確認をします。

$ cd ~/react_apps

$ git clone https://github.com/masato/helloworld-gulp.git gulp-test

プロジェクトのディレクトリに移動して、npm installを実行してローカルにモジュールをインストールします。gulp browserifyタスクを実行してJSXファイルをコンパイルします。

$ cd gulp-test

$ npm install
$ gulp browserify

ローカルでSimpleHTTPServerを起動します。

$ python -m SimpleHTTPServer 8080

ブラウザから動作確認します。

http://684baaf0.ngrok.com/