写点什么

Electron 入门【01】

作者:坚果
  • 2022 年 7 月 10 日
  • 本文字数:5968 字

    阅读完需:约 20 分钟

Electron 是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 ChromiumNode.js 到 二进制的 Electron 允许您保持一个 JavaScript 代码代码库并创建 在 Windows 上运行的跨平台应用 macOS 和 Linux——不需要本地开发 经验。

快速入门

本文会通过使用 Electron 创建一个极简的 Hello World 应用一步步的带你了解 Electron 的前世今生,


通过这个教程,你的 app 将会打开一个浏览器窗口,来展示包含当前正在运行的 Chromium, Node.js 与 Electronweb 等版本信息的 web 界面


在使用 Electron 进行开发之前,您需要安装 Node.js。 我们建议您使用最新的 LTS 版本。


请使用为你平台预构建的 Node.js 安装器来进行安装, 否则,您可能会遇到与不同开发工具不兼容的问题。


要检查 Node.js 是否正确安装,请在您的终端输入以下命令:


node -vnpm -v
复制代码


这两个命令应输出了 Node.js 和 npm 的版本信息。

创建你的应用程序

使用脚手架创建

Electron 应用程序遵循与其他 Node.js 项目相同的结构。 首先创建一个文件夹并初始化 npm 包。


  • npm

  • Yarn


mkdir my-electron-app && cd my-electron-appnpm init

yarn add --dev electron
复制代码


init初始化命令会提示您在项目初始化配置中设置一些值,有几条规则需要遵循:


  • entry point 应为 main.js.

  • authordescription 可为任意值,但对于应用打包是必填项。


你的 package.json 文件应该像这样:


{  "name": "my-electron-app",  "version": "1.0.0",  "description": "Hello World!",  "main": "main.js",  "author": "Jane Doe",  "license": "MIT"}
复制代码


然后,将 electron 包安装到应用的开发依赖中。


  • npm

  • Yarn


npm install --save-dev electron
复制代码


最后,您希望能够执行 Electron 如下所示,在您的[package.json配置文件中的scripts字段下增加一条start命令:


{  "scripts": {    "start": "electron ."  }}
复制代码


start命令能让您在开发模式下打开您的应用


  • npm

  • Yarn


npm start
复制代码


yarn start# couldn't auto-convert command
复制代码


注意:此脚本将告诉 Electron 在您项目根目录运行 此时,您的应用将立即抛出一个错误提示您它无法找到要运行的应用

运行主进程

任何 Electron 应用程序的入口都是 main 文件。 这个文件控制了主进程,它运行在一个完整的 Node.js 环境中,负责控制您应用的生命周期,显示原生界面,执行特殊操作并管理渲染器进程(稍后详细介绍)。


执行期间,Electron 将依据应用中 package.json配置下main字段中配置的值查找此文件


要初始化这个main文件,需要在您项目的根目录下创建一个名为main.js的空文件。


注意:如果您此时再次运行start命令,您的应用将不再抛出任何错误! 然而,它不会做任何事因为我们还没有在main.js中添加任何代码。

创建页面

在可以为我们的应用创建窗口前,我们需要先创建加载进该窗口的内容。 在 Electron 中,各个窗口显示的内容可以是本地 HTML 文件,也可以是一个远程 url。


此教程中,您将采用本地 HTML 的方式。 在您的项目根目录下创建一个名为index.html的文件:


<!DOCTYPE html><html>  <head>    <meta charset="UTF-8">    <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->    <meta http-equiv="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>.  </body></html>
复制代码


注意:在这个 HTML 文本中,您会发现主体文本中丢失了版本编号。 稍后我们将使用 JavaScript 动态插入它们。

在窗口中打开您的页面

现在您有了一个页面,将它加载进应用窗口中。 要做到这一点,你需要 两个 Electron 模块:


  • app模块,它控制应用程序的事件生命周期。

  • BrowserWindow 模块,它创建和管理应用程序 窗口。


因为主进程运行着 Node.js,您可以在 main.js 文件头部将它们导入作为 CommonJS 模块:


const { app, BrowserWindow } = require('electron')
复制代码


然后,添加一个createWindow()方法来将index.html加载进一个新的BrowserWindow实例。


const createWindow = () => {  const win = new BrowserWindow({    width: 800,    height: 600  })
win.loadFile('index.html')}
复制代码


接着,调用createWindow()函数来打开您的窗口。


在 Electron 中,只有在 app 模块的 ready事件被激发后才能创建浏览器窗口。 您可以通过使用 app.whenReady()API 来监听此事件。 在whenReady()成功后调用createWindow()


app.whenReady().then(() => {  createWindow()})
复制代码


注意:此时,您的电子应用程序应当成功 打开显示您页面的窗口!

管理窗口的生命周期

虽然你现在可以打开一个浏览器窗口,但你还需要一些额外的模板代码使其看起来更像是各平台原生的。 应用程序窗口在每个 OS 下有不同的行为,Electron 将在 app 中实现这些约定的责任交给开发者们。


一般而言,你可以使用 进程 全局的 platform属性来专门为某些操作系统运行代码。

关闭所有窗口时退出应用 (Windows & Linux)

在 Windows 和 Linux 上,关闭所有窗口通常会完全退出一个应用程序。


为了实现这一点,你需要监听 app 模块的 'window-all-closed'事件。如果用户不是在 macOS(darwin) 上运行程序,则调用 app.quit()


app.on('window-all-closed', () => {  if (process.platform !== 'darwin') app.quit()})
复制代码

如果没有窗口打开则打开一个窗口 (macOS)

当 Linux 和 Windows 应用在没有窗口打开时退出了,macOS 应用通常即使在没有打开任何窗口的情况下也继续运行,并且在没有窗口可用的情况下激活应用时会打开新的窗口。


为了实现这一特性,监听 app 模块的 activate事件。如果没有任何浏览器窗口是打开的,则调用 createWindow() 方法。


因为窗口无法在 ready 事件前创建,你应当在你的应用初始化后仅监听 activate 事件。 通过在您现有的 whenReady() 回调中附上您的事件监听器来完成这个操作。


app.whenReady().then(() => {  createWindow()
app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) createWindow() })})
复制代码


注意:此时,您的窗口控件应功能齐全!

通过预加载脚本从渲染器访问 Node.js。

现在,最后要做的是输出 Electron 的版本号和它的依赖项到你的 web 页面上。


在主进程通过 Node 的全局 process 对象访问这个信息是微不足道的。 然而,你不能直接在主进程中编辑 DOM,因为它无法访问渲染器 文档 上下文。 它们存在于完全不同的进程!


这是将 预加载 脚本连接到渲染器时派上用场的地方。 预加载脚本在渲染器进程加载之前加载,并有权访问两个 渲染器全局 (例如 windowdocument) 和 Node.js 环境。


创建一个名为 preload.js 的新脚本如下:


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]) }})
复制代码


上面的代码访问 Node.js process.versions 对象,并运行一个基本的 replaceText 辅助函数将版本号插入到 HTML 文档中。


要将此脚本附加到渲染器流程,请在你现有的 BrowserWindow 构造器中将路径中的预加载脚本传入 webPreferences.preload 选项。


// include the Node.js 'path' module at the top of your fileconst path = require('path')
// modify your existing createWindow() functionconst createWindow = () => { const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: path.join(__dirname, 'preload.js') } })
win.loadFile('index.html')}// ...
复制代码


这里使用了两个 Node.js 概念:


  • __dirname字符串指向当前正在执行脚本的路径 (在本例中,它指向你的项目的根文件夹)。

  • path.joinAPI 将多个路径联结在一起,创建一个跨平台的路径字符串。


我们使用一个相对当前正在执行 JavaScript 文件的路径,这样您的相对路径将在开发模式和打包模式中都将有效。

将功能添加到您的网页内容

此刻,您可能想知道如何为您的应用程序添加更多功能。


对于与您的网页内容的任何交互,您想要将脚本添加到您的渲染器进程中。 由于渲染器运行在正常的 Web 环境中,因此您可以在 index.html 文件关闭 </body> 标签之前添加一个 <script> 标签,来包括您想要的任意脚本:


<script src="./renderer.js"></script>
复制代码


renderer.js 中包含的代码可以在接下来使用与前端开发相同的 JavaScript API 和工具。例如使用 webpack 打包并最小化您的代码,或者使用 React 来管理您的用户界面。

回顾

完成上述步骤后,您应该有一个功能齐全的 Electron 程序,如下所示:


完整代码如下:


// main.js
// Modules to control application life and create native browser windowconst { app, BrowserWindow } = require('electron')const path = require('path')
const createWindow = () => { // Create the browser window. 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', () => { // On macOS it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. if (BrowserWindow.getAllWindows().length === 0) createWindow() })})
// 除了 macOS 外,当所有窗口都被关闭的时候退出程序。 There, it's common// for applications and their menu bar to stay active until the user quits// explicitly with Cmd + Q.app.on('window-all-closed', () => { if (process.platform !== 'darwin') app.quit()})
// In this file you can include the rest of your app's specific main process// code. 也可以拆分成几个文件,然后用 require 导入。
复制代码


// 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]) }})
复制代码


<!--index.html-->
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --> <meta http-equiv="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>
复制代码


总结我们所做的所有步骤:


  • 我们启动了一个 Node.js 程序,并将 Electron 添加为依赖。

  • 我们创建了一个 main.js 脚本来运行我们的主要进程,它控制我们的应用程序 并且在 Node.js 环境中运行。 在此脚本中, 我们使用 Electron 的 appBrowserWindow 模块来创建一个浏览器窗口,在一个单独的进程(渲染器)中显示网页内容。

  • 为了访问渲染器中的 Node.js 的某些功能,我们在 BrowserWindow 的构造函数上附加了一个预加载脚本。

打包并分发您的应用程序

最快捷的打包方式是使用 Electron Forge


将 Electron Forge 添加到您应用的开发依赖中,并使用其"import"命令设置 Forge 的脚手架:


  • npm

  • Yarn


npm install --save-dev @electron-forge/clinpx electron-forge import
✔ Checking your system✔ Initializing Git Repository✔ Writing modified package.json file✔ Installing dependencies✔ Writing modified package.json file✔ Fixing .gitignore
We have ATTEMPTED to convert your app to be in a format that electron-forge understands.
Thanks for using "electron-forge"!!!
复制代码


yarn add --dev @electron-forge/clinpx electron-forge import
✔ Checking your system✔ Initializing Git Repository✔ Writing modified package.json file✔ Installing dependencies✔ Writing modified package.json file✔ Fixing .gitignore
We have ATTEMPTED to convert your app to be in a format that electron-forge understands.
Thanks for using "electron-forge"!!!
复制代码


使用 Forge 的 make 命令来创建可分发的应用程序:


  • npm

  • Yarn


npm run make
> my-electron-app@1.0.0 make /my-electron-app> electron-forge make
✔ Checking your system✔ Resolving Forge ConfigWe need to package your application before we can make it✔ Preparing to Package Application for arch: x64✔ Preparing native dependencies✔ Packaging ApplicationMaking for the following targets: zip✔ Making for target: zip - On platform: darwin - For arch: x64
复制代码


yarn run make
> my-electron-app@1.0.0 make /my-electron-app> electron-forge make
✔ Checking your system✔ Resolving Forge ConfigWe need to package your application before we can make it✔ Preparing to Package Application for arch: x64✔ Preparing native dependencies✔ Packaging ApplicationMaking for the following targets: zip✔ Making for target: zip - On platform: darwin - For arch: x64
复制代码


Electron-forge 会创建 out 文件夹,您的软件包将在那里找到:


// Example for macOSout/├── out/make/zip/darwin/x64/my-electron-app-darwin-x64-1.0.0.zip├── ...└── out/my-electron-app-darwin-x64/my-electron-app.app/Contents/MacOS/my-electron-app
复制代码


发布于: 刚刚阅读数: 3
用户头像

坚果

关注

此间若无火炬,我便是唯一的光 2020.10.25 加入

公众号:“大前端之旅”,华为云享专家,InfoQ签约作者,51CTO博客首席体验官,专注于大前端技术的分享,包括Flutter,小程序,安卓,VUE,JavaScript。

评论

发布
暂无评论
Electron入门【01】_7 月月更_坚果_InfoQ写作社区