Quick Start快速启动
This guide will step you through the process of creating a barebones Hello World app in Electron, similar to electron/electron-quick-start.本指南将指导您在Electron中创建一个与electron/electron-quick-start类似的基本Hello World应用程序。
By the end of this tutorial, your app will open a browser window that displays a web page with information about which Chromium, Node.js, and Electron versions are running.在本教程结束时,您的应用程序将打开一个浏览器窗口,其中显示一个网页,其中包含运行Chromium、Node.js和Electron版本的信息。
Prerequisites先决条件
To use Electron, you need to install Node.js. 要使用Electron,您需要安装Node.js。We recommend that you use the latest 我们建议您使用可用的最新LTS
version available.LTS
版本。
Please install Node.js using pre-built installers for your platform.请使用您平台的预构建安装程序安装Node.js。You may encounter incompatibility issues with different development tools otherwise.否则,您可能会遇到不同开发工具的不兼容性问题。
To check that Node.js was installed correctly, type the following commands in your terminal client:要检查Node.js是否正确安装,请在终端客户端中键入以下命令:
node -v
npm -v
The commands should print the versions of Node.js and npm accordingly.命令应相应地打印Node.js和npm的版本。
Note: Since Electron embeds Node.js into its binary, the version of Node.js running your code is unrelated to the version running on your system.由于Electron将Node.js嵌入其二进制文件中,因此运行代码的Node.js版本与系统上运行的版本无关。
Create your application创建应用程序
Scaffold the project为项目搭建脚手架
Electron apps follow the same general structure as other Node.js projects. Electron应用程序遵循与其他Node.js项目相同的一般结构。Start by creating a folder and initializing an npm package.首先创建一个文件夹并初始化一个npm包。
- npm
- Yarn
mkdir my-electron-app && cd my-electron-app
npm init
mkdir my-electron-app && cd my-electron-app
yarn init
The interactive 交互式init
command will prompt you to set some fields in your config. init
命令将提示您在配置中设置一些字段。There are a few rules to follow for the purposes of this tutorial:在本教程中,有一些规则需要遵循:
entry point
should be必须是main.js
.main.js
。author
anddescription
can be any value, but are necessary for app packaging.author
和description
可以是任何值,但对于应用程序打包是必要的。
Your 您的package.json
file should look something like this:package.json
文件应该如下所示:
{
"name": "my-electron-app",
"version": "1.0.0",
"description": "Hello World!",
"main": "main.js",
"author": "Jane Doe",
"license": "MIT"
}
Then, install the 然后,将electron
package into your app's devDependencies
.electron
包安装到应用程序的devDependencies
中。
- npm
- Yarn
npm install --save-dev electron
yarn add --dev electron
Note: If you're encountering any issues with installing Electron, please refer to the Advanced Installation guide.注意:如果您在安装Electron时遇到任何问题,请参阅高级安装指南。
Finally, you want to be able to execute Electron. 最后,您希望能够执行Electron。In the scripts field of your 在package.json
config, add a start
command like so:package.json
配置的scripts字段中,添加如下启动命令:
{
"scripts": {
"start": "electron ."
}
}
This 此start
command will let you open your app in development mode.start
命令将允许您在开发模式下打开应用程序。
- npm
- Yarn
npm start
yarn start
# couldn't auto-convert command
Note: This script tells Electron to run on your project's root folder.注意:该脚本告诉Electron在项目的根文件夹上运行。At this stage, your app will immediately throw an error telling you that it cannot find an app to run.在此阶段,您的应用程序将立即抛出一个错误,告诉您无法找到要运行的应用程序。
Run the main process运行主进程
The entry point of any Electron application is its 任何Electron应用程序的入口点都是其main
script. main
脚本。This script controls the main process, which runs in a full Node.js environment and is responsible for controlling your app's lifecycle, displaying native interfaces, performing privileged operations, and managing renderer processes (more on that later).该脚本控制主进程,主进程在完整的Node.js环境中运行,并负责控制应用程序的生命周期、显示本机接口、执行特权操作和管理渲染器进程(稍后详细介绍)。
During execution, Electron will look for this script in the main field of the app's 在执行过程中,Electron将在应用程序的package.json
config, which you should have configured during the app scaffolding step.package.json
配置的main字段中查找该脚本,您应该在应用程序搭建步骤中配置该脚本。
To initialize the 要初始化main
script, create an empty file named main.js
in the root folder of your project.main
脚本,请在项目的根文件夹中创建一个名为main.js
的空文件。
Note: If you run the注意:如果此时再次运行start
script again at this point, your app will no longer throw any errors!start
脚本,应用程序将不再抛出任何错误!However, it won't do anything yet because we haven't added any code into然而,它不会做任何事情,因为我们还没有在main.js
.main.js
中添加任何代码。
Create a web page创建网页
Before we can create a window for our application, we need to create the content that will be loaded into it. 在为应用程序创建窗口之前,我们需要创建将加载到其中的内容。In Electron, each window displays web contents that can be loaded from either a local HTML file or a remote URL.在Electron中,每个窗口都显示可以从本地HTML文件或远程URL加载的web内容。
For this tutorial, you will be doing the former. 对于本教程,您将学习前者。Create an 在项目的根文件夹中创建index.html
file in the root folder of your project:index.html
文件:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- http://mdn.asprain.cn/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>
Note: Looking at this HTML document, you can observe that the version numbers are missing from the body text.注意:查看这个HTML文档,您可以看到正文中缺少版本号。We'll manually insert them later using JavaScript.稍后我们将使用JavaScript手动插入它们。
Opening your web page in a browser window在浏览器窗口中打开网页
Now that you have a web page, load it into an application window. 现在您有了一个网页,将其加载到应用程序窗口中。To do so, you'll need two Electron modules:为此,您需要两个Electron模块:
The app module, which controls your application's event lifecycle.app模块,用于控制应用程序的事件生命周期。The BrowserWindow module, which creates and manages application windows.BrowserWindow模块,用于创建和管理应用程序窗口。
Because the main process runs Node.js, you can import these as CommonJS modules at the top of your file:因为主进程运行Node.js,所以您可以在文件顶部将其作为CommonJS模块导入:
const { app, BrowserWindow } = require('electron')
Then, add a 然后,添加一个createWindow()
function that loads index.html
into a new BrowserWindow
instance.createWindow()
函数,将index.html
加载到新的BrowserWindow
实例中。
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile('index.html')
}
Next, call this 接下来,调用createWindow()
function to open your window.createWindow()
函数打开窗口。
In Electron, browser windows can only be created after the 在Electron中,浏览器窗口只能在app
module's ready event is fired. app
模块的就绪事件触发后创建。You can wait for this event by using the app.whenReady() API. 您可以使用app.whenReady()API等待此事件。Call 在createWindow()
after whenReady()
resolves its Promise.whenReady()
解析其承诺后调用createWindow()
。
app.whenReady().then(() => {
createWindow()
})
Note: At this point, your Electron application should successfully open a window that displays your web page!注意:此时,您的Electron应用程序应成功打开一个显示您的网页的窗口!
Manage your window's lifecycle管理窗口的生命周期
Although you can now open a browser window, you'll need some additional boilerplate code to make it feel more native to each platform. 虽然您现在可以打开浏览器窗口,但您还需要一些额外的样板代码,使其更适合每个平台。Application windows behave differently on each OS, and Electron puts the responsibility on developers to implement these conventions in their app.应用程序窗口在每个操作系统上的行为不同,Electron将在应用程序中实现这些约定的责任推给了开发人员。
In general, you can use the 通常,您可以使用process
global's platform attribute to run code specifically for certain operating systems.process
全局的平台属性来运行特定操作系统的代码。
Quit the app when all windows are closed (Windows & Linux)关闭所有窗口(windows和Linux)后退出应用程序
On Windows and Linux, exiting all windows generally quits an application entirely.在Windows和Linux上,退出所有Windows通常会完全退出应用程序。
To implement this, listen for the 要实现这一点,请监听app
module's 'window-all-closed' event, and call app.quit() if the user is not on macOS (darwin
).app
模块的“窗口全部关闭”事件,如果用户不在macOS(darwin
)上,则调用app.quit()。
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
Open a window if none are open (macOS)如果没有打开窗口,则打开窗口(macOS)
Whereas Linux and Windows apps quit when they have no windows open, macOS apps generally continue running even without any windows open, and activating the app when no windows are available should open a new one.Linux和Windows应用程序在没有打开窗口时退出,而macOS应用程序通常在没有打开任何窗口的情况下继续运行,并且在没有可用窗口时激活应用程序应会打开一个新的应用程序。
To implement this feature, listen for the 要实现此功能,请侦听app
module's activate event, and call your existing createWindow()
method if no browser windows are open.app
模块的激活事件,如果没有打开浏览器窗口,则调用现有的createWindow()
方法。
Because windows cannot be created before the 由于无法在ready
event, you should only listen for activate
events after your app is initialized. ready
事件之前创建windows,因此您只能在应用程序初始化后侦听激活事件。Do this by attaching your event listener from within your existing 通过从现有whenReady()
callback.whenReady()
回调中附加事件监听器来实现这一点。
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
Note: At this point, your window controls should be fully functional!注意:此时,您的窗口控件应该功能齐全!
Access Node.js from the renderer with a preload script使用预加载脚本从渲染器访问Node.js
Now, the last thing to do is print out the version numbers for Electron and its dependencies onto your web page.现在,要做的最后一件事是将Electron及其依赖项的版本号打印到您的网页上。
Accessing this information is trivial to do in the main process through Node's global 在主流程中,通过节点的全局process
object. process
对象访问这些信息是很简单的。However, you can't just edit the DOM from the main process because it has no access to the renderer's 但是,您不能仅从主进程编辑DOM,因为它无法访问渲染器的document
context. document
上下文。They're in entirely different processes!他们处于完全不同的过程中!
Note: If you need a more in-depth look at Electron processes, see the Process Model document.注:如果您需要更深入地了解Electron过程,请参阅过程模型文档。
This is where attaching a preload script to your renderer comes in handy. 这就是将预加载脚本附加到渲染器的方便之处。A preload script runs before the renderer process is loaded, and has access to both renderer globals (e.g. 预加载脚本在加载渲染器进程之前运行,并且可以访问渲染器全局(如window
and document
) and a Node.js environment.window
和document
)和Node.js环境。
Create a new script named 创建一个名为preload.js
as such: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])
}
})
The above code accesses the Node.js 上面的代码访问Node.jsprocess.versions
object and runs a basic replaceText
helper function to insert the version numbers into the HTML document.process.versions
对象,并运行一个基本的replaceText
助手函数将版本号插入HTML文档。
To attach this script to your renderer process, pass in the path to your preload script to the 要将此脚本附加到渲染器进程,请将预加载脚本的路径传递到现有webPreferences.preload
option in your existing BrowserWindow
constructor.BrowserWindow
构造函数中的webPreferences.preload
选项。
// include the Node.js 'path' module at the top of your file
const path = require('path')
// modify your existing createWindow() function
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
win.loadFile('index.html')
}
// ...
There are two Node.js concepts that are used here:这里使用了两个Node.js概念:
The __dirname string points to the path of the currently executing script (in this case, your project's root folder).__dirname字符串指向当前正在执行的脚本的路径(在本例中,是项目的根文件夹)。The path.join API joins multiple path segments together, creating a combined path string that works across all platforms.path.join API将多个路径段连接在一起,创建跨所有平台工作的组合路径字符串。
We use a path relative to the currently executing JavaScript file so that your relative path will work in both development and packaged mode.我们使用相对于当前正在执行的JavaScript文件的路径,这样您的相对路径将在开发和打包模式下工作。
Bonus: Add functionality to your web contents奖励:为您的web内容添加功能
At this point, you might be wondering how to add more functionality to your application.此时,您可能想知道如何向应用程序添加更多功能。
For any interactions with your web contents, you want to add scripts to your renderer process. 对于与web内容的任何交互,您需要将脚本添加到渲染器进程中。Because the renderer runs in a normal web environment, you can add a 由于渲染器在正常的web环境中运行,因此您可以在<script>
tag right before your index.html
file's closing </body>
tag to include any arbitrary scripts you want:index.html
文件的关闭</body>
标记之前添加一个<script>
标记,以包含您想要的任意脚本:
<script src="./renderer.js"></script>
The code contained in 然后,renderer.js
can then use the same JavaScript APIs and tooling you use for typical front-end development, such as using webpack to bundle and minify your code or React to manage your user interfaces.renderer.js
中包含的代码可以使用与典型前端开发相同的JavaScript API和工具,例如使用webpack捆绑和缩小代码,或者使用React管理用户界面。
Recap
After following the above steps, you should have a fully functional Electron application that looks like this:完成上述步骤后,您应该有一个功能完整的Electron应用程序,如下所示:
The full code is available below:完整代码如下:
// main.js
// Modules to control application life and create native browser window用于控制应用程序寿命和创建本地浏览器窗口的模块
const { 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')
}
})
// and load the index.html of the app.并加载应用程序的index.html。
mainWindow.loadFile('index.html')
// Open the DevTools.打开DevTools。
// mainWindow.webContents.openDevTools()
}
// This method will be called when Electron has finished initialization and is ready to create browser windows.当Electron完成初始化并准备创建浏览器窗口时,将调用此方法。
// Some APIs can only be used after this event occurs.某些API只能在此事件发生后使用。
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.在macOS上,当点击停靠图标且没有其他窗口打开时,通常会在应用程序中重新创建一个窗口。
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// Quit when all windows are closed, except on macOS. There, it's common for applications and their menu bar to stay active until the user quits关闭所有窗口后退出,macOS除外。在那里,应用程序及其菜单栏在用户退出之前一直处于活动状态是很常见的
// explicitly with Cmd + Q.显式使用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. 在此文件中,您可以包含应用程序特定主进程代码的其余部分。
// You can also put them in separate files and require them here.您也可以将它们放在单独的文件中,并在此处要求它们。
// preload.js
// All the Node.js APIs are available in the preload process.所有Node.js API在预加载过程中都可用。
// It has the same sandbox as a Chrome extension.它具有与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">
<!-- http://mdn.asprain.cn/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>.
<!-- You can also require other files to run in this process -->
<script src="./renderer.js"></script>
</body>
</html>
- main.js
- preload.js
- index.html
const { app, BrowserWindow } = require('electron')
const path = require('path')
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
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()
}
})
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}
for (const type of ['chrome', 'node', 'electron']) {
replaceText(`${type}-version`, process.versions[type])
}
})
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body>
<h1>Hello World!</h1>
<p>
We are using Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
and Electron <span id="electron-version"></span>.
</p>
</body>
</html>
To summarize all the steps we've done:总结我们已经完成的所有步骤:
We bootstrapped a Node.js application and added Electron as a dependency.我们启动了一个Node.js应用程序,并添加了Electron作为依赖项。We created a我们创建了一个main.js
script that runs our main process, which controls our app and runs in a Node.js environment.main.js
脚本来运行主进程,它控制应用程序并在Node.js环境中运行。In this script, we used Electron's在这个脚本中,我们使用Electron的app
andBrowserWindow
modules to create a browser window that displays web content in a separate process (the renderer).app
和BrowserWindow
模块创建了一个浏览器窗口,该窗口在单独的进程(渲染器)中显示web内容。In order to access certain Node.js functionality in the renderer, we attached a preload script to our为了访问渲染器中的某些Node.js功能,我们在BrowserWindow
constructor.BrowserWindow
构造函数中附加了一个预加载脚本。
Package and distribute your application打包并分发您的应用程序
The fastest way to distribute your newly created app is using Electron Forge.分发新创建的应用程序的最快方法是使用Electron Forge。
-
Add Electron Forge as a development dependency of your app, and use its添加Electron Forge作为应用程序的开发依赖项,并使用其import
command to set up Forge's scaffolding:import
命令设置Forge的脚手架:- npm
- Yarn
npm install --save-dev @electron-forge/cli
npx 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/cli
npx 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"!!! -
Create a distributable using Forge's使用Forge的make
command:make
命令创建可分发的:- npm
- Yarn
npm run make
> my-electron-app@1.0.0 make /my-electron-app
> electron-forge make
✔ Checking your system
✔ Resolving Forge Config
We need to package your application before we can make it
✔ Preparing to Package Application for arch: x64
✔ Preparing native dependencies
✔ Packaging Application
Making for the following targets: zip
✔ Making for target: zip - On platform: darwin - For arch: x64yarn run make
> my-electron-app@1.0.0 make /my-electron-app
> electron-forge make
✔ Checking your system
✔ Resolving Forge Config
We need to package your application before we can make it
✔ Preparing to Package Application for arch: x64
✔ Preparing native dependencies
✔ Packaging Application
Making for the following targets: zip
✔ Making for target: zip - On platform: darwin - For arch: x64Electron Forge creates theElectron Forge创建您的包所在的out
folder where your package will be located:out
文件夹:// Example for macOS
out/
├── 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