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

Webエンジニアの備忘録

およそ自己の作業メモとして残しております。

React開発をwebpackでおこなう

概要

前回までの記事でgulpを利用しての開発を進めていましたが、いろいろ見聞してwebpackを使ってみることにしました。

利点を簡潔に言えば、jsをひとつに纏めるかファイル群としてストアするかの選択ができます。さらにwebpack-dev-serverと組み合わせれば、実ファイルを都度生成することなくローカルサーバーで試走が行えるので、タスクランナーとしてgulpと入れ替えても事足りると思います。

最低限のサンプル

f:id:tak_taniguchi:20161010020220p:plain 以下のことをできる最低限の構成です。

  • EcmaScript6、JSXのトランスパイル実行
  • ローカルサーバーでの試走

全体構成

─ /
 └ src/
 │ └ entry.jsx
 │ └ index.html
 └ .babelrc
 └ package.json
 └ web.config.js

コード本体

シンプルにベースのindex.htmlにentry.jsxをロードするだけのサンプルです。 動作すれば画面に「Hello World」が表示されます。

index.html

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>Hello World</title>
</head>
<body>
  <div id="app"></div>
  <script src="./bundle.js"></script>
</body>
</html>

entry.jsx

import React from 'react';
import { render } from 'react-dom';

render((
  <div>
    Hello World
  </div>
), document.getElementById('app'));

セッティング

以下のコンフィグで行われる処理は次のとおりです。

  • entryファイルとしてsrc下のindex.html、entry.jsxを取り込む。
    • jsxを起点にあとの処理でimportされるファイルは全て自動的にトランスパイル対象になる。
  • htmlファイルは同名でそのまま出力する。
  • jsxファイルはトランスパイルして出力する、ただしnode_modules下は対象外にする。

webpack.config.js

module.exports = {
  context: __dirname + '/src',
  entry: {
    jsx: "./entry.jsx",
    html: "./index.html",
  },
  output: {
    path: __dirname + '/dist',
    filename: 'bundle.js',
    publicPath: '/',
  },
  module: {
    loaders: [
      { test: /\.html$/, loader: "file?name=[name].[ext]" },
      { test: /\.jsx$/, exclude: /node_modules/, loader: 'babel' },
    ]
  },
  resolve: {
    extensions: ['', '.js', '.jsx']
  },
};

補足

  • loader指定する際はnpmパッケージ名末尾から「-loader」を省略して書けるので、上記に当てられている正確なパッケージ名はfile-loader・babel-loaderです。
  • extensionsに記載された拡張子はjsx内のimport対象を探索する際のパターンになります。
import Test from './test';
// 上記の場合、「./test」「./test.js」「./test.jsx」のいずれかを探す。
// ファイルタイプ別で重複命名があるとエラーになってしまうので注意

.babelrc

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

loader設定時にオプション指定することもできるが、別ファイルを用意したほうが役割がはっきりするので分割しました。 webpackのコンフィグ側に記載する場合は以下のように記載できます。

        :
    loaders: [
      { test: /\.jsx$/, exclude: /node_modules/, loader: 'babel?presets[]=react&presets[]=es2015' },
    ]
        :

package.json

  • 上記コード、トランスパイラで必要なパッケージを纏めました。
  • また、scriptsにはトランスパイル実行(ビルド)とローカルサーバー起動コマンドを記載してみました。
{
  "name": "hello",
  "version": "1.0.0",
  "description": "",
  "main": "entry.jsx",
  "scripts": {
    "build": "webpack --progress --colors",
    "start": "webpack-dev-server --hot --inline --progress --colors"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-core": "^6.17.0",
    "babel-loader": "^6.2.5",
    "babel-preset-es2015": "^6.16.0",
    "babel-preset-react": "^6.16.0",
    "file-loader": "^0.9.0",
    "webpack": "^1.13.2",
    "webpack-dev-server": "^1.16.2"
  },
  "dependencies": {
    "react": "^15.3.2",
    "react-dom": "^15.3.2"
  }
}

実行コマンド

npm install
npm run start
npm run build

ローカルサーバーはデフォルト http://localhost:8080/ が起点となります。

【補足】ESLintもフックしておく

WebpackでESLintを実装しておくと、ビルドやウォッチのタイミングでチェックが行われるためきれいなコードが書けるかと思います。 こちらも有用なので、メモ代わりに載せておくことにしました。

導入手順

  • ESLintを設定します。セットアップは公式ドキュメントが参考になります。
  • webpack.config.jsに以下のとおり加筆します。
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -10,6 +10,9 @@ module.exports = {
     publicPath: '/',
   },
   module: {
+    preLoaders: [
+      { test: /\.jsx$/, loader: "eslint" },
+    ],
     loaders: [
       { test: /\.html$/, loader: "file?name=[name].[ext]" },
       { test: /\.jsx$/, exclude: /node_modules/, loader: 'babel' },
  • eslint-loaderも忘れずにインストールします。
npm i -D eslint-loader
  • Webpack実行時にエラーがあれば以下のように表示されます。
    • 以下はbrowser環境変数をエスケープせずに"document"を参照するコードが内包されていた例 f:id:tak_taniguchi:20161010110433p:plain

入門 React ―コンポーネントベースのWebフロントエンド開発

入門 React ―コンポーネントベースのWebフロントエンド開発