使用Electron和React创建一个应用

如何使用以下命令创建Electron Node.js桌面应用程序create-react-app

2021 UPDATE: I highly recommend using electron-react-boilerplate而不是这篇文章中描述的方法

当我第一次使用电子在2015年,尚不清楚它是否会在现代应用程序中如此普遍,我对由此产生的应用程序大小感到有些震惊。

但是,Electron显然会留下来,并且您的应用程序应该变慢并消耗大量内存不是强制性的,就像VS Code每天向我演示(在不那么快的机器上)。

因此,这是一个快速入门反应create-react-app,准备与ESlint一体化。

如果尚未安装Node.js

在macOS上:

brew install node

Move to your development folder

cd ~/dev

Create react app

npx create-react-app app
cd app

Add electron

npm install electron
npm install --save-dev electron-builder

Install foreman to allow executing the app from command line

npm install foreman -g

Install the create-react-app dependencies

npm install

Configure eslint

.eslintrc.json

{
  "env": {
    "browser": true,
    "commonjs": true,
    "es6": true,
    "jest": true
  },
  "parserOptions": {
    "ecmaFeatures": {
      "jsx": true
    },
    "sourceType": "module"
  },
  "rules": {
    "no-const-assign": "warn",
    "no-this-before-super": "warn",
    "no-undef": "warn",
    "no-continue": "off",
    "no-unreachable": "warn",
    "no-unused-vars": "warn",
    "constructor-super": "warn",
    "valid-typeof": "warn",
    "quotes": [
      2,
      "single"
    ],
    "semi": [
      "error",
      "never"
    ]
  },
  "parser": "babel-eslint",
  "extends": "airbnb",
  "plugins": [
    "react",
    "jsx-a11y",
    "import"
  ]
}

Now add ESLint and some of its helpers

npm install eslint eslint-config-airbnb eslint-plugin-jsx-a11y eslint-plugin-import eslint-plugin-react eslint-plugin-import

This is what you should have right now:

Create React App with Electron

Now tweak the package.json file to add some electron helpers.

Right now its content is something like

{
  "name": "gitometer",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "electron": "^1.7.5",
    "eslint": "^4.5.0",
    "eslint-config-airbnb": "^15.1.0",
    "eslint-plugin-import": "^2.7.0",
    "eslint-plugin-jsx-a11y": "^6.0.2",
    "eslint-plugin-react": "^7.3.0",
    "react": "^15.6.1",
    "react-dom": "^15.6.1",
    "react-scripts": "1.0.11"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
  "devDependencies": {
    "electron-builder": "^19.24.1"
  }
}

(don’t mind versions, outdated as soon as I publish this)

Remove the scripts property and change it with

"scripts": {
  "start": "nf start -p 3000",
  "build": "react-scripts build",
  "test": "react-scripts test --env=jsdom",
  "eject": "react-scripts eject",
  "electron": "electron .",
  "electron-start": "node src/start-react",
  "react-start": "BROWSER=none react-scripts start",
  "pack": "build --dir",
  "dist": "npm run build && build",
  "postinstall": "install-app-deps"
},

On Windows you might need to have a .env file with BROWSER=none in it as environemnt variables do not work like in Linux/macOS

As you can see, start was moved to react-start, but the rest is unchanged, and some electron utils were added.

BROWSER=none in react-start tells React not to load in a browser tab, so we only get the app in the Electron window.

Also add

"homepage": "./",
"main": "src/start.js",

and

"build": {
  "appId": "com.electron.electron-with-create-react-app",
  "win": {
    "iconUrl": "https://cdn2.iconfinder.com/data/icons/designer-skills/128/react-256.png"
  },
  "directories": {
    "buildResources": "public"
  }
}

The end result should be:

{
  "name": "gitometer",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "electron": "^1.7.5",
    "eslint": "^4.5.0",
    "eslint-config-airbnb": "^15.1.0",
    "eslint-plugin-import": "^2.7.0",
    "eslint-plugin-jsx-a11y": "^6.0.2",
    "eslint-plugin-react": "^7.3.0",
    "react": "^15.6.1",
    "react-dom": "^15.6.1",
    "react-scripts": "1.0.11"
  },
  "devDependencies": {
    "electron-builder": "^19.24.1"
  },
  "homepage": "./",
  "main": "src/start.js",
  "scripts": {
    "start": "nf start -p 3000",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject",
    "electron": "electron .",
    "electron-start": "node src/start-react",
    "react-start": "BROWSER=none react-scripts start",
    "pack": "build --dir",
    "dist": "npm run build && build",
    "postinstall": "install-app-deps"
  },
  "build": {
    "appId": "com.electron.electron-with-create-react-app",
    "win": {
      "iconUrl": "https://cdn2.iconfinder.com/data/icons/designer-skills/128/react-256.png"
    },
    "directories": {
      "buildResources": "public"
    }
  }
}

Now create a file named Procfile in the project root folder, with this content:

react: npm run react-start
electron: npm run electron-start

Enough with the setup!

Let’s now start writing some code.

src/start.js

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

const path = require(‘path’) const url = require(‘url’)

let mainWindow

function createWindow() { mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true } })

mainWindow.loadURL( process.env.ELECTRON_START_URL || url.format({ pathname: path.join(__dirname, ‘/…/public/index.html’), protocol: ‘file:’, slashes: true }) )

mainWindow.on(‘closed’, () => { mainWindow = null }) }

app.on(‘ready’, createWindow)

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

app.on(‘activate’, () => { if (mainWindow === null) { createWindow() } })

src/start-react.js

const net = require('net')
const childProcess = require('child_process')

const port = process.env.PORT ? process.env.PORT - 100 : 3000

process.env.ELECTRON_START_URL = http://localhost:</span><span style="color:#e6db74">${</span><span style="color:#a6e22e">port</span><span style="color:#e6db74">}</span><span style="color:#e6db74">

const client = new net.Socket()

let startedElectron = false const tryConnection = () => { client.connect({ port }, () => { client.end() if (!startedElectron) { console.log(‘starting electron’) startedElectron = true const exec = childProcess.exec exec(‘npm run electron’) } }) }

tryConnection()

client.on(‘error’, () => { setTimeout(tryConnection, 1000) })

Start up

That’s it!

Run

npm start

and you should see the React sample app coming up in a native app:

React Sample in Electron

Thanks to

This post was heavily inspired by https://gist.github.com/matthewjberger/6f42452cb1a2253667942d333ff53404

Download my free React Handbook


More react tutorials: