読者です 読者をやめる 読者になる 読者になる

React 入門以前 (Windows で環境構築)

犬さんにいろいろ教えてもらった。

というわけで

  • ES6 (ES2015)
  • React

で入門する。

進捗した結果 (リポジトリ)

環境構築メインで中身のコードほぼ書いてないので進捗ダメです。

github.com

調べたこと

React

旧石器時代JavaScriptを書いてる各位に告ぐ、現代的なJavaScript超入門

npm

npm で依存もタスクも一元化する - Qiita

npm run-scripts からは gulp のタスクを実行するだけ。

目に付いたメリットは

  • Windows でも動く
  • タスクが gulpfile.js に集約する

Nodist

複数バージョンの Node の運用には *nix 環境なら n とか nvm とか nave とか nodebrew とか色々あるみたいだけど、 不自由な Windows なので nodist というのを使う。

ちなみになぜ複数バージョン動かす必要が出たかというと、gulp のタスクを動かした時に以下のエラーが出たため。

(node:61377) fs: re-evaluating native module sources is not supported. If you are using the graceful-fs module, please update it to a more recent version.

fs: re-evaluating native module sources is not supported. If you are using the graceful-fs module, please update it to a more recent version. · Issue #291 · sequelize/cli · GitHub

その解決方法が以下の通り。まだ Node v6 をサポートしていないパッケージが沢山あるので古い Node v5 を使えとの有り難いアドバイス。

node v6 is still not supported in many packages. Consider going back to v5.

ちなみに Nodist 調べたので一応ここに書いたけど、結局複数バージョン入れるのもだるかったので、 おとなしく公式サイトから現時点の LTS (v4.4.6) をダウンロードして入れました (既存の v6 はアンインストールした)。

gulpfile.js

Browserifyの運用 〜 bundleを分ける - Qiita

全部をbundleすると太る

なるほど~

gulp で browserify - 新しい日記

最初これにしようかと思ったが、browserify().bundle() すると1つのJSファイルになってしまう。

Gulp+Browserifyでsrc/**/*.jsをdist/**/*.jsにする | 高橋文樹.com

この記事では1つのJSファイルになってしまう問題を解決するgulpの設定が書かれている。

…と思ったけど今実行したら下記の記事のエラーが出る。

TypeError: dest.write is not a function

Browserify + gulpではまったのでメモ - Qiita

結局上記記事に書かれてる through2 というパッケージを使う方法で解決…と思ったらまたエラー。

Error: File.contents can only be a Buffer, a Stream, or null.

該当箇所の変数を console.log() で出力したりしてみると、そもそも react パッケージとか babelify も入ってなくて Unexpected token 吐かれてた。

(JSX が有効になってない。結論から言うと .babelrc というものが必要)

$ npm run build

> hello-react@1.0.0 build C:\msys64\home\tyru\git\hello-react
> gulp build

[02:51:46] Using gulpfile C:\msys64\home\tyru\git\hello-react\gulpfile.js
[02:51:46] Starting 'build'...
[02:51:46] Finished 'build' after 15 ms
Error : C:/msys64/home/tyru/git/hello-react/src/app.jsx: Unexpected token (6:6) while parsing file: C:\msys64\home\tyru\git\hello-react\src\app.jsx
SyntaxError: C:/msys64/home/tyru/git/hello-react/src/app.jsx: Unexpected token (6:6)
  4 |   render: function() {
  5 |     return (
> 6 |       <div className="container">Hello {this.props.name}</div>
    |       ^
  7 |     );
  8 |   }
  9 | })
    at Parser.pp.raise (C:\msys64\home\tyru\git\hello-react\node_modules\babelify\node_modules\babel-core\node_modules\babylon\lib\parser\location.js:22:13)
    at Parser.pp.unexpected (C:\msys64\home\tyru\git\hello-react\node_modules\babelify\node_modules\babel-core\node_modules\babylon\lib\parser\util.js:89:8)
    at Parser.pp.parseExprAtom (C:\msys64\home\tyru\git\hello-react\node_modules\babelify\node_modules\babel-core\node_modules\babylon\lib\parser\expression.js:522:12)
    at Parser.pp.parseExprSubscripts (C:\msys64\home\tyru\git\hello-react\node_modules\babelify\node_modules\babel-core\node_modules\babylon\lib\parser\expression.js:277:19)
    at Parser.pp.parseMaybeUnary (C:\msys64\home\tyru\git\hello-react\node_modules\babelify\node_modules\babel-core\node_modules\babylon\lib\parser\expression.js:257:19)
    at Parser.pp.parseExprOps (C:\msys64\home\tyru\git\hello-react\node_modules\babelify\node_modules\babel-core\node_modules\babylon\lib\parser\expression.js:188:19)
    at Parser.pp.parseMaybeConditional (C:\msys64\home\tyru\git\hello-react\node_modules\babelify\node_modules\babel-core\node_modules\babylon\lib\parser\expression.js:165:19)
    at Parser.pp.parseMaybeAssign (C:\msys64\home\tyru\git\hello-react\node_modules\babelify\node_modules\babel-core\node_modules\babylon\lib\parser\expression.js:128:19)
    at Parser.pp.parseParenAndDistinguishExpression (C:\msys64\home\tyru\git\hello-react\node_modules\babelify\node_modules\babel-core\node_modules\babylon\lib\parser\expression.js:596:26)
    at Parser.pp.parseExprAtom (C:\msys64\home\tyru\git\hello-react\node_modules\babelify\node_modules\babel-core\node_modules\babylon\lib\parser\expression.js:481:19)

ちなみにこうしたら上のような詳細なエラーを吐いてくれるようになった。

.on("error", function (err) {
  console.log("Error : " + err.message);
  console.log(err.stack);
})

Unexpected token while parsing file - kubotti’s memo

によると次のパッケージを入れるといいらしい (勘)。

  • babel-preset-es2015
  • babel-preset-react
  • react
  • react-dom

今からはじめるReact.js〜React ver0.14〜 - Qiita

最新だと React の API が変わってるらしい。

0.14でReactDOMがReactから分離されました。 そのため、render()やfindDOMNode()はReactDOMのメソッドを使用しなければなりません。

//React.renderをReactDOM.renderに変更。
ReactDOM.render(
  <Index />,
  document.getElementById('content')
);

.babelrc

{
  "presets": ["es2015", "react"]
}

Browserify エラーを出す - Qiita

package.json

{
  "name": "hello-react",
  "version": "1.0.0",
  "description": "",
  "main": "dist/app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "gulp build"
  },
  "author": "tyru <tyru.exe@gmail.com>",
  "license": "ISC",
  "devDependencies": {
    "babel-preset-es2015": "^6.9.0",
    "babel-preset-react": "^6.5.0",
    "babelify": "^7.3.0",
    "browserify": "^13.0.1",
    "gulp": "^3.9.1",
    "react": "^15.1.0",
    "react-dom": "^15.1.0",
    "vinyl-source-stream": "^1.1.0"
  }
}

gulpfile.js

これだと結局

全部をbundleすると太る

問題が解決してないのですが力尽きました。 gulp 職人の方誰か助けてください。

var gulp = require('gulp');
var browserify = require('browserify');
var babelify = require('babelify');
var source = require('vinyl-source-stream');

gulp.task('build', function() {
  browserify('./src/app.jsx', { debug: true })
    .transform(babelify)
    .bundle()
    .on("error", function (err) {
      console.log("Error : " + err.message);
      console.log(err.stack);
    })
    .pipe(source('bundle.js'))
    .pipe(gulp.dest('./dist'))
});

今度は bundle.js を読み込むタイミングが早すぎてエラーが出た。 Angular でもある例のやつ。jQuery だったら $.ready() で処理すべきなやつ。

うっかり <head> タグに <script> タグで bundle.js を読み込んでしまったんだけど、その際 React では以下のようなエラーが出る。

Uncaught Invariant Violation: _registerComponent(...): Target container is not a DOM element.

とうとう上記のエラーも解消して、肝心の HTML と JS は以下の通り。

index.html

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

src/app.jsx

const React = require('react');
const ReactDOM = require('react-dom');

const Hello = React.createClass({
  render: function() {
    return (
      <div className="container">Hello {this.props.name}</div>
    );
  }
})

ReactDOM.render(<Hello name="React" />, document.getElementById("app"));

フロントエンド周りって慣れないと環境構築にほんと時間かかるな…

gulpプラグインの作り方 | js | Horic Design

through2というパッケージは、gulpのstreamまわりをサポートしてくれるプラグインです。

vinyl-source-stream やら through2 やら本来やりたいことと関係ないプラグインがいっぱい出てくるので初心者にはつらい… と思ってたらそこら辺の事情が以下の記事にまとまっていた (ブクマしとるやんけ)。

gulp と browserify と vinyl の話 - <body>


[gulp] 効率的にプラグインを読み込む - Qiita

gulp で利用するプラグインをひとつひとつ読み込むと大量の require が並ぶことになる。gulp-load-plugins を利用すると package.json から自動で読み込み利用できるようになり、require する必要がなくなる。

Flowtype

犬さんに教えてもらったのですが力尽きました。

追記Windows じゃ動きませんでした。つらい。