In five minutes, it’ll Electron.

About Electron

Electron is an open source library developed by Github for building cross-platform desktop applications using HTML, CSS, and JavaScript. Electron packages applications that run on Mac, Windows, and Linux by merging Chromium and Node.js into the same runtime environment.

Core Concepts:

  • To keep Electron small (file size) and sustainable (dependency and API expansion), Electron limits the range of core projects used.
  • Electron onlyChromiumtheRendering libraryRather thanall.
  • The new features added to Electron should be used primarily with the native API(Node.js).

What is Chromium?

Chromium is a web browser developed by Google.

Chromium is the engine behind Chrome.

A few boring associations

Chromium + Node.js = ?

When you associate a browser with Node.js, it’s common to think of a Web service, TCP, and its derivative protocols as the bridge between the page and the server.

Web + Native =?

The browser can call the Native functions, which is easily reminiscent of Hybrid. The Web communicates with the Native through the customized bridge protocol, and the Native intercepts the request to know the functions that the Web needs to call.

What is the principle of Electron?

The Electron desktop application is divided into two processes:

  • MainProcess — MainProcess
  • RenderProcess — RenderProcess

The main process manages native operations, such as file reading and writing, graphics processing, program switching, etc., as well as the rendering process and the application lifecycle.

The renderer process draws the front-end interface through Chromium, and users can trigger events on the page.

So how does Node.js communicate with Chromium?

The answer is IPC — interprocess communication.

Electron IPC communication model

Electron IPC provides an event-based API to send events to each other in both the renderer process and the background process, as well as to reply to each other in the event handler by sending new events:

  • throughEventEmitterInstances send events to each other
  • To send an event, you need to specify the handle of the other party. Global broadcast is not supported
  • Supports synchronous and asynchronous events

Create a desktop application

Step 1. Environment

  • Node.js = 8.x | 9.x

Step 2. Install the electron bag

npm install electron --save-dev --save-exact
Copy the code

If the next slow, you can try taobao mirror.

Step 3. Project structure

. └ ─ ─ app ├ ─ ─ the main, js ├ ─ ─ index. The js ├ ─ ─ index. The HTML ├ ─ ─ package. The jsonCopy the code

Main.js is the main process execution file, and index.html and index.js are renderers’ views, just as they would normally be on a web page.

You need to specify the App name and other information in package.json, and specify the entry file (main.js), for example:

{
  "name": "app"."productName": "app"."version": "0.0.1"."main": "./app/index.js"
}
Copy the code

For a more detailed example, see the official example: electron-quick-start

Step 4. Start the electron

Main process service plus NPM scripts:

"dev:electron-main": "cross-env NODE_ENV='development' electron -r babel-register ./".Copy the code

Start the main process:

npm run  dev:electron-main
Copy the code

Step 5. Development

After the electron main process file is modified, the application needs to be restarted to take effect. It is not convenient to manually restart the application each time.

electron-watch

To eat it, insert the following code snippet in the main process file:

if (process.env.NODE_ENV === 'development') {
  require('electron-watch')(
    __dirname,
    'dev:electron-main'.// means: npm run dev:electron-main
    path.join(__dirname, '/')); }Copy the code

** PS: This library has a bug on Windows. The correct way to use it is to press Ctrl+S once. Pressing Ctrl+S several times will restart multiple applications. **


Electron module

Electron provides a rich API for you to call native functions, see the Electron documentation.

But after going through the following modules, you can quickly pull out a Electron App.

1. app

A desktop application object that provides an API to control the application and monitor the event lifecycle of the application.

For example, exit the application when the last window is closed:

const {app} = require('electron');
app.on('window-all-closed', () => {
  app.quit();
});
Copy the code

Life cycle events that can be monitored:

  • will-finish-launching: Triggered when the application completes basic startup
  • ready: triggered when Electron ‘: completes initialization
  • window-all-closed: Triggered when all Windows are closed
  • before-quit: Triggered before the application begins to close the window
  • will-quitEmitted when all Windows are closed and the application is about to exit
  • quit: emitted when the application exits

2. BrowserWindow

A browser window

Create a browser window:

import { app, BrowserWindow } from 'electron';

app.on('ready', () = > {const win = new BrowserWindow({width: 800.height: 600});

  // Load the remote URL
  win.loadURL('https://www.coolecho.net'); 

  // load a local HTML file
  win.loadURL(`file://${__dirname}/app/index.html`); 
});
Copy the code

Parent and child window:

const {BrowserWindow} = require('electron');
  
const top = new BrowserWindow();
/** * with the model attribute, the child window is a modal window, the parent window is disabled */
const child = new BrowserWindow({parent: top})
child.show()
top.show()
Copy the code

The Child window will always appear at the top of the top window and will look something like this:

3. ipcMain & ipcRender

IpcMain is an instance of the EventEmitter class. When used in the main process, ipcRender handles asynchronous and synchronous information sent from the renderer process (web page). Messages sent from the renderer process will be sent to this module.

IpcRenderer is also an example of EventEmitter. You can use some of the methods it provides to send synchronous or asynchronous messages from the renderer (web page) to the main process. It can also receive messages returned by the main process.

Here is an example of sending and processing messages between rendering and the main process:

// In the main process
const {ipcMain} = require('electron');

/ / asynchronous
ipcMain.on('asynchronous-message', (event, arg) => {
    console.log(arg);  // prints "ping"
    event.sender.send('asynchronous-reply'.'pong');
});

/ / synchronize
ipcMain.on('synchronous-message', (event, arg) => {
  console.log(arg)  // prints "ping"
  event.returnValue = 'pong'
});
Copy the code
// In the renderer process
const {ipcRenderer} = require('electron');

// Synchronize the request
console.log(ipcRenderer.sendSync('synchronous-message'.'ping'));

// Send the request asynchronously
ipcRenderer.on('asynchronous-reply', (event, arg) => {
    console.log(arg) // prints "pong"
});
// Asynchronous receive returns
ipcRenderer.send('asynchronous-message'.'ping');
Copy the code

You can use the ipcMain and ipcRenderer modules to call native functions in the render page to do some things, but Electron does a lot more than that. It also provides the Remote module. With the remote module, you can call methods on the main process object without having to explicitly send interprocess messages.

4. Menu

Create native app menus and context menus.

import { Menu } from 'electron';

const menuTemplete = [{
    label: 'File'.submenu: [{
      label: 'New Note'.accelerator: 'CmdOrCtrl+N'.enabled: false.// role: 'new file',
      click: (a)= > mainWindow.webContents.send('new-file'.1),}, {label: 'New Project'.accelerator: 'Shift+CmdOrCtrl+N'.enabled: false.// role: 'new project',
      click: (a)= > mainWindow.webContents.send('new-project'),}, {type: 'separator'}, {label: 'Save'.accelerator: 'CmdOrCtrl+S'.role: 'save'.enabled: false.click: (a)= > mainWindow.webContents.send('save-content'),}]}];const menu = Menu.buildFromTemplate(menuTemplete);

Menu.setApplicationMenu(menu);
Copy the code

Effect:

You can also create the Context menu:

const menu = new Menu();

menu.append(new MenuItem({
    label: 'Rename'.click: (a)= > mainWindow.webContents.send('rename-project'),})); menu.append(new MenuItem({
  label: 'Delete'.click: (a)= > mainWindow.webContents.send('delete-project'),})); menu.append(new MenuItem({
  type: 'separator',})); menu.append(new MenuItem({
  label: 'New Notebook'.click: (a)= > mainWindow.webContents.send('new-project'),}));// Project right-click menu
ipcMain.on('show-context-menu-project-item', (event) => {
  const win = BrowserWindow.fromWebContents(event.sender);
  menu.popup(win);
});
Copy the code

Effect:

A menu item

Electron provides a number of properties to customize a menu item, such as label, Click, Role, and more in the example above:

  • click: Click the callback method of the menu item
  • role: ElectronCustom built in events, there areclick, this item will be ignored
  • type: it can benormal,separator,submenu,checkboxradio.
  • label: Menu name. The default value is Role when role is set
  • accelerator: Defines shortcut keys
  • icon
  • sublabel
  • enabled: If false, the menu item is grayed out and unclickable
  • visible: Controls whether menu items are visible
  • checked: Controls whether the menu item is selected,typeforchckboxorradioEffective when
  • submenu: Defines submenu items
  • id: allows you to reference the menu item
  • position: allows fine-grained definition of specific locations in a given menu (never tried)

Other modules

Basically, if you know the three modules, you can develop a Electron APP. However, the Electron module is far more than these, including network, power supply, notification, process, menu, localization, protocol, session, Shell and other modules. Refer to the Electron document for detailed introduction.


Distributed applications

Now that the application is developed, it’s time to pack.

There are three ways to pack:

  1. Manual packaging
  2. Packaging tools
  3. This is done by recompiling the source code

1 and 3 methods are a bit complicated. Here are some common packaging tools:

  • electron-packager
  • electron-forge
  • electron-builder

If you want to list your APP on the APP STORE, you need to fill in the certificate and developer information using XCode and manually package it.

I use the electron packer, which is very easy to pack. Check out the NPM script:

"packager:mac": "electron-packager ./lib Yosoro --overwrite --platform=darwin --arch=x64 --out=out --icon=assets/icons/osx/app.icns"."packager:win": "electron-packager ./lib Yosoro --overwrite --platform=win32 --arch=ia32 --out=out --icon=assets/icons/win/app.ico"."packager:linux": "electron-packager ./lib Yosoro --overwrite --platform=linux --arch=x64 --out=out".Copy the code

The icon parameter is used to specify the application logo. Icns format for macOS and. Ico format for Windows.

Why does Linux not have this command line argument?

Because the Linux Logo needs to be specified when initializing the Electron application and can be in PNG or JPEG format, PNG is recommended:

const options = {
    title: 'Yosoro'.width: 1180.height: 786};if (process.platform === 'linux') { / / plus the logo
  options.icon = path.join(__dirname, './resource/app.png');
}
mainWindow = new BrowserWindow(options);
Copy the code

The options.icon property is not valid on macOS and Windows.

Finally, do you think NPM run is the end of the story?

The electron packager only does the right thing in the right place. For example, on macOS, it only hits packages running on macOS, on Windows, it only hits packages running on Windows, and never does extra packing. For example, on macOS, it will be packaged directly into an APP package:

If you want to package three terminals separately, you need to package them separately in macOS, Windows, and Linux.

conclusion

Electron also has very powerful functions, such as hot update and so on. This article is just notes with food chicken, welcome to correct any mistakes.

And finally, the instance of Electron with React stamp here and find star.