Inicio Rápido
Esta guía te ayudara a través del proceso de creación de una app "Hola Mundo" básica en Electron, similar a electron/electron-quick-start
.
Al final de este tutorial, tu app abrirá una ventana de navegador que mostrará una página web con información acerca de las versiones de Chromium, node.js y Electron que se están ejecutando.
Prerequisites
Para usar Electron, debes instalar Node.js. Te recomendamos que uses la última versión LTS
disponible.
Por favor instala Node.js usando instaladores precompilados para su plataforma. De lo contrario, puedes encontrar problemas de incompatibilidad con diferentes herramientas de desarrollo.
Para comprobar que node.js se instaló correctamente, escribe los siguientes comandos en tu terminal:
node -v
npm -v
Estos deben imprimir las versiones de Node.js y npm respectivamente.
Nota: Como Electron incrusta Node.js en su binario, la versión de Node.js en la que se ejecuta tu código no está relacionada con la versión ejecutada en tu sistema.
Crea tu aplicación
Scaffold del proyecto
Las aplicaciones Electron siguen la misma estructura general que otros proyectos en Node.js. Comienza creando una carpeta e iniciando un paquete npm.
- npm
- Yarn
mkdir my-electron-app && cd my-electron-app
npm init
mkdir my-electron-app && cd my-electron-app
yarn init
El comando interactivo init
te pedirá que configures algunos campos en su configuración. Hay algunas reglas que seguir para este tutorial:
entry point
debe sermain.js
.author
ydescription
pueden ser cualquier valor, pero son necesarios para empaquetar aplicaciones.
Tu archivo package.json
debería verse algo así:
{
"name": "my-electron-app",
"version": "1.0.0",
"description": "Hello World!",
"main": "main.js",
"author": "Jane Doe",
"license": "MIT"
}
Luego, instala el paquete electron
en las devDependencies
de tu aplicación.
- npm
- Yarn
npm install --save-dev electron
yarn add --dev electron
Nota: Si encuentra algún problema con la instalación de Electron, por favor consulte la guía Instalación avanzada.
Finalmente, querrás ser capaz de ejecutar Electron. En el campo scripts
de tu configuración package.json
, añade un comando start
como se muestra a continuación:
{
"scripts": {
"start": "electron ."
}
}
Este comando start
te permitirá abrir tu aplicación en modo desarrollo.
- npm
- Yarn
npm start
yarn start
# couldn't auto-convert command
Nota: Este script le dice a Electron que se ejecute en la carpeta raíz de su proyecto. En esta etapa, tu aplicación arrojará un error diciendo que no puede encontrar una aplicación para ejecutar.
Ejecutar el proceso principal
El punto de entrada de cualquier aplicación de Electron es su script main
. Este script controla el proceso principal que se ejecuta en un entorno de Node.js completo y es responsable de controlar el ciclo de vida de tu aplicación, mostrando interfaces nativas, realizando operaciones privilegiadas y gestionando procesos renderizadores (más sobre eso más adelante).
Durante la ejecución, Electron buscará este script en el campo main
de la configuración package.json
de la aplicación, el cual deberías de haber configurado durante el paso Inicializacion del projecto.
Para inicializar el script main
, cree un archivo vacío llamado main.js
en la carpeta raíz de tu proyecto.
Nota: ¡Si vuelves a ejecutar el script
start
en este momento, tu aplicación no debería de arrojar errores! Sin embargo, aún no hará nada porque no hemos añadido ningún código amain.js
.
Crear una página web
Antes de poder crear una ventana para nuestra aplicación, necesitamos crear el contenido que se cargará en ella. En Electron, cada ventana muestra contenidos web que pueden cargarse desde un archivo HTML local o desde una URL remota.
Para este tutorial estarás haciendo el primero. Crea un archivo index.html
en la carpeta raíz de tu proyecto:
<!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>
Note: Looking at this HTML document, you can observe that the version numbers are missing from the body text. We'll manually insert them later using 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:
- The
app
module, which controls your application's event lifecycle. - The
BrowserWindow
module, which creates and manages application windows.
Because the main process runs Node.js, you can import these as CommonJS modules at the top of your file:
const { app, BrowserWindow } = require('electron')
Then, add a createWindow()
function that loads index.html
into a new BrowserWindow
instance.
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile('index.html')
}
Next, call this createWindow()
function to open your window.
In Electron, browser windows can only be created after the app
module's ready
event is fired. You can wait for this event by using the app.whenReady()
API. Call createWindow()
after whenReady()
resolves its Promise.
app.whenReady().then(() => {
createWindow()
})
Note: At this point, your Electron application should successfully open a window that displays your web page!
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.
In general, you can use the process
global's platform
attribute to run code specifically for certain operating systems.
Quit the app when all windows are closed (Windows & Linux)
On Windows and Linux, exiting all windows generally quits an application entirely.
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.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
Open a window if none are open (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.
To implement this feature, listen for the app
module's activate
event, and call your existing createWindow()
method if no browser windows are open.
Because windows cannot be created before the ready
event, you should only listen for activate
events after your app is initialized. Do this by attaching your event listener from within your existing whenReady()
callback.
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
Now, the last thing to do is print out the version numbers for Electron and its dependencies onto your web page.
Accessing this information is trivial to do in the main process through Node's global process
object. However, you can't just edit the DOM from the main process because it has no access to the renderer's document
context. They're in entirely different processes!
Note: If you need a more in-depth look at Electron processes, see the Process Model document.
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.
Create a new script named preload.js
as such:
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 process.versions
object and runs a basic replaceText
helper function to insert the version numbers into the HTML document.
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.
// 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:
- The
__dirname
string points to the path of the currently executing script (in this case, your project's root folder). - The
path.join
API joins multiple path segments together, creating a combined path string that works across all platforms.
We use a path relative to the currently executing JavaScript file so that your relative path will work in both development and packaged mode.
Bonus: Add functionality to your web contents
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. Because the renderer runs in a normal web environment, you can add a <script>
tag right before your index.html
file's closing </body>
tag to include any arbitrary scripts you want:
<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.
Recap
After following the above steps, you should have a fully functional Electron application that looks like this:
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.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Algunas APIs pueden solamente ser usadas despues de que este evento ocurra.
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()
})
})
// 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
// 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. Tu también puedes ponerlos en archivos separados y requerirlos aquí.
// preload.js
// All the Node.js APIs are available in the preload process.
// It has the same sandbox as a Chrome extension.
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>.
<!-- 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.
We created a
main.js
script that runs our main process, which controls our app and runs in a Node.js environment. In this script, we used Electron'sapp
andBrowserWindow
modules to create a browser window that displays web content in a separate process (the renderer).In order to access certain Node.js functionality in the renderer, we attached a preload script to our
BrowserWindow
constructor.
Package and distribute your application
The fastest way to distribute your newly created app is using Electron Forge.
Add Electron Forge as a development dependency of your app, and use its
import
command to set up Forge's scaffolding:- 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
make
command:- 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 the
out
folder where your package will be located:// 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