Edited at

Electron + Reactの環境作成

More than 1 year has passed since last update.


下準備


下準備

npm init

# なんでもいいけど、エントリーポイントはmain.jsにしておく
entry point: (index.js) main.js



必要なモジュールのインストール

npm install \

electron-reload \
material-ui \
ramda \
react \
react-dom

# electron-reload ・・・ 開発時のオートリロード用
# material-ui ・・・ MaterialUI
# ramda ・・・ 個人的に使いやすいのでRamda.js

npm install -D \
electron \
electron-packager \
webpack \
webpack-cli \
webpack-node-externals \
babel-loader \
html-loader \
html-webpack-plugin \
babel-cli \
babel-preset-env \
babel-preset-react \
babel-preset-stage-1 \
babel-register

# electron-packager ・・・ Electronをパッケージするのに使う
# webpack-node-externals ・・・ node_modulesをwebpackの対象から外す
# babel-preset-stage-1 ・・・ MaterialUIで必要だったはず
# babel-register ・・・ webpack.configだってES6で書きたい


↓.babelrcとwebpack.configはコピペで。


.babelrc

{

"presets": [
["react"],
["stage-1"],
[
"env",
{
"targets": "electron"
}
]
]
}


webpack.config.babel.js

import HtmlWebpackPlugin from 'html-webpack-plugin';

import nodeExternals from 'webpack-node-externals';
import webpack from 'webpack';

export default {
mode: 'development',
target: 'electron-renderer', // レンダラープロセスをメインターゲットに
externals: [nodeExternals()], // node_modulesは依存関係から外すよ
entry: './src/js/index.js',
devtool: 'inline-source-map',
module: {
rules: [
{
test: /\.(html)$/,
use: {
loader: 'html-loader'
}
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
'babel-preset-react',
'babel-preset-env'
]
}
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/html/index.html'
}),
new webpack.ProvidePlugin({
$: 'jquery'
})
]
};



ブラウザプロセス

以下をコピペ。

※内容は、

<公式の記載>

+ <electron_reload>

+ <パッケージ後のメニュー>

+ <ロードするhtmlの変更>


main.js

const {app, BrowserWindow, Menu} = require('electron');

require('electron-reload')(__dirname);
const path = require('path');
const url = require('url');

const template = [
{
label: 'Edit',
submenu: [
{role: 'undo'},
{role: 'redo'},
{type: 'separator'},
{role: 'cut'},
{role: 'copy'},
{role: 'paste'},
{role: 'pasteandmatchstyle'},
{role: 'delete'},
{role: 'selectall'}
]
},
{
label: 'View',
submenu: [
{role: 'reload'},
{role: 'forcereload'},
{role: 'toggledevtools'},
{type: 'separator'},
{role: 'resetzoom'},
{role: 'zoomin'},
{role: 'zoomout'},
{type: 'separator'},
{role: 'togglefullscreen'}
]
},
{
role: 'window',
submenu: [
{role: 'minimize'},
{role: 'close'}
]
},
{
role: 'help',
submenu: [
{
label: 'Learn More',
click () { require('electron').shell.openExternal('https://electronjs.org'); }
}
]
}
];

if (process.platform === 'darwin') {
template.unshift({
label: app.getName(),
submenu: [
{role: 'about'},
{type: 'separator'},
{role: 'services', submenu: []},
{type: 'separator'},
{role: 'hide'},
{role: 'hideothers'},
{role: 'unhide'},
{type: 'separator'},
{role: 'quit'}
],
});

// Edit menu
template[1].submenu.push(
{type: 'separator'},
{
label: 'Speech',
submenu: [
{role: 'startspeaking'},
{role: 'stopspeaking'}
]
}
);

// Window menu
template[3].submenu = [
{role: 'close'},
{role: 'minimize'},
{role: 'zoom'},
{type: 'separator'},
{role: 'front'}
];
}

let win;

function createWindow () {
win = new BrowserWindow({width: 800, height: 600});

win.loadURL(url.format({
// ここのhtmlをdistのhtmlにする
pathname: path.join(__dirname, 'dist/index.html'),
protocol: 'file:',
slashes: true
}));

//win.webContents.openDevTools();

win.on('closed', () => {
win = null;
});

const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
}

app.on('ready', createWindow);

app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});

app.on('activate', () => {
if (win === null) {
createWindow();
}
});



webpack.config.babel.js




レンダラープロセス


前準備

mkdir -p ./src/html ./src/js ./src/jsx dist


HTML

index.htmlはReactの入り口だけ作ってあげる。

MaterialUI用にRobotoの設定もここで。


src/html/index.html

<!DOCTYPE html>

<html>
<head>
<meta charset="UTF-8">
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet">
<style>
* {font-family: 'Open Sans', sans-serif;}
</style>
<title>タイトル</title>
</head>
<body>
<div id="root"></div>
</body>
</html>


JS

ReactDOM.render。

これもほぼコピペでよく、あとはコンポーネントを増やして、追記していけば良い。

MuiThemeProviderをここで記載して、どこでもMaterialUIを使えるようにしておく。


src/js/index.js

import React, { Component } from 'react';

import ReactDOM from 'react-dom';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';

class App extends Component {
render() {
return (
<MuiThemeProvider>
hoge
</MuiThemeProvider>
);
}
}

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



Electron起動

$(npm bin)/webpack

$(npm bin)/electron .


一応コンポーネントも増やしてみる


src/jsx/sub.jsx

import React, { Component } from 'react';

export default class Sub extends Component {
render() {
return (
<div>
Sub
</div>
);
}
}


index.jsでは、Subをimportする。


src/js/index.js

import React, { Component } from 'react';

import ReactDOM from 'react-dom';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';

import Sub from '../jsx/sub.jsx';

class App extends Component {
render() {
return (
<MuiThemeProvider>
hoge
<Sub />
</MuiThemeProvider>
);
}
}

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