# my-electron-app
**Repository Path**: zhao-jingtao-l_admin/my-electron-app
## Basic Information
- **Project Name**: my-electron-app
- **Description**: Electron 应用基于 npm 搭建
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2024-10-15
- **Last Updated**: 2024-12-14
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 创建您的第一个应用程序
教程目录
这是 Electron 教程的**第二部分**。
1. [基本要求](https://www.electronjs.org/zh/docs/latest/tutorial/tutorial-prerequisites)
2. **[创建您的第一个应用程序](https://www.electronjs.org/zh/docs/latest/tutorial/tutorial-first-app)**
3. [使用预加载脚本](https://www.electronjs.org/zh/docs/latest/tutorial/tutorial-preload)
4. [添加功能](https://www.electronjs.org/zh/docs/latest/tutorial/tutorial-adding-features)
5. [打包您的应用程序](https://www.electronjs.org/zh/docs/latest/tutorial/打包教程)
6. [发布和更新](https://www.electronjs.org/zh/docs/latest/tutorial/推送更新教程)
## 学习目标
在本节,您会学习如何创建您的 Electron 项目,并且编写一个简单的入门程序。 到了本节末尾,您应该能够在终端开发环境运行一个 Electron 应用。
## 创建项目
避免使用 WSL
如果您使用的是Windows系统,在本教程中请不要使用 [Windows Subsystem for Linux](https://learn.microsoft.com/en-us/windows/wsl/about#what-is-wsl-2) (WSL),否则您在尝试运行应用时可能会遇到问题。
### 初始化 npm 项目
Electron 应用基于 npm 搭建,以 package.json 文件作为入口点。 首先创建一个文件夹,然后在其中执行 `npm init` 初始化项目。
- npm
- Yarn
```sh
mkdir my-electron-app && cd my-electron-app
npm init
```
这条命令会帮您配置 package.json 中的一些字段。 为本教程的目的,有几条规则需要遵循:
- *入口点* 应当是 `main.js` (您很快就会创建它)
- *author*、*license* 和 _description_可为任意值,但对于 [应用打包](https://www.electronjs.org/zh/docs/latest/tutorial/打包教程) 是必填项。
然后,将 Electron 安装为您项目的 **devDependencies**,即仅在开发环境需要的额外依赖。
为什么 Electron 是 devDependency?
您的应用需要运行 Electron API,因此这听上去可能有点反直觉。 实际上,打包后的应用本身会包含 Electron 的二进制文件,因此不需要将 Electron 作为生产环境依赖。
- npm
- Yarn
```sh
npm install electron --save-dev
```
在初始化并且安装完 Electron 之后,您的 package.json 应该长下面这样。 文件夹中会出现一个 `node_modules` 文件夹,其中包含了 Electron 可执行文件;还有一个 `package-lock.json` 文件,指定了各个依赖的确切版本。
package.json
```json
{
"name": "my-electron-app",
"version": "1.0.0",
"description": "Hello World!",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Jane Doe",
"license": "MIT",
"devDependencies": {
"electron": "23.1.3"
}
}
```
高级安装步骤
如果直接安装 Electron 失败,请参考我们的 [安装指导](https://www.electronjs.org/zh/docs/latest/tutorial/installation) 文档,了解有关下载镜像、代理和故障排除步骤的说明。
### 添加 .gitignore 文件
[`.gitignore`](https://git-scm.com/docs/gitignore) 文件可以指定哪些文件和目录应该在Git中不被跟踪。 建议您复制一份 [GitHub 的 Node.js gitignore 模板](https://github.com/github/gitignore/blob/main/Node.gitignore) 到您项目的根目录,以避免将 `node_modules` 文件夹提交到版本控制系统中。
## 运行 Electron 应用
:::延伸阅读
参阅 [Electron 进程模型(process model)](https://www.electronjs.org/zh/docs/latest/tutorial/process-model) 相关文档来了解 Electron 的进程之间是如何协作的。
:::
您在 package.json 中指定的 [`main`](https://docs.npmjs.com/cli/v7/configuring-npm/package-json#main) 文件是 Electron 应用的入口。 这个文件控制 **主程序 (main process)**,它运行在 Node.js 环境里,负责控制您应用的生命周期、显示原生界面、执行特殊操作并管理渲染器进程 (renderer processes),稍后会详细介绍。
在继续编写您的 Electron 应用之前,您将使用一个小小的脚本来确保主进程入口点已经配置正确。 在根目录的 `main.js` 文件中写一行代码:
main.js
```js
console.log('Hello from Electron 👋')
```
由于 Electron 的主进程是一个 Node.js 运行时,您可以使用 `electron` 命令执行任意的 Node.js 代码 (甚至可以将其作为 [REPL](https://www.electronjs.org/zh/docs/latest/tutorial/repl) 使用)。 要执行这个脚本,需要在 package.json 的 [`scripts`](https://docs.npmjs.com/cli/v7/using-npm/scripts) 字段中添加一个 `start` 命令,内容为 `electron .` 。 这个命令会告诉 Electron 在当前目录下寻找主脚本,并以开发模式运行它。
package.json
```json
{
"name": "my-electron-app",
"version": "1.0.0",
"description": "Hello World!",
"main": "main.js",
"scripts": {
"start": "electron .",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Jane Doe",
"license": "MIT",
"devDependencies": {
"electron": "23.1.3"
}
}
```
- npm
- Yarn
```sh
npm run start
```
您的终端应该会输出 `欢迎来到 Electron 👋`。 恭喜,您已经在 Electron 中执行了您的第一行代码! 接下来,您会学习如何用 HTML 创建用户界面,并将它们装载到原生窗口中。
## 将网页装载到 BrowserWindow
在 Electron 中,每个窗口展示一个页面,后者可以来自本地的 HTML,也可以来自远程 URL。 在本例中,您将会装载本地的文件。 在您项目的根目录中创建一个 `index.html` 文件,并写入下面的内容:
index.html
```html
Hello from Electron renderer!
Hello from Electron renderer!
👋
```
现在您有了一个网页,您可以将其加载到一个 Electron 的 [BrowserWindow](https://www.electronjs.org/zh/docs/latest/api/browser-window) 上了。 将 `main.js` 中的内容替换成下列代码。 我们马上会逐行解释。
main.js
```js
const { app, BrowserWindow } = require('electron')
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
})
```
### 导入模块
main.js (Line 1)
```js
const { app, BrowserWindow } = require('electron')
```
在第一行中,我们使用 CommonJS 语法导入了两个 Electron 模块:
- [app](https://www.electronjs.org/zh/docs/latest/api/app),它着您应用程序的事件生命周期。
- [BrowserWindow](https://www.electronjs.org/zh/docs/latest/api/browser-window),它负责创建和管理应用窗口。
模块名的大小写规范
类型化导入别名
Electron 中的 ES 模块
Electron 28 起,Electron 支持[ECMAScript 模块](https://nodejs.org/api/esm.html)(即使用 `import` 加载模块)。 您可以在我们的 [ESM 指南](https://www.electronjs.org/zh/docs/latest/tutorial/esm) 中找到有关 Electron 中 ESM 状态以及如何在我们的应用程序中使用它们的更多信息。
### 将可复用的函数写入实例化窗口
`createWindow()` 函数将您的页面加载到新的 BrowserWindow 实例中:
main.js (Lines 3-10)
```js
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile('index.html')
}
```
### 在应用准备就绪时调用函数
main.js (Lines 12-14)
```js
app.whenReady().then(() => {
createWindow()
})
```
Electron 的许多核心模块都是 Node.js 的[事件触发器](https://nodejs.org/api/events.html#events),遵循 Node.js 的异步事件驱动架构。 app 模块就是其中一个。
在 Electron 中,只有在 app 模块的 [`ready`](https://www.electronjs.org/zh/docs/latest/api/app#event-ready) 事件触发后才能创建 BrowserWindows 实例。 您可以通过使用 [`app.whenReady()`](https://www.electronjs.org/zh/docs/latest/api/app#appwhenready) API 来监听此事件,并在其成功后调用 `createWindow()` 方法。
info
通常我们使用触发器的 `.on` 函数来监听 Node.js 事件。
```diff
+ app.on('ready', () => {
- app.whenReady().then(() => {
createWindow()
})
```
但是 Electron 暴露了 `app.whenReady()` 方法,作为其 `ready` 事件的专用监听器,这样可以避免直接监听 .on 事件带来的一些问题。 参见 [electron/electron#21972](https://github.com/electron/electron/pull/21972) 。
此时,运行 `start` 命令应该能成功地打开一个包含您网页内容的窗口!
您应用中的每个页面都在一个单独的进程中运行,我们称这些进程为 **渲染器 (\*renderer\*)** 。 渲染进程使用与常规Web开发相同的JavaScript API和工具,例如使用 [webpack](https://webpack.js.org/)来打包和压缩您的代码,或使用 [React](https://reactjs.org/) 构建用户界面。
## 管理应用的窗口生命周期
应用窗口在不同操作系统中的行为也不同。 Electron 允许您自行实现这些行为来遵循操作系统的规范,而不是采用默认的强制执行。 您可以通过监听 app 和 BrowserWindow 模组的事件,自行实现基础的应用窗口规范。
针对特定进程的控制流
通过检查 Node.js 的 [`process.platform`](https://nodejs.org/api/process.html#process_process_platform) 变量,您可以针对特定平台运行特定代码。 请注意,Electron 目前只支持三个平台:`win32` (Windows), `linux` (Linux) 和 `darwin` (macOS) 。
### 关闭所有窗口时退出应用 (Windows & Linux)
在 Windows 和 Linux 上,我们通常希望在关闭一个应用的所有窗口后让它退出。 要在您的Electron应用中实现这一点,您可以监听 app 模块的 [`window-all-closed`](https://www.electronjs.org/zh/docs/latest/api/app#event-window-all-closed) 事件,并调用 [`app.quit()`](https://www.electronjs.org/zh/docs/latest/api/app#appquit) 来退出您的应用程序。此方法不适用于 macOS。
```js
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
```
### 如果没有窗口打开则打开一个窗口 (macOS)
与前二者相比,即使没有打开任何窗口,macOS 应用通常也会继续运行。 在没有窗口可用时调用 app 会打开一个新窗口。
为了实现这一特性,可以监听模组的 [`activate`](https://www.electronjs.org/zh/docs/latest/api/app#event-activate-macos) 事件,如果没有任何活动的 BrowserWindow,调用 `createWindow()` 方法新建一个。
因为窗口无法在 `ready` 事件前创建,你应当在你的应用初始化后仅监听 `activate` 事件。 要实现这个,仅监听 `whenReady()` 回调即可。
```js
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
```
## 完整实现代码
[docs/fiddles/tutorial-first-app (32.1.2)](https://github.com/electron/electron/tree/v32.1.2/docs/fiddles/tutorial-first-app)[Open in Fiddle](https://fiddle.electronjs.org/launch?target=electron/v32.1.2/docs/fiddles/tutorial-first-app)
- main.js
- index.html
```js
const { app, BrowserWindow } = require('electron/main')
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
```
## 可选:使用 VS Code 调试
如果您希望使用 VS Code 调试您的程序,您需要让 VS Code 监听主进程 (main process) 和渲染器进程 (renderer process) 。 下面为您提供了一个简单的配置文件。 请在根目录新建一个 `.vscode` 文件夹,然后在其中新建一个 launch.json 配置文件并填写如下内容。
.vscode/launch.json
```json
{
"version": "0.2.0",
"compounds": [
{
"name": "Main + renderer",
"configurations": ["Main", "Renderer"],
"stopAll": true
}
],
"configurations": [
{
"name": "Renderer",
"port": 9222,
"request": "attach",
"type": "chrome",
"webRoot": "${workspaceFolder}"
},
{
"name": "Main",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"windows": {
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
},
"args": [".", "--remote-debugging-port=9222"],
"outputCapture": "std",
"console": "integratedTerminal"
}
]
}
```
保存后,当您选择侧边栏的 “运行和调试”,将会出现一个 "Main + renderer" 选项。然后您便可设置断点,并跟踪主进程和渲染器进程中的所有变量。
上文中我们在 `launch.json` 所做的其实是创建三个配置项:
- `Main` 用来运行主程序,并且暴露出 9222 端口用于远程调试 (`--remote-debugging-port=9222`) 。 我们将把调试器绑定到那个端口来调试 `renderer` 。 因为主进程是 Node.js 进程,类型被设置为 `node`。
- `Renderer` 用来调试渲染器进程。 因为后者是由主进程创建的,我们要把它 “绑定” 到主进程上 ()`"request": "attach"`,而不是创建一个新的。 渲染器是 web 进程,因此要选择 `chrome` 调试器。
- `Main + renderer` 是一个 [复合任务](https://code.visualstudio.com/Docs/editor/tasks#_compound-tasks),可以同时执行上述任务。
注意事项
由于我们要将进程绑定到 `Renderer` 任务,您应用中的前几行代码可能会被跳过,因为调试器 (Debugger) 在执行代码之前没有足够的时间进行连接。 在开发环境中,您可以通过刷新页面或者使用 setTimeout 延迟运行代码,来避开这个问题。
延伸阅读
如果您希望深挖调试步骤,可以查看以下指南:
- [调试应用](https://www.electronjs.org/zh/docs/latest/tutorial/application-debugging)
- [DevTools 扩展](https://www.electronjs.org/zh/docs/latest/tutorial/devtools-extension)