/

使用 Electron 和 React 創建應用程式

使用 Electron 和 React 創建應用程式

使用 create-react-app 建立 Electron Node.js 桌面應用程式的方法

2021 更新: 我強烈建議使用 electron-react-boilerplate 取代本文所述的方法

當我在 2015 年首次使用 Electron 時,它還不清楚它在現代應用程式中如此普及,而且我對其所導致的應用程式大小感到震驚。

但是,我們可以清楚地知道 Electron 已經成為必不可少的工具,並且你的應用程式不需要讓人感到遲鈍和消耗大量記憶體,就像VS Code每天向我展示的那樣(在一部不是非常快的機器上)。

所以,這裡有一個快速入門指南,使用 create-react-app 創建一個React應用程式,並預先整合了 ESlint

如果尚未安裝 Node.js, 請先安裝

在 macOS 上:

1
brew install node

轉到開發資料夾

1
cd ~/dev

建立 React 應用程式

1
2
npx create-react-app app
cd app

加入 Electron

1
2
npm install electron
npm install --save-dev electron-builder

安裝 foreman 以允許從命令列執行應用程式

1
npm install foreman -g

安裝 create-react-app 的相依性

1
npm install

配置 eslint

.eslintrc.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
{
"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"
]
}

現在添加 ESLint 和一些其輔助工具

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

目前的檔結構如下所示:

Create React App with Electron

現在調整 package.json 檔案以添加一些 Electron 輔助工具。

檔案內容目前類似於:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
"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"
}
}

(版本會在我發布後過時,所以不要在意)

將腳本屬性清除並改為

1
2
3
4
5
6
7
8
9
10
11
12
"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"
},

在 Windows 上,您可能需要在其中使用環境變數的 .env 文件中放置 BROWSER=none,因為環境變數在 Linux/macOS 上無法正常工作

如您所見, start 已更改為 react-start,但其餘部分保持不變,同時添加了一些 Electron 公用工具。

同樣地添加

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

1
2
3
4
5
6
7
8
9
"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"
}
}

最終結果應如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
{
"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"
}
}
}

現在在專案根目錄中創建一個名為 Procfile 的文件,其內容如下:

1
2
react: npm run react-start
electron: npm run electron-start

配置完成!

現在讓我們開始編寫一些程式碼。

src/start.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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:${port}`

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)
})

啟動

就是這樣!

執行

1
npm start

你應該會在原生應用程式中看到 React 範例應用程式:

React Sample in Electron

感謝

本文受到 https://gist.github.com/matthewjberger/6f42452cb1a2253667942d333ff53404 的重要啟發。

tags: [“Electron”, “React”, “create-react-app”, “Node.js”]