webpack
React
Electron

(Babel6 対応更新)Electron(0.36.*)/React(^0.14.*)/WebpackHMR

More than 3 years have passed since last update.


この記事の内容はもう古いです。

Babel5 -> Babel6からかなりかわりました。

この記事の例題であるRepositoryだけ更新しておいたので参考してください。

https://github.com/Rokt33r/electron-react-hmr-example

記事をすべて書き直すのは時間がなくてできませんが、

簡単に変わった点を説明すると、



<<<<<<< OLD

"babel-core": "^5.8.25",

"babel-loader": "^5.3.2",

"babel-plugin-react-transform": "^1.1.1",

"react-transform-catch-errors": "^1.0.0",

"react-transform-hmr": "^1.0.1",

"redbox-react": "^1.1.1",

=======

"babel-core": "^6.3.26",

"babel-loader": "^6.2.0",

"babel-plugin-react-transform": "^2.0.0",

"babel-preset-es2015": "^6.3.13",

"babel-preset-react": "^6.3.13",

"babel-preset-react-hmre": "^1.0.1",

>>>>>>> NEW



などをつかうようになりました。

.babelrcはかなりシンプルになり、webpack.config.jsを見ると余計なPluginも要らなくなりました。

とりあえず、前より簡単になったので参考してください。



Webpack HMR(Hot module replacement)をElectronで使う


HMRとは?

Hot module replacementという意味で、

React componentが編集された時にブラウザのRefreshなしで変更が反映される。

なので、生産性をかなり上げることができる。


Demo動画

自分が作っているアプリ、Boostでの試演



仕様

electron 0.33.9

react 0.14.0
react-dom 0.14.0
redux 3.*


前回の問題点


  1. React関連のmoduleは必ずコンパイルされるべきである

  2. webpack.config.jsのtarget: 'atom'が効かない

Productionで運用する時にModuleが、

AppのAPP_PATH/node_modulesではなくて、

~/node_modules/からModuleが呼ばれる場合がある。

その際にAPP_PATH/node_modules/react~/node_modules/reactが両方、呼ばれる場合がある。

Browserで二つのReactを呼び出すと、

すごく致命的なので気をつけるべきである

そういうことで、

私の場合はreactなどはdevDependenciesにいれることにした。

何故かというと、

electron-packager--pruneを使うと、

自動的にdevDependenciesを除いてアプリをパッケージングしてくれるからだ。

しかし、target:atomを使うとHMRが効きなかったので、

これが治るまではElectron moduleのExternal処理は手動でする。


このRepoが現在の最適解

chentsulin/electron-react-boilerplate

このパッケージのままでも問題なく使えるが、

ExpressとWebpack dev middlewareを使っているので、ちょっと面倒だと思った。

この記事ではそれをwebpack-dev-serverwebpack.config.jsだけで押さえるやり方を紹介する。


事前準備

NPMで必要なライブラリを設置する。

npm i -D react react-dom react-transform-catch-errors react-transform-hmr redbox-react babel-loader babel-plugin-react-transform webpack webpack-dev-server


react, react-dom

Reactの基本パッケージ。

v0.14からrenderメソッドはreact-domから使うようになったので、一緒に入れておく。


react-transform-catch-errors, react-transform-hmr, redbox-react

React HMR plugin


babel-loader, babel-plugin-react-transform, webpack, webpack-dev-server

Webpackを実行するために必要なもの


設定

3つのファイルをいじる.babelrc, package.json, webpack.config.js


.babelrc

{

"stage": 0,
"env": {
"development": {
"plugins": ["react-transform"],
"extra": {
"react-transform": {
"transforms": [{
"transform": "react-transform-hmr",
"imports": ["react"],
"locals": ["module"]
}, {
"transform": "react-transform-catch-errors",
"imports": ["react", "redbox-react"]
}]
}
}
}
}
}

HMR transformerで、

React componentをHMRで処理できるようにする


package.json

{

"name": "electron-react-hmr-example",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"start": "electron .",
"webpack": "webpack-dev-server --hot --inline --config webpack.config.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Dick Choi <fluke8259@gmail.com> (http://rokt33r.github.io)",
"license": "ISC",
"devDependencies": {
"babel-core": "^5.8.25",
"babel-loader": "^5.3.2",
"babel-plugin-react-transform": "^1.1.1",
"electron-prebuilt": "^0.35.0",
"react": "^0.14.0",
"react-dom": "^0.14.0",
"react-transform-catch-errors": "^1.0.0",
"react-transform-hmr": "^1.0.1",
"redbox-react": "^1.1.1",
"webpack": "^1.12.2",
"webpack-dev-server": "^1.12.1"
}
}

scriptに注目するwebpack-dev-server --hot --inlineで、--hot --inlineはHMRに必要であるコードをbundle.jsなどに含めてくれる。webpack.config.jsにも設定はできるが、ここでしたほうが楽だと思う。


webpack.config.js

var webpack = require('webpack')

var JsonpTemplatePlugin = webpack.JsonpTemplatePlugin
var FunctionModulePlugin = require('webpack/lib/FunctionModulePlugin')
var NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin')

var opt = {
filename: 'bundle.js',
libraryTarget: 'commonjs2',
publicPath: 'http://localhost:8080/assets/'
}

var config = {
module: {
loaders: [
{
test: /\.js?$/,
loaders: ['babel-loader'],
exclude: /node_modules/
}
]
},
debug: true,
devtool: 'cheap-module-eval-source-map',
entry: [
'./app/index.js'
],
output: opt,
resolve: {
extensions: ['', '.js', '.jsx'],
packageMains: ['webpack', 'browser', 'web', 'browserify', ['jam', 'main'], 'main']
},
plugins: [
new webpack.NoErrorsPlugin(),
new NodeTargetPlugin()
],
externals: [
'electron'
// 'socket.io-client',
// 'md5',
// 'superagent',
// 'superagent-promise',
// 'lodash',
// 'markdown-it',
// 'moment'
]
}

config.target = function renderer (compiler) {
compiler.apply(
new JsonpTemplatePlugin(opt),
new FunctionModulePlugin(opt)
)
}

module.exports = config



pluginsと下のrendererという関数に注目。ここは変えずに使う。

libraryTarget:'commonjs2'はコードをNodeJSのrequireで処理してくれる。

externalsにはWebpackが読み込んだらまずいものを入れる。

(Binary moduleは必ず入れておくこと。NodeとElectronの基本ModuleはNodeTargetPluginExternalsPluginが全部処理しているので大丈夫)

style-loaderもそのまま使える。自分の場合はstylusを使っているので、

  module: {

loaders: [
{
test: /\.js?$/,
loaders: ['babel-loader'],
exclude: /node_modules/
},
{
test: /\.styl?$/,
exclude: /(node_modules|bower_components)/,
loader: 'style-loader!css-loader!stylus-loader'
}
]
}

これで設定はこれで終わり。

この設定をそのまま使っている例題。

https://github.com/Rokt33r/electron-react-hmr-example