HTML5テクニカルノート
React入門 06: ローカルサーバーの立ち上げとJSXのコンパイル
- ID: FN1608007
- Technique: HTML5 / JavaScript
- Library: React 15.4.2
このReact入門シリーズでは、Reactのチュートリアルのサンプルファイルでローカルサーバーを立ち上げました(「React入門 03: データはJSON形式にしてページをローカルサーバーで表示する」03「チュートリアルのサンプルファイルでサーバーを立てる」)。また、JSXのコンパイルはbabel-coreのJavaScriptライブラリを用いて、ブラウザ上で行っています(「React: まずは動かしてみる」04「BabelでJSXをコンパイルする」)。けれど、チュートリアルの設定にとらわれずに、ローカルサーバーを動かしたいこともあるでしょう。また、コンテンツをサーバーに公開するときは、ユーザーのブラウザ上で標準のJavaScriptコードに変換するのでなく、あらかじめ(静的に)コンパイルしておく方がブラウザの負荷が下げられます。そこで、ローカルサーバーの立ち上げとJSXのコンパイルについて、簡単なやり方をご紹介します。
なお、Node.jsがインストールされていなければなりません(「React入門 03: データはJSON形式にしてページをローカルサーバーで表示する」02「チュートリアルのサンプルファイルとNode.jsのインストール」参照)。
01 http-serverでローカルサーバーを立ち上げる
ローカルサーバーはhttp-serverで立ち上げることにします。コマンドラインツール(OS Xならターミナル、WindowsはNode.js command promptなど)を開いて、npmのコマンドで、つぎのようにグローバルにインストールします。
npm install http-server -g
そして、コマンドラインツールでローカルサーバーのルートにするディレクトリに切り替えます。あとは、つぎのようにコマンドを打ち込むだけです。http://localhost:8080/
でルートが開きます。
http-server
試しに、「React入門 05: フォームからサーバーにデータを送ってページに加える」コード002「フォームに入力したデータをサーバーに送ってページに加える」をhttp-serverで動かしてみましょう。チュートリアルのserver.jsは使いませんので、ルートのフォルダ名は「public」でなくても構いません(ここでは変えずにおきます)。そして、データを読み書きするJSONファイル(comments.json)は、ルートにおいてください(図001)。
図001■サーバーのルートにcomments.jsonを納める
前出コード002は、server.jsにもとづいてプロパティ(url)に定めたJSONファイルのパスを、つぎのように(comments.jsonに)改めます。コマンドラインツールでディレクトリをルートにするフォルダ(public)に移し、コマンドhttp-server
を打てばルートのHTMLドキュメント(http://localhost:8080/sample.html)が開けます。ただし、送ったデータをJSONファイルに書き加える処理がありません(チュートリアルのserver.jsにはテスト用の処理が含まれていました)。そのため、データの表示はできても、送信がエラーになります(図002)。
ReactDOM.render( <CommentBox url="comments.json" />, document.getElementById('content') );
図002■JSONのデータの表示はできても送信できない
02 BebelのReact presetでJSXを標準のJavaScriptコードにコンパイルする
ReactのJSXをコンパイルするために、BebelのReact presetを使うことにします。コマンドラインツールでReactでつくったプロジェクトのディレクトリに移り、つぎのnpmのコマンドでbabel-cliとbabel-preset-reactをインストールします。
npm install --save-dev babel-cli babel-preset-react
そして、Babelの設定ファイル.babelrcを定めます。コマンドラインツールにつぎのよう入力すればファイルがつくられます。
echo '{ "presets": ["react"] }' > .babelrc
package.jsonファイルには、npmから呼び出すコマンドをひとつ"scripts"に加えます。コマンドbabel
のあとに変換もとのディレクトリ、オプション-d
に続けて変換先ディレクトリを与えます。
babel 変換もとディレクトリ -d 変換先ディレクトリ
つぎの記述はReactの練習用ディレクトリから、publicフォルダ内のsrcにあるJSXのJavaScriptファイルを、同じフォルダのlibにコンパイルして納めることになります。
{ "scripts": { "build": "babel public/src -d public/lib" }, }
コマンドラインツールから、npmでつぎのようにスクリプト(build)を呼び出します。変換先フォルダ(public/lib)に、標準のJavaScriptコードにコンパイルされたファイルができ上がります。
npm run build
ご参考までに、前出「React入門 05: フォームからサーバーにデータを送ってページに加える」コード002「フォームに入力したデータをサーバーに送ってページに加える」からコンパイルしたJavaScriptの記述を以下のコード001に掲げました。JSXのタグがReact.createElement()
メソッドに書き替えられています。
このJavaScriptファイル(script.js)を読み込むHTMLドキュメント(sample.html)には、つぎのように手を加えます。まず、babel-standaloneのJavaScriptライブラリ(babel.min.js)は要りません。つぎに、<script>
要素のsrc
属性には、コンパイルした(フォルダlibの)ファイルのパスを与えます。<body>
要素の最後に移したのは、ReactDOM.render()
メソッドの第2引数に渡した親要素(id
属性"content")が読み込まれるのを待つためです。<script>
要素を<head>
要素に入れたい場合には、ドキュメントがロードされてからJavaScriptコードの処理を行うように書き直さなければなりません。
<!doctype html> <html> <head> <meta charset="UTF-8"> <title>Sample</title> <script src="https://unpkg.com/react@15/dist/react.min.js"></script> <script src="https://unpkg.com/react-dom@15/dist/react-dom.min.js"></script> <!--<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.23.1/babel.min.js"></script>--> <script src="https://cdnjs.cloudflare.com/ajax/libs/remarkable/1.7.1/remarkable.min.js"></script> <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script> <!--<script src="src/script.js" type="text/babel"></script>--> </head> <body> <div id="content"></div> <script src="lib/script.js"></script> </body> </html>
コード001■標準のJavaScriptコードにコンパイルされたファイルの記述
var CommentBox = React.createClass({
displayName: 'CommentBox',
getInitialState: function () {
return { data: [] };
},
componentDidMount: function () {
$.ajax({
url: this.props.url,
dataType: 'json',
cache: false,
success: function (data) {
this.setState({ data: data });
}.bind(this),
error: function (xhr, status, error) {
console.error(this.props.url, status, error.toString());
}.bind(this)
});
},
handleCommentSubmit: function (comment) {
$.ajax({
url: this.props.url,
dataType: 'json',
type: 'POST',
data: comment,
success: function (data) {
this.setState({ data: data });
}.bind(this),
error: function (xhr, status, error) {
console.error(this.props.url, status, error.toString());
}.bind(this)
});
},
render: function () {
return React.createElement(
'div',
{ className: 'commentBox' },
React.createElement(
'h1',
null,
'コメント'
),
React.createElement(CommentList, { data: this.state.data }),
React.createElement(CommentForm, { onCommentSubmit: this.handleCommentSubmit })
);
}
});
var CommentList = React.createClass({
displayName: 'CommentList',
render: function () {
var commentNodes = this.props.data.map(function (comment) {
return React.createElement(
Comment,
{ author: comment.author, key: comment.id },
comment.text
);
});
return React.createElement(
'div',
{ className: 'commentList' },
commentNodes
);
}
});
var Comment = React.createClass({
displayName: 'Comment',
rawMarkup: function () {
var markDown = new Remarkable();
var rawMarkup = markDown.render(this.props.children.toString());
return { __html: rawMarkup };
},
render: function () {
return React.createElement(
'div',
{ className: 'comment' },
React.createElement(
'h2',
{ className: 'commentAuthor' },
this.props.author
),
React.createElement('span', { dangerouslySetInnerHTML: this.rawMarkup() })
);
}
});
var CommentForm = React.createClass({
displayName: 'CommentForm',
getInitialState: function () {
return { author: '', text: '' };
},
handleChange: function (eventObject) {
var state = {};
state[eventObject.target.id] = eventObject.target.value;
this.setState(state);
},
handleSubmit: function (eventObject) {
eventObject.preventDefault();
var author = this.state.author.trim();
var text = this.state.text.trim();
if (!author || !text) {
return;
}
this.props.onCommentSubmit({ author: author, text: text });
this.setState({ author: '', text: '' });
},
render: function () {
return React.createElement(
'form',
{ className: 'commentForm', onSubmit: this.handleSubmit },
React.createElement('input', {
type: 'text',
id: 'author',
placeholder: '名前',
value: this.state.author,
onChange: this.handleChange
}),
React.createElement('input', {
type: 'text',
id: 'text',
placeholder: 'コメントを入力',
value: this.state.text,
onChange: this.handleChange
}),
React.createElement('input', { type: 'submit', value: '送信' })
);
}
});
ReactDOM.render(React.createElement(CommentBox, { url: 'comments.json' }), document.getElementById('content'));
本稿では、すぐに試しやすいローカルサーバーの立ち上げとJSXのコンパイルのやり方をご紹介しました。実際にコンテンツをつくるようになったら、GulpやGruntなどのタスクランナーツールを使って、作業の効率化も考えるとよいでしょう。
- React: まずは動かしてみる
- React入門 01: コンポーネントを組み立てる
- React入門 02: remarkableでMarkdownの機能を加える
- React入門 03: データはJSON形式にしてページをローカルサーバーで表示する
- React入門 04: JSONデータをローカルサーバーから読み込んでページに表示する
- React入門 05: フォームからサーバーにデータを送ってページに加える
作成者: 野中文雄
更新日: 2017年3月15日 ライブラリのバージョン更新にともなう修正。
作成日: 2016年8月30日
Copyright © 2001-2017 Fumio Nonaka. All rights reserved.