nikumaro2’s blog

webエンジニアです。HTML、CSS、Javascript、React.jsの開発についてまとめます。また、初心者英語TOEIC350点。音楽(ベース)、ゴルフなどもたまに、、

【React初心者】React + Electron + VSCodeでデバックまでのHello World

ElectronとReactでアプリケーションを作成する際に、vscodeブレークポイントを張ってデバックできるまでに結構手こずったので備忘録として。

環境

最初に

まず空のフォルダを作成(React_Electron_VsCode_HelloWorldフォルダとする)

VsCodeを開き、React_Electron_VsCode_HelloWorldフォルダを開く

VsCodeの下からTERMINALを引っ張り出して、以下を実行

  • npm init -y
    (-yを付けない場合、いろいろ聞かれるのですべてENTER)

フォルダにpackage.jsonができる

最終的なフォルダ構成

.vscode (vscodeのデバックの設定)
    ┣ launch.json

dist (npm run buildでここにファイルが出力される)
    ┣ index.js
    ┣ index.js.map

node_modules  (npm install できるフォルダ)

src
    ┣ hello.js
    ┣ index.js

index.html

main.js

package.json

package-lock.json

webpack.config.js

npm installでいろいろインストールする

まずelectron

  • npm install --save-dev electron

次にBabel系

  • npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react

React系

  • npm install --save-dev react react-dom

Webpack系

  • npm install --save-dev webpack webpack-cli


"scripts" に"build"を追加

 webpack4用のビルド用のコマンド

最終的にnpm run build でビルドできる


package.jsonが以下のようになる

{
  "name": "react_electron_vscode_helloworld",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --mode development"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {},
  "devDependencies": {
    "babel-core": "^6.26.3",
    "babel-loader": "^7.0.0",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-react": "^6.24.1",
    "electron": "^5.0.6",
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "webpack": "^4.35.3",
    "webpack-cli": "^3.3.5"
  }
}


index.html

<!DOCTYPE html>
<html>

<head>
  <meta charset='utf-8' />
</head>

<body>
  <div id='root'></div>
  <script src='dist/index.js'></script>
</body>

</html>

src= dist/index.jsを指定しているが、最終的にnpm run buildしたときに生成されるもので、出力フォルダはwebpack.config.jsで指定している


main.js

// Electronの実行に必要なモジュールを取り込む
const electron = require('electron')
const path = require('path')
const url = require('url')
const app = electron.app
const BrowserWindow = electron.BrowserWindow

// Electronのライフサイクルを定義
let mainWindow // メインウィンドウを表す変数
app.on('ready', createWindow)
app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') app.quit()
})
app.on('activate', function () {
  if (mainWindow === null) createWindow()
})



// ウィンドウを作成してコンテンツを読み込む
function createWindow() {
  mainWindow = new BrowserWindow({ width: 800, height: 600 })
  mainWindow.loadURL(url.format({ // 読み込むコンテンツを指定 --- (※1)
    pathname: path.join(__dirname, 'index.html'),
    protocol: 'file:',
    slashes: true
  }))

  // //ディベロッパツールを開く
  // mainWindow.webContents.openDevTools()


  // ウィンドウが閉じるときの処理
  mainWindow.on('closed', function () {
    mainWindow = null
  })
}


webpack.config.js

// Reactを変換するためのWebpackの設定ファイル
const path = require('path')
const webpack = require('webpack')
// 変換対象から除外するモジュール --- (※1)
const externalPlugins = new webpack.ExternalsPlugin('commonjs', [
  'app',
  'auto-updater',
  'browser-window',
  'content-tracing',
  'dialog',
  'electron',
  'global-shortcut',
  'ipc',
  'menu',
  'menu-item',
  'power-monitor',
  'protocol',
  'tray',
  'remote',
  'web-frame',
  'clipboard',
  'crash-reporter',
  'screen',
  'shell'
])

module.exports = {
  entry: {
    index: path.join(__dirname, 'src', 'index.js')
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js'
  },
  // devtool: 'cheap-module-eval-source-map',
  devtool: '--source-maps', //元のソースコードと紐づける。babelでトランスパイルしても、元のコードでブレイクを張れる
  target: 'node',
  module: {
    rules: [
      {
        test: /.js$/,
        loader: 'babel-loader',
        options: {
          presets: ['es2015', 'react']
        }
      },
      { test: /\.css$/,
        loaders: ['style-loader', 'css-loader']
      }
    ]
  },
  plugins: [
    externalPlugins
  ]
}

npm run buildでビルドするinputファイルとoutputファイルを指定している



index.js

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

import Hello from './hello';


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


hello.js

import React, { Component } from 'react';


class Hello extends Component {
    constructor(props) {
        super(props)
        this.state = {
            count: 0
        }
    }

    CountFunction() {
        this.setState({count: this.state.count + 1})
    }

    render() {

        return (
            <div className='HelloCount'>
                <div>{this.state.count}</div>
                <button onClick={(e) => this.CountFunction()}>Hello World</button>
            </div>

        );
    }
}

export default Hello;


launch.json

{
    "version": "0.2.0",
    "configurations": [
      {
        "name": "Debug Renderer Process",
        "type": "chrome",
        "request": "launch",
        "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
        "windows": {
          "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd"
        },
        "runtimeArgs": [
          "${workspaceRoot}/main.js",
          "--remote-debugging-port=9222"
        ],
        "sourceMaps": true,
        "webRoot": "${workspaceRoot}"
      },
      {
        "name": "Debug Main Process",
        "type": "node",
        "request": "launch",
        "cwd": "${workspaceRoot}",
        "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
        "windows": {
          "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd"
        },
        "program": "${workspaceRoot}/main.js",
        "protocol": "inspector",
      }
    ]
  }



以上で、npm run buildすると、以下のようなエラーがでる

f:id:nikumaro2:20190711011634p:plain
エラーメッセージ


”babel-core” ver 6を使うなら、"babel-loader" ver7を使えと言われるので、package.json
"babel-core": "^6.26.3",
"babel-loader": "^7.0.0"
などを指定して、npm install

もう一度、npm run buildでビルドが成功したら、Visal Studio Codeで"Debug Renderer Process" 
ブレークポイントを張れるはず。

ちなみに、作業フォルダまでのパスに空白があるとエラーになります。
(onedriveなどで作業している場合は注意)
以上