说起 Electron,大家能定不会感觉到陌生,庞大的体积,内置浏览器,Hello World 都有 200+M... 我个人是很反感跨段应用的,虽然对于开发来说,节省了很多时间,但是站在用户的角度来讲,体验就不是那么称心如意了。但是最近一些业务需要用到 Electron,折腾过程中也踩了不少坑,总结一下。

开发环境的搭建

平时我们在开发前端应用时,一般都是使用 Webpack 去打包,在开发环境中,也是由 Webpack dev server 来实现 HMR。在 Electron 中也是可以使用 Webpack 的。
我们使用 electron-wepack 包,简单搭建一下环境。
1yarn add source-map-support
2yarn add -D electron electron-webpack electron-builder webpack 
Copy
然后我们参考这个项目结构建立目录:
1project/
2├─ resources/
3│  ├─ icon 						// 程序图标
4├─ src/
5│  ├─ main/ 					// 主进程
6│  │  └─ index.ts
7│  ├─ renderer/ 			// 渲染层(启动界面)
8│     └─ index.js
9└─ static/ 						 // 静态资源
Copy
src 目录下的分别为存放 Electron 主进程逻辑(main) 和 渲染层(renderer)。入口文件必须为 indexmain

TypeScript 支持 (可选)

1yarn add electron-webpack-ts typescript -D
Copy
安装完以上依赖,electron-webpack 会识别支持 TypeScript。

渲染层

src/renderer/index.ts 中,你可以操作 DOM 树。electron-wepack默认会提供一个空白的 HTML 文档,只有一个 #app 节点供你使用,你无法通过一般操作自定义一个入口 index.html, 但是你也可以用其他手段达到这个目标,在此不多赘述 (参看 issue)。
1// src/renderer/index.ts
2const $app = document.getElementById('app')!
3
4$app.textContent = 'Hello World'
Copy

主进程

src/main/index.ts 中, 简单建立一个 app
1import { app, BrowserWindow } from 'electron'
2import { createWindow } from './common/window'
3
4let mainWindow: BrowserWindow
5app.on('ready', () => {
6  mainWindow = createWindow()
7  app.show()
8})
9
10app.on('window-all-closed', () => {
11  if (process.platform !== 'darwin') {
12    app.quit()
13  }
14})
15
16app.on('activate', function () {
17  if (mainWindow === null) {
18    createWindow()
19  }
20})
Copy
其次是 window.ts,建立一个 window
1import { BrowserWindow } from 'electron'
2import path from 'path'
3import { isDev } from '../utils'
4import { format } from 'url'
5export function createWindow() {
6  const mainWindow = new BrowserWindow({
7    height: 620,
8    width: 400,
9    webPreferences: { nodeIntegration: true }, // 一定要加!!!
10  })
11  if (isDev) {
12    mainWindow.loadURL(
13      `http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}`, // 开发环境
14    )
15  } else {
16    mainWindow.loadURL(
17      format({
18        pathname: path.join(__dirname, 'index.html'),
19        protocol: 'file',
20        slashes: true,
21      }),
22    )
23  }
24  return mainWindow
25}
Copy

脚本

package.json 中添加。
1{
2  "scripts": {
3    "prebuild": "rm -rf dist",
4    "build": "cross-env NODE_ENV=production electron-webpack",
5    "start": "electron-webpack dev",
6    "package": "yarn build && electron-builder build --publish never"
7  }
8}
Copy
执行 yarn start 。发现正确显示了 Hello World。
oihA1t
使用 yarn package 来生成 dmg 也是没有问题的。一般教程到此就结束了,但是我们的需求并不是这么简单,我们还需要配置其他,比如 app version,app icon,app sign key... 而这些配置也有很多坑。

配置

图标

应用图标需要不同大小的几张 png 以及 icns 等格式的图片,手动操作比较麻烦,我们可以用一张 png 去生成,使用 electron-icon-builder 工具就能轻松转换到我们想要的结果。
1npx electron-icon-builder -i ./path-your-icon-file.png -o output
Copy
1.
2├── icon.icns
3├── icon.ico
4├── icon.png
5└── icons
6    ├── 1024x1024.png
7    ├── 128x128.png
8    ├── 16x16.png
9    ├── 24x24.png
10    ├── 256x256.png
11    ├── 32x32.png
12    ├── 48x48.png
13    ├── 512x512.png
14    └── 64x64.png
Copy
把生成的文件放入 resources 文件夹内,如不存在则新建。
jq8DsT
package.json 中加入 build 字段,用于配置 electron-builder
1{
2  "build": {
3    "appId": "com.innei.electron-template",
4    "productName": "template",
5    "extraMetadata": {
6      "main": "main.js"            // **必须** 
7    },
8    "copyright": "Copyright © 2019-2020 ${author}",
9    "mac": {
10      "category": "public.app-category.utilities"
11    },
12    "files": [
13      "package.json",
14      "resources/**/*",  						// **必须** 
15      "static",  
16      {
17        "from": "dist/main"      	 // **必须** 
18      },	
19      {
20        "from": "dist/renderer"      // **必须** 
21      }
22    ],
23    "extends": null,
24    "dmg": {
25      "contents": [
26        {
27          "x": 130,
28          "y": 220
29        },
30        {
31          "x": 410,
32          "y": 220,
33          "type": "link",
34          "path": "/Applications"
35        }
36      ]
37    },
38    "win": {
39      "icon": "resources/icon.ico",
40      "target": [
41        "nsis",
42        "msi"
43      ]
44    },
45    "nsis": {
46      "oneClick": false,
47      "allowToChangeInstallationDirectory": true,
48      "installerIcon": "resources/icon.ico"
49    },
50    "linux": {
51      "target": [
52        "deb",
53        "rpm",
54        "AppImage"
55      ],
56      "category": "Development"
57    },
58    "directories": {
59      "buildResources": "resources",
60      "output": "release"
61    },
62    "extraResources": [
63      {
64        "from": "resources/",  // **必须** 
65        "to": "resources/"     // **必须** 
66      },
67      {
68        "from": "static",
69        "to": "static"
70      }
71    ]
72  }
73}
Copy
这里是个大坑,因为我们自定义了配置,覆盖了原来 electron-webpack 的配置,所以有几个地方是必须要这么写的,否则就会在打包之后无法显示 renderer 或者 找不到入口文件。这是我自己摸索出来的,比较 hack 的方法。因为我实在找不到答案。
如果你需要使用 __static 常量的话,
1{ // 也是必须的
2        "from": "static",
3        "to": "static"
4}
Copy
最后,附上 GitHub 地址:

亲亲留个评论再走呗

正在加载评论区...