background

The company needs to make a desktop program. Before, there was a CLI tool written by Python, which needs to encapsulate a GUI for cross-platform use. The technology adopts Electron + Vue technology stack, and the template uses Electron – Vue. The special feature is that the application is packaged with PyInstaller into a cross-platform application using Node calls.

Problems encountered in basic projects

As mentioned above, this project is created according to the electron-vue template. During the creation, electron- Builder is selected as the packaging tool, and the * -Unpacked directory and corresponding installable files such as.exe and.deb will be generated in the build directory after packaging. The following are some of the problems encountered when developing based on this template.

upgradeelectronversion

  • Used by templateselectronVersion is2.XVersion, the version is lower, so the upgrade11.3.0Version to facilitate the use of the latest framework features
  • The template is delivered with the upgradevuex-electronThe plugin was removed because it didn’t work

A problem with path separators in the system

  • For historical reasons the path’s divider is inWindowsandPOSIXdifferent
    • \Backslash, inWindows, such asC:\tmp\test.txt
    • /Diagonal, inPOSIX, such as/tmp/test.txt
  • Each programming language has an API for getting the current system separator method,nodeCan be used in:
    const sep = require('path').sep
    Copy the code
  • So you need to go through the above to manually add pathsapiGet path splitter, dynamic splicing:
    Import the path from the 'path' const downloadPath = ` ${this. $electron, remote app. GetPath (' downloads')} ${path. Sep} combined form. XLSX `Copy the code

On the useelectron-builderProblems with packaging

  • It is said that usingelectron-builderCan package out cross-operating system applications, just to be safe inWindowsandDeepinThe system is packaged separately
  • The packaged configuration basically passespackage.jsonThe configuration can be completed:
    "build": {
      "productName": "excel-util"."appId": "com.excelUtil.xxx"."directories": {
        "output": "build"
      },
      "files": [
        "dist/electron/**/*"]."dmg": {
        "contents": [{"x": 410."y": 150."type": "link"."path": "/Applications"
          },
          {
            "x": 130."y": 150."type": "file"}},"mac": {
        "icon": "build/icons/icon.icns"
      },
      "win": {
        "icon": "build/icons/icon.ico"
      },
      "nsis": {
        "shortcutName": "ExcelUtil"."oneClick": false."allowToChangeInstallationDirectory": true."include": "./installer.nsh"
      },
      "asar": false."linux": {
        "icon": "build/icons"."target": "deb"}}Copy the code
  • The above iselectron-builderAll the configuration for packaging in the
    • WindowsPackage configuration, specify icon path andnsisconfigurationWindowsThe behavior of installing and uninstalling applications
      "win": {
        "icon": "build/icons/icon.ico"
      },
      "nsis": {
        "shortcutName": "ExcelUtil"."oneClick": false."allowToChangeInstallationDirectory": true."include": "./installer.nsh"
      }
      Copy the code
    • LinuxPackage configuration, specify ICONS and package target format, etc
      "linux": {
        "icon": "build/icons"."target": "deb"
      }
      Copy the code
  • Mirroring problems with dependency packages used for packaging
    • Packaging depends on a number of external installation packages, which are passed by defaultgithubornpmOfficial warehouse, there will be slow download or download failure problems
    • Need to increase the.yarnrcConfiguration files in the root directory, configuration downloads involved the repository address dependent
      registry "https://registry.npm.taobao.org" sass_binary_site "https://npm.taobao.org/mirrors/node-sass/" phantomjs_cdnurl  "http://cnpmjs.org/downloads" electron_mirror "https://npm.taobao.org/mirrors/electron/" sqlite3_binary_host_mirror "https://foxgis.oss-cn-shanghai.aliyuncs.com/" profiler_binary_host_mirror "https://npm.taobao.org/mirrors/node-inspector/" chromedriver_cdnurl "https://cdn.npm.taobao.org/dist/chromedriver"Copy the code

Problems encountered during development

Main process and renderer process

  • electronIs essentially anodejs runtimeAnd an open sourcechromiumBrowser, development time master and renderer
  • The main process code is insrc/maindirectory
  • The renderer process code is insrc/rendererdirectory
  • And it goes throughwebpackRespectively formainandrendererPackage build
  • Interprocess communication can be usedipcMainandipcRendererTo communicate so that the renderer can call native resources in the main process

Main process window configuration

  • Since the main process development involved in this development is relatively simple, only involving a SRC /main/index.js, we can directly refer to the BrowserWindow configuration code in the file

    new BrowserWindow({
      height: 563.useContentSize: true.width: 1000.fullscreen: false.// Whether to allow full screen
      fullscreenable: false.titleBarStyle: 'hidden'.maximizable: false.webPreferences: {
        nodeIntegration: true.// Whether to introduce the Node API so that the renderer can use the Node API
        nodeIntegrationInWorker: true.enableRemoteModule: true // Whether to introduce the remote module so that the renderer can use the remote module API}})Copy the code
  • Of course, it also involves the reference to the local database LowDB, here is a reference to digg friends article

  • The application also involves a single window, using the requestSingleInstanceLock API to get if there is a window is running

    const gotTheLock = app.requestSingleInstanceLock()
    // Get the singleton instance lock and set application singleton
    if(! gotTheLock) { app.quit() }else {
      app.on('second-instance'.(event, commandLine, workingDirectory) = > {
        // When the second instance is run, the window mainWindow will be focused
        if (mainWindow) {
          if (mainWindow.isMinimized()) mainWindow.restore()
          mainWindow.focus()
        }
      })
      app.on('ready', createWindow)
      app.on('window-all-closed'.() = > {
        if(process.platform ! = ='darwin') {
          app.quit()
        }
      })
      app.on('activate'.() = > {
        if (mainWindow === null) {
          createWindow()
        }
      })
    }
    Copy the code

callpythonProblems encountered with the application

  • You have to go throughpyinstallerPackage separately for use in each operating system environmentcliThe application
  • Will be packed aftercliTool uncompressed package intostatic/clidirectory
  • Pass when calledwebpackSpit global__staticThe variable gets the corresponding path supplynodeChild process call
  • You need to modify the packaging configuration to make it workcli
    • Add “ASar “: false to the build field of package.json to ensure that the packaged application is not compressed and Node can access CLI resources normally

    • For Windows, configure the default installation path of NSIS to ensure that the path is available. Because the default installation path is C:\\Program Files, the path with Spaces will cause the call failure, so you need to add the configuration

      "nsis": {
        "some": "other config"."include": "./installer.nsh"
      }
      Copy the code

      Add an nSIS installation script installer. NSH to package.json so that the application is installed in C:\excel-utils by default

      ! macro preInit SetRegView 64 WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\excel-utils" WriteRegExpandStr HkCU "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\excel-utils" SetRegView 32 WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\excel-utils" WriteRegExpandStr HkCU "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\excel-utils" ! macroendCopy the code
    • For the Deepin system, the executable permissions of CLI programs are lost when webPack copies the static/ CLI directory. As a result, commands cannot be executed after package. Therefore, a script and command for adding permissions are added

    package.jsonIn the

    "scripts": {
      "build:linux": "node .electron-vue/build.js && .electron-vue/changeMainMod.sh && electron-builder",}Copy the code

    .electron-vueaddchangeMainMod.shAnd have it called after the business code has been packaged

    #! /bin/bashFor the main ` in ls. / dist/electron/static/cli / * / main ` do echo "is set at $main for executable permissions" chmod + x $main doneCopy the code
  • webpack.renderer.configThe whitelist problem
    • Due to the use ofvue2.X.UILibraries useelement-ui, found use during developmentel-tableThe component is not displayed correctly. After consulting information, it is found that it needs to be added to the package whitelist. The annotation is also very detailed and needs to be specifiedUI librariesTo compile.vuefile
    /** * List of node_modules to include in webpack bundle * * Required for specific packages like Vue UI libraries * that provide pure *.vue files that need compiling * https://simulatedgreg.gitbooks.io/electron-vue/content/en/webpack-configurations.html#white-listing-externals */
    let whiteListedModules = ['vue'.'element-ui']
    Copy the code

One day

There are two choices in technology selection: Electron and Nw.js. Here is a document to explain the similarities and differences between the two. The main differences are:

  • ElectronThere are many success storiesAtom,VScodeAnd so on. Of courseNW.jsThere are also giant apps like Dingding and wechat developer Tools
  • On the wholeElectronWith more user bases, more tripartite toolkits, a more active community, problems can be quickly solved
  • NW.jsTo keep theWindows xpSystem support, whileElectronIt is not supported for security reasons
  • And fornodeThe integration of,ElectronIntegrated withlibuvIn both processes, it can be used directly, eliminating the need for pairsChromiumHack, andNW.jsIt needs to be distributed

To move the brick

  • electron
  • electron-vue
  • node