electron, react, babel, webpack, gulpの環境にした。
今までのものからwebpackを追加した。
その理由は、jsxファイルを分割して、他ファイルからrequireするときに、正しくできないため。
requireが無いと言われたり、パスが異なると言われたりする。
パスが違う原因は、おそらくパス指定がhtmlファイル基準になるためだと思う。
gulp+babelでのトランスパイルは、ファイルはまとまらないようなので、これではまずい。
この問題を解決するために、webpackの導入を行った。
さらに、main.jsなどのメインプロセス側ファイルの変更のホットリロードに対応するため、electron-connectを導入し、gulpfileからelectronを操作できるようにした。
導入とwebpack関連のセットアップ
まずは、パッケージのインストール(追加分のみ、かつelectron-connectは後回し)。
npm install -D babel-loader webpack webpack-stream
続いて、webpackの設定。resolveとmoduleの中身が大事:
// webpack.config.js
module.exports = {
// モード値を production に設定すると最適化された状態で、
// development に設定するとソースマップ有効でJSファイルが出力される
mode: "development",
// メインのJS
entry: "./renderer/index.jsx",
// 出力ファイル
output: {
filename: "bundle.js"
},
resolve: {
extensions: ['.jsx'] // デフォルトは、jsxファイルを探してくれない。
},
module: {
rules: [{
test: /\.jsx$/, // 拡張子がjsxで
exclude: /node_modules/, // node_modulesフォルダ配下でなければ
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react']
}
}
}]
}
}
次は、gulpのタスク定義:
// gulpfile.js
const gulp = require('gulp');
const babel = require('gulp-babel');
const webpackStream = require('webpack-stream');
const webpack = require('webpack');
function transpileViaWebpack() {
// webpackStreamの第2引数にwebpackを渡す
return webpackStream(webpackConfig, webpack)
.pipe(gulp.dest("dist"));
}
exports.default = transpileViaWebpack;
また、watchを変更すればwebpackにしてもホットリロードができる。githubのソースでは、そうしている。しかし、electron-connectを利用している点で異なる。(後述)
Reactのコンポーネント
rendererプロセス用のファイル構成は下のようになる。
renderer/
├── components
│ ├── app.jsx
│ └── person.jsx
├── index.html
└── index.jsx
分割したので、index.jsxは以下のようになる。
// index.jsx
const { App } = require('./components/app');
document.addEventListener("DOMContentLoaded", () => {
ReactDom.render(<App />, document.getElementById('app'));
})
分割先の./components/app.jsxは以下に。
// components/app.jsx
const { Person } = require('./person');
class App extends React.Component {
render() {
return (
<div>
<h1>hello electron+react+webpack world!</h1>
<Person food="sushi" />
</div>
);
}
}
module.exports = {
App: App,
};
さらに分割した./components/person.jsxは以下に。
// components/person.jsx
class Person extends React.Component {
render() {
return (
<p>i want to eat {this.props.food}!</p>
)
}
}
module.exports = {
Person: Person,
};
htmlでの読み込み元の変更
gulpfile.jsで、トランスパイル後の出力ディレクトリ先をdistに変更したので、htmlファイルでの読み込み元もそれに合わせて変更する。
<!-- index.html -->
...
<!-- 以前の出力先 -->
<!-- <script src="../build/index.js"></script> -->
<!-- 現在の出力先 -->
<script src="../dist/bundle.js"></script>
gulpfileからelectronの起動・ホットリロード
今までの内容は、起動時のみ事前のトランスパイル(npx gulp)が必要だった。
これは、若干面倒なので、npm start時にトランスパイルするようにする。
これには、gulp上でelectronの実行ができればいいと考えた。
そこで、electron-connectというツールが使えることがわかった。インストール:
npm install -D electron-connect
メインプロセス側でclientを生成する。html内に埋め込む形にした。配布時には除去できるらしい。(未確認)
<body>
...
<!-- build:remove -->
<!-- Connect to server process -->
<script>electronconnect.client.create()</script>
<!-- end:build -->
</body>
electronconnectなのは、preload.jsでグローバル変数にセットしてあるから。
// preload.js
...
process.once('loaded', () => {
...
global.electronconnect = require('electron-connect');
})
gulpfile.jsに追記。watchでcallback()しないと、一度の変更時しか関数が実行されない。(なぜかelectron.restartはしっかり動いたが。):
// gulpfile.js
const electron = require('electron-connect').server.create();
...
function runElectron() {
electron.start();
}
function watch() {
gulp.watch(paths.main.src, electron.restart);
gulp.watch(paths.renderer.srcjsx, (callback) => {
transpileViaWebpack();
electron.reload();
callback();
});
gulp.watch(paths.renderer.srchtml, (callback) => {
electron.reload();
callback();
});
}
exports.run = gulp.series(transpileViaWebpack, gulp.parallel(runElectron, watch));
これで、npx gulp runすればOK。package.jsonを変更して、npm startでこれを実行するようにする。
// package.json
"scripts": {
"start": "gulp run",
...
},
electron-connectはメインプロセスとレンダラープロセスの両方をリロードできるので、今まで使っていた、electron-reloadは不要になる。よって、アンインストールしておく。
npm uninstall -D electron-reload
後書き
gulpのwatchでcallback()が必要なことに気がつくのに時間がかかった。
自分で環境を構築していくと、いろいろわかってきて楽しい。あまり時間はかけたくないが。
配布のためのパッケージングについても、そのうちまとめておきたい。
最後に現在のpackage.jsonの依存関係を載せておく。:
// package.json
...
"devDependencies": {
"@babel/core": "^7.4.5",
"@babel/preset-env": "^7.4.5",
"@babel/preset-react": "^7.0.0",
"babel-loader": "^8.0.6",
"electron-connect": "^0.6.3",
"electron-mocha": "^8.0.3",
"gulp": "^4.0.2",
"gulp-babel": "^8.0.0",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"webpack": "^4.35.2",
"webpack-stream": "^5.2.1"
},
"dependencies": {
"electron": "^5.0.6"
}
参考
- Module | webpack
- Gulpで始めるwebpack 4入門 - Qiita
- babel-loader - npm
- webpack-stream - npm
- electron-connect - npm


コメント