进击Electron(1)——初次使用和创建一个完整Electron桌面应用,及在vscode中调试Electron主进程

2,189 阅读7分钟

本文已参与掘金创作者训练营第三期「话题写作」赛道,详情查看:掘力计划|创作者训练营第三期正在进行,「写」出个人影响力

Electron

Electron 是一个使用 JavaScript、 HTML 和 CSS 等 Web 技术创建跨平台桌面应用程序的框架,可以通过纯 JavaScript 调用丰富的原生(操作系统) APIs 来创造桌面应用,可以看作Node.js的一种变体,只不过是用于桌面应用开发。

如下,是一个 Electron 应用开发的架构和工具链:

环境配置

  1. 安装最新版本的Node.js ,勾选Node.js runtime、npm package manager和Add to PATH。

  2. 命令行中确认是否安装

# 打印出Node.js的版本信息
node -v

# 打印出npm的版本信息
npm -v
  1. 使用一个js编辑器即可,推荐VSCode

  2. 安装淘宝NPM镜像

npm install -g cnpm --registry=https://registry.npm.taobao.org
  1. 或者,使用Yran包管理
npm install -g yarn

打造第一个 Electron 应用

Electron 可以看作是一个被 JavaScript 控制的,精简版的 Chromium 浏览器。其开发工具链也是基于node,其开发是一个完整的node项目的开发过程。

目录结构

Electron application 本质上是一个 Node.js 应用程序。 应用的入口是 package.json 文件。

一个最基本的 Electron 应用一般来说会有如下的目录结构:

your-app/
├── package.json
├── main.js
└── index.html

初始化和安装

  • npm init初始化一个新的Electron应用
$ mkdir my-electron-app && cd my-electron-app
$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (app1) firstelectronapp
version: (1.0.0)
description: 第一个Electron应用
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to E:\vscode\Electron\App1\package.json:

{
  "name": "firstelectronapp",
  "version": "1.0.0",
  "description": "第一个Electron应用",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this OK? (yes)

npm 会创建一个基本的 package.json 文件。main 表示的是应用的启动脚本,在主进程中执行。

package.json 缺省main字段时,Electron 将会尝试加载 index.js 文件。

和Node应用类似,可以添加一个start脚本,指定Electron执行当前的项目目录:

{
  "name": "firstelectronapp",
  "version": "1.0.0",
  "description": "第一个Electron应用",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "electron ."
  }
}
  • 安装Electron

推荐将Electron作为 app 中的开发依赖项安装,不同的app可以使用不同版本Electron

cnpm install --save-dev electron

Electron安装报错问题

Electron在安装时的报错问题,如下:

Install fail! Error: EISDIR: illegal operation on a directory, symlink 'E:\vscode\Electron\App1\node_modules\_@types_node@12.12.26@@types\node' -> 'E:\vscode\Electron\App1\node_modules\_electron@7.1.11@electron\node_modules\@types\node'
Error: EISDIR: illegal operation on a directory, symlink 'E:\vscode\Electron\App1\node_modules\_@types_node@12.12.26@@types\node' -> 'E:\vscode\Electron\App1\node_modules\_electron@7.1.11@electron\node_modules\@types\node'
npminstall version: 3.27.0

这个问题一般是由于磁盘格式是 FAT32 导致的,将磁盘格式改为NTFS,删除node_modules重新安装即可。

怎样将FAT32格式磁盘转换为NTFS格式

比如,将E盘转换为NTFS格式:convert E: /FS:NTFS /X

简易Electron

引入Electron模块

const electron = require('electron')

electron 模块所提供的功能都是通过命名空间暴露出来的。 比如说: electron.app负责管理 Electron 应用程序的生命周期, electron.BrowserWindow类负责创建窗口。

创建一个简单窗口

  • 如下,在main入口文件中添加如下创建窗口的代码
const { app, BrowserWindow } = require('electron')

function createWindow() {
    // 创建浏览器窗口
    let win = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            nodeIntegration: true
        }
    })

    // 加载index.html文件。加载的文件必须位于当前项目目录下,外层目录将无法加载
    win.loadFile('index.html')
}

app.on('ready', createWindow)
  • index.html中为简单的Hello信息和一个弹窗
<div>
    <span>Hello Eletron</span>
    <button id="btn">点击</button>
</div>
<script type="text/javascript">
    var btn = document.getElementById("btn");
    btn.addEventListener("click", function () {
        alert("你好,欢迎使用Electron!")
    })
</script>
  • npm start 启动Electron程序,查看效果:

优化Electron程序

一般都是在 main 入口文件中创建窗口,并处理程序中可能遇到的所有系统事件。

如下,在main入口文件中添加以下功能:打开开发者工具、处理窗口关闭事件、在macOS用户点击dock上图标时重建窗口:

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

// 保持对window对象的全局引用,如果不这么做的话,当JavaScript对象被
// 垃圾回收的时候,window对象将会自动的关闭。
let win

function createWindow() {
    // 创建浏览器窗口。
    win = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            nodeIntegration: true
        }
    })

    // 加载index.html文件
    win.loadFile('index.html')

    // 打开开发者工具
    win.webContents.openDevTools()

    // 当 window 被关闭,这个事件会被触发。
    win.on('closed', () => {
        // 取消引用 window 对象,如果你的应用支持多窗口的话,
        // 通常会把多个 window 对象存放在一个数组里面,
        // 与此同时,你应该删除相应的元素。
        win = null
    })
}

// Electron 会在初始化后并准备
// 创建浏览器窗口时,调用这个函数。
// 部分 API 在 ready 事件触发后才能使用。
app.on('ready', createWindow)

// 当全部窗口关闭时退出。
app.on('window-all-closed', () => {
    // 在 macOS 上,除非用户用 Cmd + Q 确定地退出,
    // 否则绝大部分应用及其菜单栏会保持激活。
    if (process.platform !== 'darwin') {
        app.quit()
    }
})

app.on('activate', () => {
    // 在macOS上,当单击dock图标并且没有其他窗口打开时,
    // 通常在应用程序中重新创建一个窗口。
    if (win === null) {
        createWindow()
    }
})

// 在这个文件中,你可以续写应用剩下主进程代码。
// 也可以拆分成几个文件,然后用 require 导入。

由于窗口无法在 ready 事件前创建activate 事件的监听可以放在ready中处理。如下所示:

最新版本的 Electron 基于Promise实现的 ready 事件,推荐如下写法:

app.whenReady().then(() => {
  createWindow()

  app.on('activate', function () {
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})

Electron主进程的调试

对于窗口内页面的代码调试,可以通过Electron浏览器窗口的DevTools(开发者工具)。

但是对于主进程调试,必须依靠 Electron 提供的 --inspect--inspect-brk 开关。详见调试主进程

在vscode中调试主进程

  1. 如下,在 package.json 文件下的scripts脚本下添加debug项。
{
 "scripts": {
    "start": "electron .",
    "debug": "electron --inspect=5858 ."
  }
}
  1. 如下,在vscode的调试运行菜单下,新建launch.json文件,并添加"附加到进程"的配置项。

如下,指定"request"为"attach",端口和上面script配置中inspect值相同。

launch.json文件中:

        {
            "type":"node",
            "request": "attach",
            "name": "附加到进程",
            "port": 5858,
            "address": "localhost"
        }
  1. yarn debug运行electron程序
$ yarn debug
yarn run v1.21.1
$ electron --inspect=5858 .

 Debugger listening on ws://127.0.0.1:5858/c115b336-f5d4-42f4-85a7-3ef807d9d8a4
For help, see: https://nodejs.org/en/docs/inspector
  1. electron执行inspect后,运行vscode中"调试与运行"下的“附加到进程”项,这样就可以调试主进程。

开启调试主进程开关

  • --inspect=[port], 比如: electron --inspect=5858 your/app
  • --inspect-brk=[port],和--inspector 一样,但js会在运行的第一行暂停执行。

官方文档写着会默认打开5858端口,但实际测试默认打开的是其他端口,为了附加到进程成功,指定其端口为5858。

运行electron .可能的报错的处理

运行 electron . 时出错 xxx\node_modules\electron\index.js:14 throw new Error('Electron failed to install correctly, please delete node_modules/electron and try installing again,该问题的发生处理如下:

基于以上的代码,运行electron .可以正常执行,启动窗口并使用。

但在很久之后的一次重新运行npm run start(即electron .),竟然报这个错:

e:\vscode\Electron\WaterfullElectron\node_modules\electron\index.js:14
    throw new Error('Electron failed to install correctly, please delete node_modules/electron and try installing again')
    ^

Error: Electron failed to install correctly, please delete node_modules/electron and try installing again
    at getElectronPath (e:\vscode\Electron\WaterfullElectron\node_modules\electron\index.js:14:11)
    at Object.<anonymous> (e:\vscode\Electron\WaterfullElectron\node_modules\electron\index.js:18:18)
    at Module._compile (internal/modules/cjs/loader.js:955:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:991:10)
    at Module.load (internal/modules/cjs/loader.js:811:32)
    at Function.Module._load (internal/modules/cjs/loader.js:723:14)
    at Module.require (internal/modules/cjs/loader.js:848:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at Object.<anonymous> (e:\vscode\Electron\WaterfullElectron\node_modules\electron\cli.js:3:16)
    at Module._compile (internal/modules/cjs/loader.js:955:30)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! waterfullimageviewer@0.1.0 start: `electron .`
npm ERR! Exit status 1
npm ERR!
ging output above.

查看node_modules\electron\index.js:14的内容,是判断path.txt时出现的错误,而且文件确实不存在。

起先参考Electron 安装报错 'Electron failed to install correctly',基本步骤都是一样的,但是electron项目下node install的执行,下载的electron文件确实存在[虽然下载时卡住],切换npm包镜像源运行下载也能成功。

但是执行run start还是一样的错。

中间尝试修改Temp权限、重新下载等均不行。。。。

最后参考Stack Overflow下Electron failed to install correctly, please delete node_modules/electron and try installing again. Could it be a conflict of versions?的解决办法,手动下载Electron文件并修改path.txt文件解决。

Please do the following steps in order to solve the problem:

Create a file named path.txt in node_modules\electron folder.(创建path.txt)

Write electron.exe in it. (path.txt文件内容为:electron.exe )

Download electron package manualy. Maybe from: fossies.org/windows/www… (下载 在node_modules/electron下执行node install时显示出来的、对应于你的系统的 Electron zip包文件,或者直接下载对应系统的Electron版本即可,我的是 github.com/electron/el…)

Unpackage the electron files into node_modules\electron\dist (node_modules/electron下新建dist文件夹,并将解压后的electron files放到里面)

Run your start script (再次运行 npm run startyarn start,成功运行,打开Electron程序)

参考