React x babel x browserifyでファイルに分割したコンポーネントのクラスがロードできない

Reactのチュートリアルでつまづいたのでエントリーに残しておきます。

複数のjsxファイルをBrowserifyを使ってバンドルし、簡単なReactのウェブサイトを作成するつもりでしたが、ReferenceError: React is not definedというエラーのためページがレンダリングされませんでした。

$ tree .
 src
 ├── components
 │          └─Comp1.jsx
 └── main.jsx
$ cat "./src/components/Comp1.jsx"import { Component } from 'react'

export default Comp1 extends Component {
    render() {
        return(<p>Hello</p>)
    }
}
$ cat "./src/main.jsx"import ReactDom from 'react-dom'
import Comp1 from './components/Comp1.jsx'

ReactDom.render(
    <Comp1 />,
    document.getElementById('content')
)
$ cat "./index.html"<html>
  <body>
    <div id="content"></div>
  </body>
</html>
%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88_2016-11-14_20_19_04
Uncaught ReferenceError: React is not defined(…)

結論を言うと、エントリポイントmain.jsxやコンポーネントのモジュールComp1.jsxなどにおいてもReactのインポートが必要でした。Babal x babel-preset-reactでコンパイルした後のJavaScriptコードはスコープにあるReactオブジェクトを前提としたものになるためです。例えば、上記のmain.jsxのケースだと、コンパイル後のファイルはReact.createElement利用します。

コンパイル前

import ReactDom from 'react-dom'
import Comp1 from './components/Comp1.jsx'

ReactDom.render(
    <Comp1 />,
    document.getElementById('content')
)

コンパイル後

'use strict';
var _reactDom = require('react-dom');
var _reactDom2 = _interopRequireDefault(_reactDom);
var _Comp = require('./components/Comp1.jsx');
var _Comp2 = _interopRequireDefault(_Comp);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

_reactDom2.default.render(React.createElement(_Comp2.default, null), adocument.getElementById('content')); // React.createElementが含まれる

未使用の変数Reactをスコープに転がしている形になり、エディターのLint機能が警告してくるため、Reactへの参照をスコープに転がしておくことを忌避していました。このことは実際にコンパイル結果を検証すれば一目瞭然でしたが、気付くまでに時間を消費してしまったため記録しておきます。
%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-11-14-20-26-20

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です