Learn Electron in fifteen minutes

What is Electron

Electron is an open source framework built on Node.js and Chromium for building cross-platform desktop applications.

Electron provides many cross-platform features, such as window management, menus, dialog boxes, tray icons, etc. It also easily integrates with Node.js modules so developers can use libraries and tools from the existing Node.js ecosystem.

This makes Electron ideal for developing desktop applications with rich user interfaces and native operating system integration.

Because Electron uses Chromium as its rendering engine, applications get high performance and support for modern web technologies.

And because of its cross-platform nature, developers can use consistent development tools and techniques to build applications for multiple operating systems such as Windows, macOS, and Linux.

To put it simply, Electron provides a method to package nodejs and Chromium into a set of cross-platform desktop applications.


Why choose Electron

Let’s take a look at what technologies are available to develop desktop applications:

Programming Language/Technology Framework Available capabilities Representative works
C#/WPF Develop Windows apps Visual Studio
Swift Develop macOS apps CodeEdit
C++/QT Cross-platform application YY Voice
C++/CEF Cross-platform application DingTalk
Java/Swing Cross-platform application JetBrains series software
JavaScript/Electron Cross-platform application Visual Studio Code
Rust/Bulls Cross-platform application xplorer
Dart/Flutter Cross-platform application rustdesk

As a developer, learning a certain technology depends on whether the return on investment is high. For example, C# on the Windows platform and Swift on the macOS platform, I personally feel that the technical route will be relatively narrow. In the future, more scenarios will adopt cross-platform Technology to achieve.

So if you have C++ skills, QT and CEF are good choices. For the front end, the best choices are the following three:

  • Electron: Pure JavaScript technology stack, the ecosystem is very mature, front-end students can get started quickly, and there is no learning cost
  • Tauri: The package is very small and requires a certain Rust foundation
  • Flutter: One set of code covers the six major platforms of web, iOS, Android, macOS, Windows and Linux

It can be seen that the advantages of the above three options are very obvious, but the other two have a certain learning cost for the front end, which requires learning rust and dart languages, while Electron is simply zero cost for the front end, so starting from learning In terms of cost, Electron is the most suitable.

In terms of popularity, quite a few desktop applications are developed using Electron. There are many well-known and popular applications among them, such as Postman, Notion, Skype, etc., and I bet that you must have installed applications developed with Electron on your computer. If you are using a Mac computer, please run the following on the command line Command to detect local desktop software developed using Electron technology:

for app in /Applications/*; do;[ -d  $app/Contents/Frameworks/Electron\ Framework.framework ] && echo $app; done

The applications I detected locally include:

$ for app in /Applications/*; do;[ -d  $app/Contents/Frameworks/Electron\  Framework.framework ] && echo $app; done
/Applications/BaiduNetdisk_mac.app
/Applications/QQ.app
/Applications/Scratch 3.app
/Applications/Visual Studio Code.app
/Applications/Xmind.app
/Applications/aDrive.app
/Applications/lx-music-desktop.app

Finally, let’s take a look at the advantages of Electron over the Web:

  • Resource localization and offline persistence: For traditional web applications, performance stuck points often lie not in parsing and rendering, but in network requests. After localizing resources, The page can be opened instantly after the application is started, which greatly reduces the white screen and the user's waiting time. In addition, traditional Web data is saved to the server in real time by calling interfaces, and cannot be persisted offline. However, Electron can write all user configuration and cache data to local files, and the software can still be used normally when offline. Sync to the cloud when back online, such as note-taking applications.
  • System underlying API calls: The Web environment is essentially a sandbox provided by the browser. For security reasons, many underlying capabilities are restricted, such as file operations, etc., and in Electron Inside, you can call any API provided by the operating system, including fs, child_process, os, etc. that are encapsulated by node.js for developers.
  • Unrestricted network communication: Every front-end development will encounter cross-domain problems. This is actually artificially created by web browsers to ensure data security in different domains. restrictions, but in the Electron environment, you don't need to consider whether it is cross-domain, all http and https requests are unblocked, and you can intercept and redirect these requests, and even modify any header fields and response results. Not only that, lower-level network capabilities such as tcp and udp are also supported. You can make a chat software similar to QQ.
  • Customizable windows: The traditional Web can only provide users with one tab, which is tedious. Electron can create a variety of borderless windows, which can even be set into circles. It has a square or triangular shape. For example, you may have used Apple's own Spotlight or Alfred, which only provides a search entrance. The shortcut keys evoke the global top input box, and you can leave after using it. It completely explodes the Web in terms of visual and interactive experience. , In addition, the desktop application can also set the tray menu to create a flashing effect similar to QQ messages.

So what are you front-ends waiting for? Come and learn with me!


Install Electron

Why do we need to talk specifically about installation? Because there is a pit here.

When executing npm install electron -D it will always be stuck in one place and cannot be installed normally

Solution Use cnpm:

npm install -g cnpm --registry=https://registry.npmmirror.com
cnpm install electron -D

Desktop CSDN actual combat

It’s easy to understand on paper, so let’s start with Electron by handwriting an Electron Demo.

Let's first quickly create an Electron project:

$ mkdir my-electron
$ cd my-electron
$ npm init -y
$ npm install electron electron-packager --dev

Next we create a src directory, and create two subdirectories main and renderer inside it.

In Electron there aremain process and rendering process Two important concepts are that we use Node.js code to call the Electron-encapsulated API in the main process to create windows and manage the entire life cycle of the application, and load the traditional Web interface in the rendering process.

Therefore, the main directory is used to store code related to the main process, and the renderer directory is used to store code related to the rendering process.

The entry point of the entire desktop application is in the main process. Next, create index.js in the main directory as the entry point.

In order for Electron to know this entry, we need to specify the following in package.json:

"main": "src/main/index.js",
"scripts": {
    
    
  "start": "electron ."
},

At this point, a basic Electron project has been built. Next, we can write our page.

In the src/main/index.js entry file, let’s load a CSDN:

//引入两个模块:app 和 BrowserWindow
//app 模块,控制整个应用程序的事件生命周期。
//BrowserWindow 模块,它创建和管理程序的窗口。
const {
    
     app, BrowserWindow } = require('electron')

//在 Electron 中,只有在 app 模块的 ready 事件被激发后才能创建浏览器窗口
app.whenReady().then(() => {
    
    
  //创建一个窗口
  createWindow()
})

function createWindow() {
    
    
  const mainWindow = new BrowserWindow({
    
     width: 800, height: 600 })
  //窗口加载 URL
  mainWindow.loadURL('https://www.csdn.net/')
}

Then enter npm start in the terminal to start the project, and you will see a window popping up to load the CSDN official website
Insert image description here

General enterprise desktop applications will define their own exclusive protocols. We may have all encountered that when we click to download Baidu Netdisk on the web page, the Baidu Netdisk software in our computer will automatically open. How is this done? Just through a custom protocol.

The so-called custom protocol actually means giving the application a unique name and then registering it in the operating system. The software can be invoked through this protocol name. Registering the protocol in Electron only requires one line of code:

app.setAsDefaultProtocolClient('electron-desktop')

After registration, when entering electron-desktop:// in the browser, you will find a jump prompt popping up. Click Agree to start and jump to the desktop application. Through this protocol, The application is called scheme evocation, and it can also bring some parameters when evoking, for example:

electron-desktop://width=800&height=600

After customizing the protocol, you can use scheme to invoke desktop applications. This is a very important capability.

The most critical thing here is to get the protocol activation parameters, otherwise you will not know who to chat with after awakening QQ, and you will not know which data to download after awakening Baidu Netdisk.

The behavior of scheme evocation is supported by the operating system by default. The operating system also provides APIs to monitor evocation events and obtain evocation parameters.

Obtaining protocol evocation parameters is different on Mac and Windows. This is due to different platform policies. Here we will explain Mac.

By listening to the open-url event on Mac, you can get the evoked scheme parameters:

app.on('open-url', (event, url) => {
    
    
  console.log(url) // 打印 electron-desktop://width=800&height=600
})

The url contains the complete address string evoked by the scheme. Except for the electron-desktop:// prefix at the beginning, the following content is completely customized by the user, for example:

  • electron-desktop://hello-CSDN
  • electron-desktop://1+1=2

These can all be evoked. The reason why width=800&height=600 is used above is entirely because it imitates the format of the query parameter in the http address bar, and there is a ready-made API to facilitate parsing the parameters.

Next, we parse the scheme parameter obtained by the open-url callback and put it into the global variable urlParams:

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

const protocol = 'electron-desktop'
app.setAsDefaultProtocolClient(protocol)

let urlParams = {
    
    }

app.on('open-url', (event, url) => {
    
    
  const scheme = `${
      
      protocol}://`
  const urlParams = new URLSearchParams(url.slice(scheme.length))
  urlParams = Object.fromEntries(urlParams.entries())
})

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

function createWindow() {
    
    
  const mainWindow = new BrowserWindow({
    
     width: 800, height: 600 })
  mainWindow.loadURL('https://www.csdn.net/')
}

There are two points to note about protocol evocation on the Mac platform:

  • open-url must be registered before the ready event, because in some scenarios, it is necessary to get the parameters before deciding how to create the window. If it is placed in the ready callback, createWindow may not be able to get the parameter.
  • In a scenario where the application supports multiple instances, if the program is not started, the application will be started immediately and the arousal parameters will be obtained in the open-url. If there are running instances (there may be multiple), (one of the) already running programs will be activated instead of starting a new instance. The activated instance can obtain the arousal parameters through the open-url callback.

Next we will complete this desktop CSDN demo:

  • Immediately enter the CSDN homepage after opening the desktop application
  • Supports using csdn:// this scheme to invoke the application
  • Supports using csdn://width=500&height=300 this scheme to specify the window size
const {
    
     app, BrowserWindow } = require('electron')

let mainWindow

const protocol = 'csdn'
const scheme = `${
      
      protocol}://`
app.setAsDefaultProtocolClient(protocol)

let urlParams = {
    
    }

handleSchemeWakeup(process.argv)

app.on('open-url', (event, url) => handleSchemeWakeup(url))

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

// 创建 electron 新窗口
function createWindow() {
    
    
  const width = parseInt(urlParams.width) || 800
  const height = parseInt(urlParams.height) || 600
  if (mainWindow) {
    
    
    mainWindow.setSize(width, height)
  } else {
    
    
    mainWindow = new BrowserWindow({
    
     width, height })
    mainWindow.loadURL('https://www.csdn.net/')
  }
}

// 处理自定义协议 scheme 唤起
function handleSchemeWakeup(argv) {
    
    
  const url = [].concat(argv).find((v) => v.startsWith(scheme))
  if (!url) return
  // url 之间的 search 转换
  const searchParams = new URLSearchParams(url.slice(scheme.length))
  urlParams = Object.fromEntries(searchParams.entries())
  if (app.isReady()) createWindow()
}

At this point, our desktop CSDN practice is completed.

We call the way traditional Web pages are loaded with Electron "Shell desktop application", which is also the way to make a website Desktop software the fastest way.

After the development is completed, the application needs to be packaged into an executable file. You can use electron-builder for packaging.

Run the following command on the command line to install:

npm install electron-builder --save-dev

After the installation is complete, you can add the following script to the project's package.json file:

"scripts": {
    
       "start": "electron .",   "build": "electron-builder" }

Then, run the npm run build command from the command line to package the Electron application.

I believe you have already understood Electron’s simple development and packaging process through the above application.

Next, let’s learn some basic theoretical knowledge and advanced usage of Electron.


Electron basic configuration

const {
    
     app, BrowserWindow } = require('electron')
let win
// 监听electron 加载完毕的时候的创建窗口等等
app.on('ready', function () {
    
    
    // 创建一个窗口 设置属性
    win = new BrowserWindow({
    
    
    //fullscreen: true   //全屏
    //frame: false,   	//让桌面应用没有边框,这样菜单栏也会消失
    resizable: false,   //不允许用户改变窗口大小
    width: 800,         //设置窗口宽高
    height: 600,
    icon: iconPath,     //应用运行时的标题栏图标
    minWidth: 300,     // 最小宽度
    minHeight: 500,    // 最小高度
    maxWidth: 300,    // 最大宽度
    maxHeight: 600,    // 最大高度
    // 进行对首选项的设置
    webPreferences:{
    
        
      backgroundThrottling: false,   //设置应用在后台正常运行
      nodeIntegration:true,     //设置能在页面使用nodejs的API
      contextIsolation: false,  //关闭警告信息
      //preload: path.join(__dirname, './preload.js')
    }
  })
  // 这里让主进程加载一个index.html
  win.loadFile('index.html')
  // 设置为最顶层
  //win.setAlwaysOnTop(true)
  //win.loadURL(`www.baidu.com`) 可以让主进程打开文件或者一个链接
  // 监听窗口关闭事件
  win.on('closed',()=>{
    
    
      //释放win
      win = null
  })
})

// 监听所有的窗口都关闭了
app.on('window-all-closed', () => {
    
    
    console.log('窗口全部都关闭了')
})

Electron process

Electron applications have two types of processes: the main process and the renderer process.

The main process is responsible for managing the life cycle of the application and all windows, while the rendering process is responsible for displaying the window contents.

Usually, the main process and rendering process are through ipcMain and ipcRenderer module communicates.

Using the main process and the rendering process, you can better manage applications and windows, and can handle different tasks in different processes.

main process

The process in which Electron runs the main script of package.json is called the main process (there is only one)

Main process characteristics:

  • The main process connects the operating system and the rendering process. It can be regarded as a bridge between the page and the computer.
  • Inter-process communication, window management
  • Global general service
  • Some things that can only or are suitable to be done in the main process, such as browser downloads, global shortcut key processing, tray, and session
  • Maintain some necessary global state

rendering process

The rendering process is the front-end environment we are familiar with, but the carrier has changed, from browser to window.

Note: For security reasons, the rendering process cannot directly access local resources, so it needs to be completed in the main process.

Rendering process features:

  • Electron uses Chromium to display web pages, so Chromium's multi-process architecture is also used
  • Each web page runs in its own rendering process. Each rendering process is independent of each other and only cares about their own web page
  • Use the BrowserWindow class to start a rendering process and run this instance in the process. When a BrowserWindow instance is destroyed, the corresponding rendering process will also be terminated.
  • Native resources cannot be called in the rendering process, but the rendering process also contains the Node.js environment, so Node.js can be introduced

The difference between the main process and the rendering process

  • The main process uses a BrowserWindow instance to create a web page
  • Each BrowserWindow instance runs a web page in its own rendering process. When a BrowserWindow instance is destroyed, the corresponding rendering process will also be terminated.
  • The main process manages all pages and their corresponding rendering processes
  • Since managing native GUI resources on a web page is very dangerous and can easily cause resource leakage, calling GUI-related APIs on a web page is not allowed. If you want to use GUI operations on a web page, the corresponding rendering process must communicate with the main process and request the main process to perform related GUI operations.

Think of it like this. Each tab and its page in Chrome is like a separate rendering process in Electron.

Even if you close all tabs, Chrome still exists. This is like Electron's main process, which can open a new window or close the application.

Communication between the main process and the rendering process

Main thread to Rendering thread sent via webContents.send — >ipcRenderer.on to monitor

Rendering thread to Main thread needs to be sent via ipcRenderer.send — > ipcMain.on to monitor


Electron cross-platform issues

Cross-platform issues are an important issue to consider when developing Electron applications.

Since different platforms have different UIs and APIs, different code is required to handle cross-platform issues.

Here are some common cross-platform issues and solutions:

  • File path: On different operating systems, the format of the file path may be different. To solve this problem, you can use the path module provided by Node.js to handle file paths.
  • Window size and position: The size and position of the window may vary on different operating systems. To solve this problem, you can use the screen module provided by Electron to get the screen size and resolution, and use relative position to set the size and position of the window.
  • Shortcut keys: On different operating systems, the shortcut key combinations may be different. In order to solve this problem, you can use the globalShortcut module provided by Electron to register shortcut keys, which can automatically adapt to different operating systems.

You can use the shortcut keysCtrl+Shift+I (Windows and Linux) orCmd+Shift +I (macOS) Open developer tools.


Electron deployment

Package application

Before an application can be deployed to a production environment, it needs to be packaged as an executable file.

Here are some commonly used tools that can help us package Electron applications into executable files:

  • electron-builder: An Electron-based packager that supports packaging applications into various formats such as Windows, macOS, and Linux.
  • electron-packager: Another popular packager that also supports multiple formats.

The following introduces the steps and precautions for using Electron Builder:

First you need to install Electron Builder using npm:

npm install electron-builder --save-dev

Then we have to configure the package.json file, we need to add some fields to configure the packaging and publishing of the application.

  • build field: Used to configure build options for the application.
  • directories field: Used to configure the application's source code and build output directories.
  • repository field: used to configure the source code repository address of the application.

The following is an example of a package.json file:

{
    
    
    "name":"my-electron-app",
    "version":"1.0.0",
    "description":"my Electron App",
    "main":"main.js",
    "scripts":{
    
    
        "start":"electron .",
        "build":"electron-builder"
    },
    "repository":{
    
    
        "type":"git",
        "url":"https://github.com/username/my-electron-app.git"
    },
    "build":{
    
    
        "appId":"com.example.my-electron-app",
        "productName":"my Electron App",
        "directories":{
    
    
            "output":"dist"
        }
    }
}

In thebuild field, we need to add some build options to specify the behavior of the application. Here are some commonly used build options:< /span>

  • appId: The ID of the application.
  • productName: The name of the application.
  • files: Files and folders to be packaged.
  • directories: Source code and build output directories.
  • asar: Whether to package the application into an ASAR file.
  • mac, win, linux : Use each flat platform construction selection.
  • dmg, nsis, deb : Use each flat base packaging option.

The following is an example of a common build field:

{
    
    
    "build":{
    
    
        "appId":"com.example.my-electron-app",
        "productName":"My Electron App",
        "directories":{
    
    
			"buildResources": "build",   //指定打包需要的静态资源,默认是build
      		"output": "dist",  //打包生成的目录,默认是dist
        },
        "files":[
            "main.js",
            "package.json",
            "index.html",
            "assets/**/*"
        ],
        "asar":true,
        "mac":{
    
    
            "target":"dmg",
            "icon":"assets/icon.icns"
            "category": "public.app-category.utilities"  //应用程序安装到哪个分类下
        },
        "win":{
    
    
            "target":"nsis",
            "icon":"assets/icon.ico"
        },
        "linux":{
    
    
            "target":"deb",
            "icon":"assets/icon.png"
        },
        "dmg": {
    
    
             "background": "build/background.jfif",   //安装窗口背景图
             "icon": "build/icons/icon.icns",         //安装图标
             "iconSize": 100,                         //图标的尺寸
             "contents": [                            //安装图标在安装窗口中的坐标信息
                {
    
    
                  "x": 380,
                  "y": 180,
                  "type": "link",
                  "path": "/Applications"
                },
                {
    
    
                  "x": 130,
                  "y": 180,
                  "type": "file"
                }
             ],
             "window": {
    
                                 //安装窗口的大小
                "width": 540,
                "height": 380
             }
   		}
    }
}

In the package.json file, you can use the following command to package the application:

npm run build

After executing this command, Electron Builder will build the application using the options we configured in the build field and will build the output file Save to the directory specified in directories.output.

In the folder generated by packaging, there will be oneapp.asar, which is the main business file compression package of the Electron application. To know which files in the project are packed into the installation package, You can view it by unzippingapp.asar.

After unzipping app.asar, in addition to all the files of the project, there is also a node_modules.

Fornode_modules, not all content innode_modules will be packaged into the installation package, only The dependencies in the field in a> field will not. package.json will be packaged, but the dependencies in the dependenciesdevDependencies

This is the only rule and has nothing to do with whether the project actually uses dependencies.

Therefore, in order to reduce the size of the installation package, it is recommended that all external packages used in the rendering process be installed in devDependencies, and then use webpack to package the code of the external package and the business code Come together.

publish application

After packaging the application into an executable file, we can publish it to the app store of each platform or on our own website.

electron-updater: Tool for automated publishing of applications

The installation package of the updated application should be stored on a server on the Internet. Every time the application is opened, it will be automatically detected and based on the current application's version and online version. Matching is performed, and when a new version is found, it is automatically downloaded. After the download is completed, the user is asked whether to install the new version.

Another situation is to separate the web resources from the "app shell". The web resources are placed on the server and dynamically loaded through the network every time, just like our desktop CSDN practice above:

mainWindow.loadURL('https://www.csdn.net/')

In scenarios where the business requires frequent updates, this method can be used to implement updates quickly and without hindrance.

In this case, we can package and update the "shell" as mentioned above, which is related to the main process;

The packaging of page resources is the same as the packaging of ordinary front-end projects, so I won’t go into details here.


Electron cross-terminal principle

ElectronThe cross-terminal principle is not difficult to understand. We will briefly introduce it here. I believe everyone can easily understand it.

It integrates the browser kernel and uses front-end technology to achieve rendering under different platforms, and combines Chromium, Node.js and the system for calling There are three major sections of local functionsAPI.
Insert image description here

  • Chromium provides powerful rendering capabilities for Electron. Since itself is cross-platform, there is no need to consider code compatibility. sex. Most importantly, development can be done using front-end tools. UIChromiumElectron
  • Chromium does not have native GUI operation capabilities, so Electron internally integrates Node.js and writes < a i=4> can also call the bottom layer of the operating system, such as path, fs, crypto and other modules. UIAPI
  • Native API provides Electron with native system GUI support so that Electron can call native APIs.

To sum up, Chromium is responsible for page UI rendering, Node.js is responsible for business logic, Native API provides native capabilities and cross-platform.


Summarize

Electron It is indeed a powerful tool for building cross-platform desktop applications. It is recommended that you read more official documents when learning, becauseElectron the version iteration is too fast, and it is really difficult not to read the official documents in time. There are still a lot of pitfalls.

To make a brief summary, this article introduces some basic knowledge of Electron, including Electron’s definition, advantages, basic configuration, process, deployment, and cross-terminal principles, and completes a practical case of desktop CSDN application.

By mastering the above knowledge, you can already try to develop your own Electron application, go and try it.

Guess you like

Origin blog.csdn.net/weixin_46232841/article/details/130233664