webpack2でReactを使う

webpacke2でReactの開発環境を作る。

フォルダ・ファイルを作る

$ mkdir react1
$ cd react1
$ mkdir src
$ mkdir public
$ touch public/index.html
$ touch src/index.js
$ touch webpack.config.js
$ touch postcss.config.js

インストール

$ npm init -y
$ npm i -D webpack webpack-dev-server
$ npm i -D babel-loader babel-core babel-plugin-syntax-dynamic-import babel-preset-es2015 babel-preset-react
$ npm i -D extract-text-webpack-plugin
$ npm i -D style-loader css-loader postcss postcss-loader autoprefixer cssnano precss react-css-modules
$ npm i -D react react-dom

package.jsonは下記のようになった。

{
  "name": "react1",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "autoprefixer": "^6.7.7",
    "babel-core": "^6.24.0",
    "babel-loader": "^6.4.1",
    "babel-plugin-syntax-dynamic-import": "^6.18.0",
    "babel-preset-es2015": "^6.24.0",
    "babel-preset-react": "^6.23.0",
    "css-loader": "^0.27.3",
    "cssnano": "^3.10.0",
    "extract-text-webpack-plugin": "^2.1.0",
    "postcss": "^5.2.16",
    "postcss-loader": "^1.3.3",
    "precss": "^1.4.0",
    "react": "^15.4.2",
    "react-css-modules": "^4.1.0",
    "react-dom": "^15.4.2",
    "style-loader": "^0.16.0",
    "webpack": "^2.3.1",
    "webpack-dev-server": "^2.4.2"
  }
}

webpack.config.jsを作る

var path = require('path');
const webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  entry: path.resolve(__dirname, 'src/index.js'),
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'public')
  },
  devServer: {
    contentBase: path.resolve(__dirname, 'public'),
    port: 8080,
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: [
            'css-loader',
            'postcss-loader'
          ],
        })
      },
      {
        test: /\.js$/,
        use: [{
          loader: 'babel-loader',
          options: {
            presets: [
              ['es2015', {modules: false}],
              'react'
            ],
            plugins: ['syntax-dynamic-import']
          }
        }]
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin('styles.css'),
    new webpack.optimize.UglifyJsPlugin({
      beautify: false,
      mangle: {
        screw_ie8: false,
        keep_fnames: false
      },
      compress: {
        screw_ie8: true
      },
      comments: false
    })
  ]
};

postcss.config.jsを作る

module.exports = {
  plugins: [
    require('autoprefixer')({}),
    require('cssnano')({}),
    require('precss')({}),
    require('react-css-modules')({})
  ]
}

public/index.htmlを作る

<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>React App</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="bundle.js"></script>
  </body>
</html>

src/index.jsを作る

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.getElementById('root')
);

webpackを実行する。実行後、public/bundle.jsが作成される。

$ webpack

webpack-dev-serverを実行する。実行後、http://localhost:8080にアクセスすると確認できる。

$ webpack-dev-server

webpack + eslint

webpackでeslintを使う場合、eslintとは別に、eslint-loaderをインストールする必要があります。

インストール

$ npm i -D webpack
$ npm i -D webpack-dev-server
$ npm i -D eslint
$ npm i -D eslint-loader

そして、webpack、eslintそれぞれの設定ファイルを作成します。

webpackの設定

下記のように、webpack.config.jsを設定します。
moduleのpreLoadersにeslint-loaderの設定を書きます。moduleは、eslint-loader等の-loaderを省略できます。あと、下の方にあるeslintというところで、eslintの設定ファイルを指定します。eslintrc.jsonとか、.eslintrcというファイル名であれば指定は不要かもです。

module.exports = {
  entry: './src/main.js',
  output: {
    path: __dirname + '/www/js',
    filename: 'bundle.js'
  },
  devServer: {
    contentBase: __dirname + '/www',
    port: 8080
  },
  module: {
    preLoaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: "eslint"
      }
    ],
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel'
      },
     {
        test: /\.css$/,
         loader: "style!css"
     }
    ]
  },
  plugins: [],
  eslint: {
    configFile: './.eslintrc'
  }
};

eslintの設定

eslintのルールは沢山あって自分でルールを使うかどうか決められますが、AirBnBのルールが人気だし、そういうところに合わせておいて悪いことはないと思うので、基本AirBnBを使います。ただ、Reactとbabelを使っているときに沢山エラーがでたので、ちょっと修正しました。AirBnBのルールを使いつつ、このエラーは出なくてもいいやと思ったら、ルールを無効にして調整してます。まだ、使いだしたばかりなので、単なる一例です。

.eslintrc

{
    "extends": "airbnb",
    "plugins": [
        "react",
        "jsx-a11y",
        "import"
    ],
    "rules": {
        "import/no-extraneous-dependencies": 0
    },
    "env": {
        "browser": true,
        "node": true
    }
}

jsx拡張子に関するルール

reactはjsxを使いますが、jsxを使っているファイルの拡張子はjsxにしないと、AirBnBルールに怒られます。jsxを使っていないファイルはjsのままだと思うので、拡張子がjsとjsx共に、webpackがjavascriptに対して実行する処理を適用させるようにしてみます。

該当ファイルの拡張子をjsxに変更し、webpack.config.jsを下記のように修正します。

module.exports = {
  entry: './src/main.jsx',
  output: {
    path: __dirname + '/www/js',
    filename: 'bundle.js'
  },
  devServer: {
    contentBase: __dirname + '/www',
    port: 8080
  },
  module: {
    preLoaders: [
      {
        test: /\.jsx{0,1}$/,
        exclude: /node_modules/,
        loader: "eslint"
      }
    ],
    loaders: [
      {
        test: /\.jsx{0,1}$/,
        exclude: /node_modules/,
        loader: 'babel'
      },
     {
        test: /\.css$/,
         loader: "style!css"
     }
    ]
  },
  plugins: []
};

webpack

webpack

参考:webpack で始めるイマドキのフロントエンド開発

webpack は WebApp に必要なリソースの依存関係を解決し、アセット(配布物)を生成するビルドツール(要するにコンパイラ)です。JavaScript だけでなく、CoffeeScript や TypeScript、CSS 系、画像ファイルなどを扱うことができます。

webpack を使えば、Grunt も Gulp も必要ありません!覚えるべきことはほとんどありません。(必要なら)簡単な設定ファイルを書いて webpack コマンドを実行するだけです。

インストール

$npm i -g webpack

これで、hoge.jsがscript.jsとして作成される。

$webpack hoge.js script.js

参考:http://webpack.github.io/docs/installation.html
これを使うと簡易webサーバが立ち上げられるっぽい。

$ npm install webpack-dev-server --save-dev

参考:webpack-dev-serverの基本的な使い方とポイント
便利だな。

下記のように、package.jsonのscriptsに、webpack-dev-serverの起動を追加して、npm run webpack-dev-serverとしたらサーバが起動した。設定しないと、プロジェクトルートをwebルートにされました。

"scripts": {
  "webpack-dev-server": "webpack-dev-server"
},

webpackの設定

webpack.config.jsというファイルに設定を書き込む。

webpack.config.jsを下記のようにして、webpackを実行するとできた。

module.exports = {
  entry: './src/main.js',
  output: {
    path: __dirname + '/www/js',
    filename: 'bundle.js'
  }
};

devServerのcontentBaseを指定すると、webpack-dev-serverのWEBルートが変更できる。ポートも変更できるらしい。

module.exports = {
  entry: './src/main.js',
  output: {
    path: __dirname + '/www/js',
    filename: 'bundle.js'
  },
  devServer: {
    contentBase: __dirname + '/www',
    port: 8080
  },
};

Hot Module Replacement(HMR)というのも便利そう。

参考:http://webpack.github.io/docs/usage.html

nativeのjavascript以外に対応させるためには、loaderというのを使うらしい。例えばbabelであれば、babel-loaderというのがある。

babelをnpmでインストールしてから、webpack.config.jsに、下記を追加する。

module: {
  loaders: [{
    test: /\.js$/,
    exclude: /node_modules/,
    loader: 'babel-loader'
  }]
},

testとかよくわからないけど、jsファイルはbabel-loader通す的な感じでしょうか?これによって、Reactとかも対応可能になるもよう。reactで試してみよう。

参考:babelとwebpackを使ってES6でreactを動かすまでのチュートリアル

main.jsを下記のようにする。

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

class App extends React.Component {
  render () {
    return <p> Hello React!</p>;
  }
}

render(<App/>, document.getElementById('example'));

これでwebpackしたら、正常に動いた。

あと、プラグインもあって、例えば、jsファイルの圧縮もある。
webpack.config.jsの最初の行に下記を追加する。

const webpack = require('webpack');

あと、webpack.config.jsに下記を追記する。

plugins: [
      new webpack.optimize.UglifyJsPlugin({
          compress: {
              warnings: false,
          },
          output: {
              comments: false,
          },
      }),
  ]

これで圧縮された。
webpack -p とするだけで、本番用になるので、圧縮してくれるらしい。

スタイルシートもエントリーポイントのJSに組み込むらしい。
参考:http://webpack.github.io/docs/tutorials/getting-started/
参考:タスクランナーを使わずに webpack だけでフロントエンド開発する方法

$ npm i -D css-loader style-loader

cssをmain.jsに組み込む。

require("./css/style.css");

webpack.config.jsにcss loaderの設定を追加する。

module: {
  loaders: [
    {
      test: /\.js$/,
      exclude: /node_modules/,
      loader: 'babel'
    },
    {
      test: /\.css$/,
        loader: "style!css"
    }
  ]
},

これでできた。
webpack.config.jsに下記を追加すると、importとかするときに、拡張子をつけなくてよくなる。

resolve: {
  extensions: ['', '.js', '.css']
},

あと、webpack-dev-serverは、watchしてくれているらしい。ファイルを変更すると自動的に内部的にwebpackし、その結果をメモリ上に保存するらしい。ファイル自体は作成しない。webpack-dev-serverを利用しない場合は、webpackのwatch機能を利用したらしい。

$ webpack -d --watch

-dというのは、source mapを作成してくれるものらしい。やってみる。おーでてる。bundle.js.mapが作成されました。多分watchできてそう。

あとは、コードチェックしてくれる、eslintを入れてみる。webpackで使う場合、これもloaderになる。eslint-loader。

$ npm i -D eslint-loader

どうもERROR in Cannot find module ‘eslint’というエラーがでるので、eslintは別で調べる。