Logo Vincent
返回文章列表

一篇文章学会Electron

Electron
一篇文章学会Electron

【前言】

javascript语言的强大生命力,为前端开发拓展了很多业务

网页端业务:基于js,html,css开发网页相关业务

服务端业务:基于nodejs开发服务端业务

桌面端业务:基于chromium和nodejs开发桌面业务

移动端业务:基于webview开发移动端业务

【electron-简介】

桌面端业务,也就是mac和windows上的应用开发业务,

是基于chromium和nodejs来开发的,

chromium

地址:https://www.chromium.org/chromium-projects/

chromium负责渲染进程(ui层),chromium也就是chrome内核,

由于chromium基本支持js,html,css最新的特性,

所以渲染层的各种实现不在话下

nodejs

地址: https://nodejs.org/dist/latest-v16.x/docs/api/

nodejs大家比较熟悉,跨平台的runtime,具备文件,网络等能力,

例如将mac,windows和linux下的文件能力都封装为fs模块,

所以nodejs负责主进程,抹平各操作系统的差异,

electron

地址: https://www.electronjs.org/

electron大概做了几件事情

1.内嵌了chromium和nodejs,具备了渲染进程和主进程能力

2.提供ipc通信,打通渲染进程和主进程之间通信的能力

3.实现各种操作系统的特性,例如mac下图标,任务栏等特性

electron的性能

地址: https://www.electronjs.org/apps

跨平台的技术一般会被挑战性能方面的指标,

上述地址是用electron开发的应用列表,

可以看到有很多大型应用都使用electron开发,

例如:vscode,figma,postman,slack,discord等等,

覆盖面很广,从工具类vscode,postman到社交应用slack和discord都有,

侧面证明了electron性能是ok的,

如果你开发出的electron应用性能差,要更多的从自己业务代码上找原因

【electron-hello world】

electron官方提供了入门的示例,跑起一个hello world,

首先需要安装electron

electron:安装

electron安装比较简单,命令如下,

-D是因为electron这个包在开发时提供环境,

构建为mac,windows应用时会通过一些打包工具将electron的能力打包进去,

npm i -D electron

这里需要注意的是,第一次安装时要下载electron,

这个包比较大,建议选一个网络比较好的环境下载

安装后可以参考官网示例,示例中大概有这几个文件:

index.html

对应上面说的渲染进程,渲染层,ui层,运行在chromium上,

其实就是一个html,可以看到内容很简单,甚至没有引用css

<!--index.html-->

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <!-- https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP -->
    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'" />
    <meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'" />
    <title>Hello World!</title>
  </head>
  <body>
    <h1>Hello World!</h1>
    We are using Node.js <span id="node-version"></span>, Chromium <span id="chrome-version"></span>, and Electron
    <span id="electron-version"></span>. <!-- 您也可以此进程中运行其他文件 -->
    <script src="./renderer.js"></script>
  </body>
</html>

main.js

对应上面说的主进程,运行在nodejs环境上,

逻辑也比较简单,创建了一个window,

为这个window加载了preload.js文件

监听window的一些事件

// main.js

// 控制应用生命周期和创建原生浏览器窗口的模组
const { app, BrowserWindow } = require('electron');
const path = require('path');

function createWindow() {
  // 创建浏览器窗口
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
    },
  });

  // 加载 index.html
  mainWindow.loadFile('index.html');

  // 打开开发工具
  // mainWindow.webContents.openDevTools()
}

// 这段程序将会在 Electron 结束初始化
// 和创建浏览器窗口的时候调用
// 部分 API 在 ready 事件触发后才能使用。
app.whenReady().then(() => {
  createWindow();

  app.on('activate', function () {
    // 通常在 macOS 上,当点击 dock 中的应用程序图标时,如果没有其他
    // 打开的窗口,那么程序会重新创建一个窗口。
    if (BrowserWindow.getAllWindows().length === 0) createWindow();
  });
});

// 除了 macOS 外,当所有窗口都被关闭的时候退出程序。 因此,通常对程序和它们在
// 任务栏上的图标来说,应当保持活跃状态,直到用户使用 Cmd + Q 退出。
app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') app.quit();
});

// 在这个文件中,你可以包含应用程序剩余的所有部分的代码,
// 也可以拆分成几个文件,然后用 require 导入。

preload.js

开发electron的第一个疑问是如何使用nodejs能力,

有两种方式

|—直接在渲染层中使用,也就是上面index.html包含或者引用的js中

|—主进程创建window时注入preload.js文件,在preload.js中注册一些nodejs能力,然后在渲染层使用

前者由于有安全隐患,这里推荐使用后者,

但是前者这种渲染层直接使用nodejs能力却是另一个桌面端框架的特色,

nwjs: https://nwjs.io/ ,nwjs目前维护不是很好,就不推荐了

下述preload.js的示例中就使用了nodejs的process模块

// preload.js

// 所有Node.js API都可以在预加载过程中使用。
// 它拥有与Chrome扩展一样的沙盒。
window.addEventListener('DOMContentLoaded', () => {
  const replaceText = (selector, text) => {
    const element = document.getElementById(selector);
    if (element) element.innerText = text;
  };

  for (const dependency of ['chrome', 'node', 'electron']) {
    replaceText(`${dependency}-version`, process.versions[dependency]);
  }
});

package.json

这个文件比较简单,依赖了electron,添加了一个脚本,

  "devDependencies": {
    "electron": "^21.1.1",
  },
  "scripts": {
    "start": "electron ."
  }

可以通过执行npm start看效果了,效果如下

你没看错,简单的几个文件,已经可以在桌面端跑起来一个桌面应用了

小结

上面的hello world示例,蕴含了electron最核心的原理

1.index.html代表渲染进程,后续会使用html,css,js开发渲染进程(UI层),这里你可以使用任何前端技术栈,例如react,vue等,总体来说类似开发网页

2.main.js代表主进程,操作系统一些特性,应用各种事件监听等,都在这里实现,这里更多的是要熟悉electron的api,因为electron磨平了操作系统特性

3.preload.js代表nodejs能力,所有渲染层需要使用到的nodejs能力,建议都封装到preload.js中,这里更多的是需要熟悉nodejs能力

4.这里还差一个主进程和渲染进程通信能力

熟悉了以上4个能力,基本就掌握了electron的开发,所以可以多看看这个示例~

【electron-实践】

由于需要一篇文章学会electron,只讲概念比较枯燥,

这里引入一个实践项目,跟着实践项目,掌握概念比较快,

之前开发了一个网页版的todolist,

这里在这个项目的基础上继续深入,

了解之前的项目可以看这两篇文章:

一篇文章开发todolist

一篇文章学会IndexedDB

上述hello world代码详见: https://github.com/uikoo9/dishi-monorepo/tree/dishi-electron%400.0.3

在packages/dishi-electron文件夹下,

electron-抽取src

这里需要注意,electron是作为dev依赖引入的,如下

  "devDependencies": {
    "electron": "^21.1.1"
  },

这是因为electron的开发和构建有些不同

开发时:依赖electron这个npm包

构建时:会将electron相关能力打入包内,而不直接使用electron这个npm包

所以对如上代码,需要抽取一个src文件夹,只放electron相关业务代码,如下

这里可以看到抽取了一个src文件夹放index.html,main.js,preload.js,以及package.json

外层也有一个package.json,和src内的package.json不一样

外层package.json内容如下:

负责提供开发时的electron环境,以及后续的打包事宜

{
  "name": "dishi-electron",
  "private": true,
  "version": "0.0.4",
  "devDependencies": {
    "electron": "^21.1.1"
  },
  "scripts": {
    "start": "electron electron-src"
  }
}

内层package.json内容如下:

负责electron应用的业务代码,主要是提供入口main.js的位置

{
  "name": "dishi",
  "private": true,
  "version": "0.0.3",
  "main": "main.js"
}

以上代码详见: https://github.com/uikoo9/dishi-monorepo/tree/dishi-electron%400.0.5

【electron-Mac打包】

上面已经用electron跑起一个本地的桌面应用了,

本地跑起应用后,是不是迫不及待想构建打包,发给小伙伴们看看?

桌面应用的打包分发分为两步:

1.构建好对应操作系统的应用,比如mac下的app,windows下exe等

2.将构建好的应用程序打成安装包,最终对外分发安装包

这里先进行第一步生成应用,

官方推荐的打包工具是:https://www.electronforge.io/

这里使用另一个工具进行打包,或者说生成应用, https://github.com/electron/electron-packager

由于后续打包相关的工作比较多,封装了一个打包工具, https://qiao-electron-cli.vincentqiao.com/#/

qiao-electron-cli:安装

先安装这个工具,如下,这个工具是打包使用,所以也是安装在外层文件夹

npm i -D qiao-electron-cli

qiao-electron-cli:配置

然后在src同级创建一个pack文件夹,引入一个配置文件qiao-electron.config.js,如下

每个字段都有备注,要关注的几个字段

arch:平台类型,例如我是mac非m1,选择x64

srcPath,srcFiles:就是上一步抽取src的文件夹,和最终桌面应用需要使用哪些文件,

distPath:会将src下的文件复制到dist,这是为了减少包体积,避免打入一些无用文件

// 主进程下的package.json
const srcPkg = require('../src/package.json');

// config
let config = {
  // app环境,online,test之类的,会拼接在dmg安装包名上
  appEnv: 'online',

  // app名称,默认从主进程下的package.json中获取
  appName: srcPkg.name,

  // app版本号,会显示在dmg安装包名以及关于面板上,默认从主进程下的package.json中获取
  appVersion: srcPkg.version,

  // app应用图标
  appIconPath: 'pack/static/icon/icon.icns',

  // app权限声明,会显示在关于面板上
  appCopyright: 'Copyright © 2022 dishi版权所有',

  // app操作系统,详见https://electron.github.io/electron-packager/main/interfaces/electronpackager.options.html#arch
  arch: 'x64',

  // app应用包中的app文件夹是否使用asar格式,默认为false
  asar: false,

  // app中主进程src路径
  srcPath: 'src',

  // 最终要打包到app应用包中的文件和文件夹,在dist这一步会复制出去
  srcFiles: ['index.html', 'main.js', 'preload.js', 'package.json'],

  // srcFiles中的文件和文件夹会复制到这个目录
  distPath: 'dist',

  // app应用包及dmg安装包生成的路径
  outPath: 'out',

  // app安装包dmg中的背景图
  dmgBackground: 'pack/static/bg.png',
};

// qe config
module.exports = config;

qiao-electron-cli:dist

qiao-electron-cli的dist命令,作用是将src中配置好的文件复制到dist文件夹,避免打包后引入多余的文件

执行这个命令

        "dist": "qelectron d ./pack/qiao-electron.config.js",

效果如下

qiao-electron-cli:packmac

packmac用来生成mac下的应用文件,同样可以在外层package.json中加入下面这些命令

        "dist": "qelectron d ./pack/qiao-electron.config.js",
        "prepackmac": "npm run dist",
        "packmac": "qelectron pm ./pack/qiao-electron.config.js",

执行npm run packmac,效果如下

可以看到执行命令后,src同层级,生成了dist文件夹存放待打包文件,out文件夹存放生成好的mac应用,

out文件下的dishi app已经是可以双击打开的mac应用了,

打开后的效果如下

以上代码见: https://github.com/uikoo9/dishi-monorepo/tree/dishi-electron%400.0.6

qiao-electron-cli:icon

可以看到上面跑起来的mac应用的图标是这样,右侧的Qz图标

这个图标是复用之前另一个应用了,这里做下定制,

之前pack/qiao-electron.config.js配置中有icon属性,如下

    // app应用图标
    appIconPath: 'pack/static/icon/icon.icns',

这里可以看到app icon需要一个icns文件,

icns的生成比较麻烦,所以qiao-electron-cli工具做了封装

qiao-electron-cli的icon命令用来将普通png生成为icns文件,

需要准备一个512*512的图,放到pack/static/icon/pic.png这个位置,

然后执行如下命令

"icon": "qelectron icon ./pack/static/icon/pic.png",

效果如下

同时会在icon文件夹下生成icns文件,

再次执行npm run packmac,打开应用查看图标,如下

由于修改的代码都是ignore的部分,所以代码还是这个版本:https://github.com/uikoo9/dishi-monorepo/tree/dishi-electron%400.0.6

qiao-electron-cli:packdmg

生成本地应用,和定制mac图标后,接着是进行打包了,

执行下面的命令

        "packdmg": "qelectron pd ./pack/qiao-electron.config.js",

即可生成dmg文件,如下

打开dmg后,效果如下

这里左侧显示滴石是qiao-electron.config.js中的

    appName: '滴石',

左侧以及title上显示的icon是qiao-electron.config.js中的

    appIconPath: 'pack/static/icon/icon.icns',

整个界面的背景图是qiao-electron.config.js中的

    dmgBackground: 'pack/static/bg.png',

打开dmg的同时在mac桌面会生成如下图标,这个是安装包的图标

按图示将滴石DS拖动到右侧applications中,后在应用程序中就可以找到运行的图标了

运行后的效果

以上代码详见: https://github.com/uikoo9/dishi-monorepo/tree/dishi-electron%400.0.7

qiao-electron-cli:uploaddmg

生成dmg后为了方便分发,可以上传到一些文件服务器,比如cos,

qiao-electron-cli中封装了上传到cos的命令uploaddmg,

需要在qiao-electron.config.js中配置cos的config,如下

// cos config,可以配置cos,直接上传到cos上
const cosConfig = require('./config.json');
config.cosConfig = {
  SecretId: cosConfig.SecretId,
  SecretKey: cosConfig.SecretKey,
  Region: cosConfig.Region,
  Bucket: cosConfig.Bucket,
  destPath: '21_dishi/dmg',
};

然后执行如下命令即可

        "uploaddmg": "qelectron ud ./pack/qiao-electron.config.js"

以上代码详见: https://github.com/uikoo9/dishi-monorepo/tree/dishi-electron%400.0.8

【electron-Mac定制】

到这里学习到了这些内容:

1.electron:简介

2.electron:安装

3.electron:helloworld

4.electron:打包mac应用

5.electron:定制mac图标

6.electron:打包mac安装包

web项目

以上内容都是基于hello world,下面基于之前的一个web项目继续,

地址: https://insistime.com/dishi-indexeddb

文章: https://blog.insistime.com/indexeddb

代码: https://github.com/uikoo9/dishi-monorepo/tree/indexeddb

这个web项目基本是一个本地项目,基于本地的IndexedDB,

所以比较好内嵌到electron中,

通过dishi-web项目下的webpack,新建一个webpack配置文件,将项目构建到dishi-electron/src/renderer下

主进程文件调整

由于src下新增了renderer文件夹,对应的新增一个main文件夹,用来存放主进程代码

主进程这里引入另一个工具npm包,方便使用electron的能力, https://code.insistime.com/#/qiao-electron

调整后如下

自定义菜单和关于面板

可以看到之前滴石启动后的菜单是默认的,如下

这里通过qiao-electron的方法,即可自定义菜单,代码如下,在src/main/init/init-menu.js中

'use strict';

// q
const { setApplicationMenu, setAboutVersion } = require('qiao-electron');

// version
const { version } = require('../../package.json');

// set application menu
setApplicationMenu();

// set about version
setAboutVersion(version);

定制后效果如下

自定义标题栏

目前标题栏效果如下

看着比较丑,可以在创建window时添加这个属性隐藏标题栏

titleBarStyle: 'hiddenInset',

隐藏后效果如下

但是顶部不可拖动了,需要修改下html和css

html添加一个title,css也做对应修改

这样顶部就可以拖动了,并且隐藏了标题栏

最终效果如下

以上代码详见: https://github.com/uikoo9/dishi-monorepo/tree/dishi-electron%400.1.2

【electron-进程和通信】

上面有说到electron分为主进程和渲染进程,

渲染进程,开发ui

主进程,处理操作系统相关事情

这里用mac下的活动监视器查看这个项目跑起来后的进程,

由于应用名称叫滴石,直接搜索滴石即可,如下,

其中第一个就是主进程,renderer的就是渲染进程

这里演示一下简单的进程通信,例如渲染进程从主进程拿到应用的版本号

主进程通过ipcMain做监听,如下

ipcMain.handle(IPC_APP_GET_VERSION, () => {
  return version;
});

渲染进程通过ipcRenderer获取主进程的版本号,如下

/**
 * appGetVersionIPC
 * @returns version
 */
export const appGetVersionIPC = async () => {
  return await ipcRenderer.invoke(IPC_APP_GET_VERSION);
};

将上述代码放到window的preload.js文件中,即可在渲染进程的js中调用,如下

const v = await window.electron.appGetVersionIPC();

最终渲染进程中的preload.js提供了获取版本的方法,preload中通过ipc通信获取到主进程返回的版本,效果如下

以上代码详见:  https://github.com/uikoo9/dishi-monorepo/tree/dishi-electron%400.1.4

【qiao-electron】

qiao-electron

1.https://code.insistime.com/#/qiao-electron

2.封装了很多electron常用的能力

qiao-electron-cli

1. https://qiao-electron-cli.vincentqiao.com/#/

2.封装了electron打包相关的能力

【总结】

到这里,用electron开发完了一个mac应用,

以上代码详见: https://github.com/uikoo9/dishi-monorepo/tree/electron

1.electron-简介

2.electron-安装

3.electron-hello world

4.electron-使用qiao-electron-cli的packmac命令打包mac应用

5.electron-使用qiao-electron-cli的icon命令制作mac图标

6.electron-使用qiao-electron-cli的packdmg命令打包mac安装包dmg

7.electron-使用qiao-electron-cli的uploaddmg命令上传dmg到cos

8.electron-使用qiao-electron定制mac菜单

9.electron-使用qiao-electron定制mac关于面板

10.electron-mac定制无标题栏应用

11.electron-进程和通信

12.electron-使用qiao-electron获取app版本号

13.electron-electron专栏: https://blog.csdn.net/uikoo9/category_11468921.html

© 2026 Vincent. 保留所有权利。