Electron + Vue

2020-2-14 101 2/14

背景

近期公司几个大神应公司需求自研+自制了一个硬件(街机上的电子投币开关),用的树莓派,里面需要一个自启动的应用程序,展示一个付费的二维码和一些维护或者等待页面之类的,公司没有专职开发桌面应用的,机会当然就给了前端...,还好有electron,下面简单记录一下这个项目开发时候需要安装哪些工具与步骤。

创建项目

安装脚手架vue cli

npm install -g @vue/cli

创建项目

vue create vue-electron

添加electron插件


vue add electron-builder
这里可能会非常慢,最终导致超时失败。这是因为需要根据系统来下载electron的基础库,由于网络原因,建议此处使用设置npm proxy来进行下载。不建议使用其他镜像源下载,可能会导致最终打包失败。

启动

此时项目src文件夹下就多了一个background.js,这里就是electron主进程相关代码,负责和我们的vue页面(渲染进程)进行交互。
执行以下代码启动项目

npm run electron:serve

配置background.js

//background.js
//文件头部,引用增加ipcMain用于通信
import { app, protocol, BrowserWindow, ipcMain } from 'electron'
import { createProtocol } from '@matthijsburgh/vue-cli-plugin-electron-builder/lib'
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
const isDevelopment = process.env.NODE_ENV !== 'production'
//窗口启动增加选项
const win = new BrowserWindow({
    width: 800, //窗口默认宽度
    height: 600, //窗口默认高度
    useContentSize: false, 
    frame: true, //取消window自带的关闭最小化等
    resizable: false, //禁止改变主窗口尺寸
    transparent: false, //透明
    hasShadow: true, //窗口阴影
    maximizable: true,  //是否允许最大化
    webPreferences: {
      enableRemoteModule:true, //在渲染进程启用remote模块
      nodeIntegration: true, //在渲染进程启用Node.js
      contextIsolation:false,
      webSecurity: false,
      backgroundThrottling: false, //程序在最小化时渲染进程不冻结
    }
  })
  //由于渲染进程中electron.remote已废弃,需要手动引入,并在每一个browserwindow中启用remote
  require('@electron/remote/main').initialize()
  require("@electron/remote/main").enable(win.webContents);
  if (process.env.WEBPACK_DEV_SERVER_URL) {
    // Load the url of the dev server if in development mode
    await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
    if (!process.env.IS_TEST) win.webContents.openDevTools()
  } else {
    createProtocol('app')
    // Load the index.html when not in development
    win.loadURL('app://./index.html')
  }

配置main.js

//main.js
const electron = window.require('electron') //引用electron
const fs = window.require('fs') //引用Node模块fs
const remote = window.require('@electron/remote') //引用remote模块用于通信、打开文件弹框等
Vue.prototype.$electron = electron
Vue.prototype.$fs = fs
Vue.prototype.$remote = remote

页面应用

//在页面中使用相关API
this.$electron.ipcRenderer.sendSync('testMsg',data); //与主进程通信
this.$remote.getCurrentWindow().minimize(); //最小化窗口
this.$fs.existsSync("C:/test.js"); //调用nodejs方法查找文件是否存在

打包配置vue.config.js

module.exports = {
  pluginOptions: {
    electronBuilder: {
      "customFileProtocol": "./", //增加此项让css中相对引用的文件能正常访问,否则一些css库中的字体会无法显示
      "builderOptions": {
        "extraResources": [
          "./extraResources/**", //这里指定外部资源文件夹,你可以把一些外部程序放在./extraResources中,比如ffmpeg等,打包时electron将直接原样拷贝
          "./node_modules/@electron/remote/**"//必须添加这一行否则remote会引用不到
        ],
        "productName": "",
        "appId": "",
        "copyright":"",// 版权信息
        "directories": {
          "output": "./build" //输出文件夹
        },
        "afterSign": "", //签名文件
        "dmg": { //输出mac的dmg时图标位置
          "contents": [
            {
              "x": 410,
              "y": 150,
              "type": "link",
              "path": "/Applications"
            },
            {
              "x": 130,
              "y": 150,
              "type": "file"
            }
          ]
        },
        "mac": {
          "icon": "./applogo.icns",//mac图标,必须至少包含512*512尺寸的图标
          "target":[{
            "target": "dmg", //设置输出dmg安装包
            "arch": ["arm64", "x64"], //arm64是apple silicon机器专用的包;x64是intel版的包,两种电脑都能用,不过x64运行启动会慢一点;这里你可以填universal,这样会生成一个arm64+x64打出来然后装一起的一个包(体积也是两种应用之和),运行时会自动选择版本
          }],
          "identity": "your name",
          "entitlements": "./entitlements.mac.plist", //签名必须
          "entitlementsInherit": "./entitlements.mac.inherit.plist"//签名必须
          "entitlementsLoginHelper": "./entitlements.mas.loginhelper.plist"//如果需要mac的mas版打包,则需要此项
        },
        "win": {
          "icon": "./applogo.ico",//win打包图标
          "target": [{
            "target": "nsis",// 利用 nsis 制作安装程序
            "arch": [
              "x64",//64]
          }]
        },
        "nsis": {
          "oneClick": false, // 是否一键安装
          "allowElevation": true, // 允许请求提升. 如果为 false, 则用户必须使用提升的权限重新启动安装程序.
          "allowToChangeInstallationDirectory": true, // 允许修改安装目录
          "installerIcon": "./applogo.ico",// 安装图标
          "uninstallerIcon": "./applogo.ico",// 卸载图标
          "installerHeaderIcon": "./applogo.ico", // 安装时头部图标
          "createDesktopShortcut": true, // 创建桌面图标
          "createStartMenuShortcut": true,// 创建开始菜单图标
          "shortcutName": "DNG自动转换工具", // 图标名称
          "perMachine": true
        },
      }
    }
  },
  configureWebpack: config => {
    return {}//webpack相关配置
  }
}

打包APP

npm run electron:build

打包后运行偶尔出现闪退问题

解决方案

//background.js
import { app } from 'electron'
app.commandLine.appendSwitch('--no-sandbox'); //该行应在app.on('ready')前面执行

require报错

require无法引用,根本原因node中的require覆盖了webpack的require,这就导致了打包失败

  1. 解决方案一
    • //background.js
      //在渲染进程中禁用Node.js。在主进程background.js中,将nodeIntegration选项设置为false
      //这样就可以正常使用require了。副作用是无法访问一些底层的参数比如__dirname,当引用的组件使用这些参数时会报错。
      const win = new BrowserWindow(
        webPreferences: {
          nodeIntegration: false //该选项在渲染进程中禁用Node.js
        }
      })
  2. 解决方案二 (推荐)
    • //background.js
      const win = new BrowserWindow(
        webPreferences: {
          nodeIntegration: true //该选项在渲染进程中启用Node.js
        }
      })
    • //main.js
      //在require组件时,必须在main.js中引用,并且必须使用window.require
      const electron = window.require('electron')
      Vue.prototype.$electron = electron 这样就可以在页面中通过this.$electron访问到electron的API了

以上就是这次大概的开发流程,记录以下以后可以备用,毕竟开发开发桌面应用的实战机会不多

 

- THE END -

米阳

10月24日11:18

最后修改:2024年10月24日
1

非特殊说明,本博所有文章均为博主原创。