preface

Recently developed a new requirement using electron development desktop application to sort out the sad history and some pits for your reference. Without further ado, let’s get to the point

Project Construction

I. Technical requirements

  • electron13.x
  • vue3.x
  • ts4.x
  • The node version ‘> = 14.0.0’

Create v3 + TS project

 vue create electron-vue3-ts
Copy the code
  1. As shown in the following figure, select Custom

  1. Select some project basic configuration

  1. For vUE version, select 3.x

  1. Eslint you can optionally check error only

  1. The overall basic configuration is as follows

  1. Start automatic build

So far, the vUE + TS project has been built

V3 integrationElectron

There are two existing integration solutions on the market:

  1. Vue CLI Plugin Electron Builder
  2. electron-vue

Since the electron vue has not been updated for a long time, it is judged that it is not maintained, so vue CLI Plugin electron Builder is selected as the technology

Pit 1: An error occurs when you run vue add electron- Builder

The right thing to do is

Ensure that the local node version '>=14.0.0' NPM install vue-cli-plugin-electronic-Builder -d vue add electronic-BuilderCopy the code

Select version 13 to continue the installationAfter installation, the overall directory structure of the project is as follows:

The console output a warning after the installation is complete

 WARN  
 It is detected that you are using Vue Router. 
 It must function in hash mode to work in Electron. 
 Learn more at https://goo.gl/GM1xZG
Copy the code

Vue can only use hash mode in electron. The history mode cannot be changed as follows

 import { createRouter, createWebHashHistory, createWebHistory, RouteRecordRaw } from 'vue-router'
 const router = createRouter({
  history: process.env.IS_ELECTRON ? createWebHashHistory(process.env.BASE_URL) : createWebHistory(process.env.BASE_URL),
  routes
})
Copy the code

After the modification is complete, start the project

 npm run electron:serve
Copy the code

The startup process always finds it takes a long time for the project to come up and that’s becauseinstallExtensionMethod keeps asking for installationVUEJS3_DEVTOOLS, which then causes the project to start so slowly that it must wait five times for its requests to time out before starting the projectSo you can comment out this code and not execute it

// background.ts
// This line of code is commented out
import installExtension, { VUEJS3_DEVTOOLS } from 'electron-devtools-installer'
// The second part, these lines of code comment out
if(isDevelopment && ! process.env.IS_TEST) {// Install Vue Devtools
    try {
      await installExtension(VUEJS3_DEVTOOLS)
    } catch (e) {
      console.error('Vue Devtools failed to install:', e.toString())
    }
}
Copy the code

At this point, the ELECTRON + V3 + TS project has been set up successfully

Actual Project

As shown in the picture, the overall project structure is basically unchanged. It is ok to basically follow the normal VUE project development, but it is necessary to know the main process and rendering process in ELECTRON

A,ElectronThe main process and renderer process in

What is the main process

  • The process running main.js when the electron project starts is the main process
  • A project has one and only one main process
  • All system events, such as creating Windows, are carried out in the main process. Simply speaking, our Electron project has only one main process. The execution code of the main process needs to be written in main.js, and all the code related to system events is written here

What is a render process

  • We create a renderer process for every Web page we create
  • Each Web page runs in its own rendering process
  • Each renderer is independent and only cares about the page it is running on, which is simply a web page and a renderer

The difference between the main and renderer processes

  • The main process creates the page through BrowserWindow
  • Each BrowserWindow instance runs in its own renderer process, and when the BrowserWindow instance is destroyed, the corresponding renderer process is terminated

How do the main process and renderer communicate

  • Use ipcRenderer and ipcMain modules to send messages to solve communication problems
  • Main process code
const { ipcMain } = require('electron')
// Listen for messages sent by the renderer process
ipcMain.on('renderer-msg'.(event, arg) = > {
  console.log(arg) // prints' Help me create a new page '
  event.reply('main-msg'.'good');  // Return a message to the renderer
})
Copy the code
  • Renderer code
const { ipcRenderer } = require('electron')
// Listen for messages sent by the main process
ipcRenderer.on('main-msg'.(event, arg) = > {
  console.log(arg) // prints' ok '
})
// Send a message to the main process
ipcRenderer.send('renderer-msg'.'Help me create a new page')
Copy the code

More on Electron can be found in the official documentation

Error 2: Using electron to reference the vue page directly in the render process will cause an error

Uncaught ReferenceError: __dirname is not defined
Copy the code

At this time, most of the solutions given by Baidu Yisuo are to create vue.config.js file in the root directory of the project and add the following contents

module.exports = {
  pluginOptions: {
    electronBuilder: {
      nodeIntegration: true}}}Copy the code

After adding the configuration, re-run the project and find that the problem is resolved, but if you open the project directly in the browser at this time, you will find that the project still reported an errorThere is no problem in electronAnother solution is to usepreloadPreloaded script

Second,ElectronPreload preload

Let’s take a look at electron’s official introduction

  • preloadString (Optional) – Preloads the specified script before the page runs other scripts. This script can access all Node API scripts regardless of whether the page is integrated with Node. The script path is the absolute path of the file. When Node Integration is closed, the preloaded script reintroduces node’s global reference flag from global scope
  • preloadWebPreferences is an optional setting for the webPreferences parameter of the BrowserWindow class,preloadThe loading time of the script is after the window is created and before the page is loaded. If someone asks, if I don’t use loadURL, if I don’t load the page,preloadWill the script load? The answer is yes, but what good is it? What the hell is that about you not showing people your page? Anyway, the main thing is that we just need to understand this loading time.
  • And then just to be clear,preloadThe script is run in the render process. And the other thing is,preloadThe script calls the Window tool (which is essentially a browser shell),preloadScripts run in the render process, before pages and all other JS are loaded, and can call the Node API; The script file path is an absolute path, and when Node Integration is closed, the preloaded script reintroduces node’s global reference flag from the global scope.

So what exactly is preloading? Preloading is when a render process loads a local script that calls all Node apis and the Window tool before the page loads. Usage:

const win = new BrowserWindow({
    width: 800.height: 600.webPreferences: {
        preload: path.join(__dirname, 'preload.js')}})Copy the code

Now that we know what preload is, let’s go back to the previous question: How do I use preload to solve an error

  • Start by creating a preload. Ts file in the SRC directory
preload.ts
import { ipcRenderer } from 'electron'
(window as any).ipcRenderer = ipcRenderer
Copy the code
  • Then load preload.ts in the vue.config.js configuration
module.exports = {
  pluginOptions: {
    electronBuilder: {
      // nodeIntegration: true,
      preload: 'src/preload.ts'}}}Copy the code
  • Then load preload.js in background.ts configuration
const win = new BrowserWindow({
    width: 800.height: 600.webPreferences: {
      // Use pluginOptions.nodeIntegration, leave this alone
      // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
      nodeIntegration: (process.env.ELECTRON_NODE_INTEGRATION as unknown) as boolean,
      contextIsolation:!!!!! process.env.ELECTRON_NODE_INTEGRATION,enableRemoteModule: true.webSecurity: false.preload: path.join(__dirname, 'preload.js')}})Copy the code
  • Finally, it can be used directly in the VUE file
setup() {
    const ipcRenderer = (window as any).ipcRenderer
    // Listen for messages sent by the main process
    ipcRenderer.on('main-msg'.(event: any, arg: string) = > {
      console.log(arg) // prints' ok '
    })
    // Send a message to the main process
    ipcRenderer.send('renderer-msg'.'Help me create a new page')}Copy the code

Now, if you open the browser and visit, you’ll notice that the page has something on it but js still reports an errorThere is no problem in electronAs for how to solve the problem of opening access in the browser, I haven’t found any other good solution immediately. Please leave a comment in the comments section

Three,ElectronPackaging configuration

Vue has already integrated the electron Builder so it just needs to be configured in vue.config.js

module.exports = {
  pluginOptions: {
    electronBuilder: {
      // nodeIntegration: true,
      preload: 'src/preload.ts'.builderOptions: {
        productName: "".// Project name, which is also the prefix of the generated EXE file
        appId: ""./ / package name e7
        copyright: "".// Copyright information
        compression: "store"./ / "store" | "normal" | "maximum" compress condition (store relatively quickly), store 39749 KB, maximum 39186 KB
        directories: {
          output: "dist_electron" // Output folder
        },
        asar: true./ / asar packaging
        win: {
          icon: "build/icons/icon.ico".// Icon path
          target: [{target: "nsis".// Install the application
              arch: [
                // ia32 | x64 | armv7l | arm64
                "ia32".Arch =ia32, 32-bit operating system, can also be installed on a 64-bit operating system
                "x64" Arch =x64, 64-bit operating system, cannot be installed on 32-bit operating system using this architecture package]]}},linux: {
          icon: "build/icons".category: "home".target: [{target: "AppImage".// AppImage, snap, deb, rpm, freebsd, pacman, p5p, apk, 7z, zip, tar.xz, tar.lz, tar.gz, tar.bz2, dir.
              arch: ["arm64"]]}},mac: {
          icon: "build/icons/icon.icns".target: [{target: "dmg"}},nsis: {
          oneClick: false.// One-click setup
          // "guID ":" XXXX ", // Registry name, not recommended
          perMachine: false.// Whether to enable installation permission restrictions (for this computer or the current user)
          allowElevation: true.// Allow request promotion. If false, the user must restart setup with the promoted permissions.
          allowToChangeInstallationDirectory: true.// Allows you to change the installation directory
          installerIcon: "build/icons/icon.ico".// Install icon
          uninstallerIcon: "build/icons/icon.ico".// Uninstall the icon
          installerHeaderIcon: "build/icons/icon.ico".// Install header icon
          createDesktopShortcut: true.// Create a desktop icon
          createStartMenuShortcut: true.// Create start menu icon
          shortcutName: "" // Icon name
        }
      }
    }
  }
}
Copy the code

MAC ICONS generate ICNs

  • Prepare a 1024 x 1024 PNG image named asicon.png
  • Create a temporary directory for images of different sizes namedtmp.iconset
 mkdir tmp.iconset
Copy the code
  • theicon.pngConvert to a different size image and placetmp.iconsetIn the
sips -z 16 16     icon.png --out tmp.iconset/icon_16x16.png
sips -z 32 32     icon.png --out tmp.iconset/[email protected]
sips -z 32 32     icon.png --out tmp.iconset/icon_32x32.png
sips -z 64 64     icon.png --out tmp.iconset/[email protected]
sips -z 128 128   icon.png --out tmp.iconset/icon_128x128.png
sips -z 256 256   icon.png --out tmp.iconset/[email protected]
sips -z 256 256   icon.png --out tmp.iconset/icon_256x256.png
sips -z 512 512   icon.png --out tmp.iconset/[email protected]
sips -z 512 512   icon.png --out tmp.iconset/icon_512x512.png
sips -z 1024 1024   icon.png --out tmp.iconset/[email protected]
Copy the code
  • throughiconutilGenerate the ICNS file
 conutil -c icns tmp.iconset -o Icon.icns
Copy the code

At this point you have icon. Icns Apple icon image execute the package command

npm run electron:build
Copy the code

The Window icon generates an ICO

Pit three remember not to directly.pngThe icon at the end is changed.icoThere will be an error when packing

throughIco Online generation toolTo generate a size of 256 x 256

Just repack it

npm run electron:build_win
Copy the code

Note: This paper is based onmacPackaging for the development environment can be typed simultaneouslymacPackage andwindowThe package; If the package is Windows, you can only playwindowThe corresponding package packaging command isnpm run electron:build

Project Git address

Github.com/jifenjilian… It is recommended to use the NPM installation root directory to create the NPMRC file

electron_mirror=https://npm.taobao.org/mirrors/electron/
ELECTRON_BUILDER_BINARIES_MIRROR=http://npm.taobao.org/mirrors/electron-builder-binaries/
phantomjs_cdnurl=http://npm.taobao.org/mirrors/phantomjs/
sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
Copy the code

conclusion

At this electron + VUe3, the whole process from project construction, to project development, and then to the final project packaging has been basically combed out. I believe that the friends who see this will gain something. You are also welcome to discuss the differences in the comments section.

reference

  • electron
  • vue3
  • Vue CLI Plugin Electron Builder
  • electron-builder
  • electron-vue
  • Ico Online generation tool