如何利用 Electron 快速开发一个桌面端应用

前言

一直以来都有听说利用electron可以非常便捷的将网页应用快速打包生成为桌面级应用,并且可以利用 electron 提供的 API 调用原生桌面 API 一些高级功能,于是这次借着论证环信 Web 端 SDK 是否可以在 electron 生成的桌面端正常稳定使用,我决定把官方新推出的 webim-vue3-demo,打包到桌面端,并记录一下这次验证的过程以及所遇到的问题以及解决方式。

前置技能

  • 拥有良好的情绪自我管理,能够在遇到棘手问题时不一拳给到键盘。
  • 拥有较为熟练的水群能力,能够在遇到问题时,主动向技术群内参差不齐的群友们抛出自己的问题。
  • 【重要】拥有较为熟练的搜索引擎使用能力。
  • 能够看到这篇文章,那说明以上能力你已完全具备。

测试流程记录

第一步、准备工作

  • 克隆 vue3 Demo 项目到本地 环信 vue3-demo 源码地址
  • 在编辑器内打开此项目并执行yarn install安装项目相关 npm 依赖。
  • 在此项目目录下打开终端请敲下yarn add electron,从而在该项目中安装 electron。
  • 安装一些依赖工具wait-on以及cross-env

wait-on 是一个 Node.js 包,它可以用于等待多个指定的资源(如 HTTP 资源、TCP 端口或文件)变得可用。它通常用于等待应用程序的依赖项准备好后再启动应用程序。例如,您可以使用 wait-on 等待数据库连接、消息队列和其他服务就绪后再启动您的应用程序。这样可以确保您的应用程序在尝试使用这些资源之前不会崩溃。

cross-env 是一个 npm 包,它的作用是在不同平台上设置环境变量。在不同操作系统中,设置环境变量的方式是不同的。例如,在 Windows 中使用命令 set NODE_ENV=production 设置环境变量,而在 Unix/Linux/Mac 上则需要使用 export NODE_ENV=production 命令。

此时可能会进入到漫长的等待阶段,第一、这个包本身就比较大,第二、相信大家都懂由于网络原因导致,并且有可能进行会经历几次TIMOUT安装失败。此时就需要心平气和,且有耐心的进行改变镜像地址科学进行上网WIFI切换为移动流量多去重试几次,相信道友你总会成功过的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2xyqXdwF-1685947556715)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/69f46811946344499047553af9abccd9~tplv-k3u1fbpfcp-watermark.image?)]
有如下输出则应该为安装成功。
在这里插入图片描述

第二步、项目目录增加 electron 文件

在项目增加 electron 文件时我们需要扩展一部分知识从而了解为什么创建创建这个目录,并在该目录下增加main.js文件的作用。当然如果觉得不需要可以直接略过。

主进程与渲染进程的概念

在 Electron 中,主进程和渲染进程是两个不同的概念。主进程是 Electron 应用程序的核心,它运行在一个 Node.js 实例中,并管理应用程序的生命周期、窗口创建和销毁、与底层操作系统进行交互等。主进程还可以通过 IPC(进程间通信)机制与渲染进程进行通信。
渲染进程则是应用程序的 UI 界面所在的进程。每个 Electron 窗口都有其自己的渲染进程。渲染进程是一个 Chromium 渲染引擎实例,它运行在一个仅包含 Web API 的环境中。渲染进程负责渲染 HTML、CSS 和 JavaScript,并处理来自用户的输入事件,同时通过 IPC 机制与主进程进行通信。
由于渲染进程只能访问 Web API 而不能直接访问 Node.js API,因此如果需要在渲染进程中使用 Node.js API,就需要通过 IPC 机制向主进程发出请求,由主进程代为执行并将结果返回给渲染进程。

主进程与渲染进程分别应该写在哪?

在 Electron 应用程序中,主进程通常写在名为 main.js 或者 index.js 的 JavaScript 文件中,这个文件是应用程序的入口点。而渲染进程则通常写在 HTML 文件和其引入的 JavaScript 文件中。在一个 Electron 窗口中,可以通过调用 webContents 对象的 loadURL 方法来加载一个 HTML 文件,其中包含了渲染进程所需的代码和资源。该 HTML 文件中的 JavaScript 代码将运行在对应的渲染进程中,可以通过 Electron 提供的一些 API 和 Web API 来进行与用户界面相关的操作
需要注意的是,在 Electron 中,由于主进程和渲染进程是不同的 Node.js 实例,因此它们之间并不能直接共享变量或者调用函数。如果想要实现主进程和渲染进程之间的通信,必须使用 Electron 提供的 IPC 机制,通过发送消息的方式来进行进程间通信。

有些 electron 文件目录下 preload.js 的作用

在 Electron 中,preload.js 文件是一个可选的 JavaScript 文件,用于在渲染进程创建之前加载一些额外的脚本或者模块,从而扩展渲染进程的能力。preload.js 文件通常存放在与主进程代码相同的目录下。

preload.js 的实际运用主要有以下几个方面:

  1. 托管 Node.js API:preload.js 中可以引入 Node.js 模块,并将其暴露到 window 对象中,从而使得在渲染进程中也能够使用 Node.js API,避免了直接在渲染进程中调用 Node.js API 带来的安全风险。
  2. 扩展 Web API:preload.js 中还可以定义一些自定义的函数或者对象,然后将它们注入到 window 对象中,这样在渲染进程中就可以直接使用它们了,而无需再进行额外的导入操作。
  3. 进行一些初始化操作:preload.js 文件中的代码会在每个渲染进程的上下文中都运行一遍,在这里可以进行一些初始化操作,比如为页面添加一些必要的 DOM 元素、为页面注册事件处理程序等。

需要注意的是,preload.js 文件中的代码运行在渲染进程的上下文中,因此如果 preload.js 中包含一些恶意代码,那么它很可能会危及整个渲染进程的安全性。因此,在编写 preload.js 文件时,一定要格外小心,并且仅引入那些你信任的模块和对象。

1、 添加 electron 文件

  • 此时项目目录
    在这里插入图片描述

2、 electron 下新建main.js示例代码如下:

const { app, BrowserWindow } = require('electron');
const path = require('path');
const NODE_ENV = process.env.NODE_ENV;
app.commandLine.appendSwitch('allow-file-access-from-files');
function createWindow() {// Create the browser window.const mainWindow = new BrowserWindow({width: 980,height: 680,fullscreen: true,skipTaskbar: true,webPreferences: {nodeIntegration: true,preload: path.join(__dirname, 'preload.js'),},});if (NODE_ENV === 'development') {mainWindow.loadURL('http://localhost:9001/');mainWindow.webContents.openDevTools();} else {mainWindow.loadURL(`file://${path.join(__dirname, '../dist/index.html')}`);}
}// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.app.whenReady().then(() => {createWindow();
});// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', function () {if (process.platform !== 'darwin') app.quit();
});

3、 electron 下新建preload.js,示例代码如下:

此文件为可选文件

//允许vue项目使用 ipcRenderer 接口, 演示项目中没有使用此功能
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('ipcRender', ipcRenderer);

4、修改package.json,当前示例代码如下:

  • 修改"main"配置,将其指向为"main": "electron/main.js"
  • 增加一个针对 electron 启动的"scripts""electron:dev": "wait-on tcp:3000 && cross-env NODE_ENV=development electron ./"

当前项目配置如下所示

{"name": "webim-vue3-demo","version": "0.1.0","private": true,"main": "electron/main.js","scripts": {"dev": "vue-cli-service serve","build": "vue-cli-service build","lint": "vue-cli-service lint","electron:dev": "wait-on tcp:9001 && cross-env NODE_ENV=development  electron ./"},"dependencies": {"@vueuse/core": "^8.4.2","agora-rtc-sdk-ng": "^4.14.0","axios": "^0.27.2","benz-amr-recorder": "^1.1.3","core-js": "^3.8.3","easemob-websdk": "^4.1.6","element-plus": "^2.2.5","nprogress": "^0.2.0","pinyin-pro": "^3.10.2","vue": "^3.2.13","vue-router": "^4.0.3","vuex": "^4.0.0"},"devDependencies": {"@babel/core": "^7.12.16","@babel/eslint-parser": "^7.12.16","@vue/cli-plugin-babel": "~5.0.0","@vue/cli-plugin-eslint": "~5.0.0","@vue/cli-plugin-router": "~5.0.0","@vue/cli-plugin-vuex": "~5.0.0","@vue/cli-service": "~5.0.0","cross-env": "^7.0.3","electron": "^24.3.1","eslint": "^7.32.0","eslint-plugin-vue": "^8.0.3","sass": "^1.51.0","sass-loader": "^12.6.0","wait-on": "^7.0.1"}
}

第三步、本地启动起来验证一下

  1. 启动运行原 vue 项目

这里启动项目至端口号 9001,跟上面 electron/main.jsmainWindow.loadURL(' http://localhost:9001/')是可以对应上的,也就是 electron 运行起来将会加载此服务地址。

yarn run dev
  1. 新开一个终端执行,输入下方命令启动 electron

执行下面命令

yarn run electron:dev

可以看到自动开启了一个 electron 页面

image.png

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AHAwWz6J-1685947556717)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/df6cf25fcaf1447f8e2df4b73a14c793~tplv-k3u1fbpfcp-watermark.image?)]
并且经过测试验证登录没有什么问题。

第四步、尝试打包并验证打包出来的安装包是否可用。

1、安装electron-builder

该工具为 electron 打包工具库

electron-builder 官方文档

终端执行下面命令安装 electron-builder

yarn add electron-builder --dev

2、package.json 配置打包脚本命令以及设置打包个性化配置项

参考配置如下

具体配置项作用请参考官网文档,下面有些配置也是 CV 大发过来的,没有具体深入研究。

{"name": "webim-vue3-demo","version": "0.1.0","private": true,"main": "electron/main.js","scripts": {"dev": "vue-cli-service serve","build": "vue-cli-service build","lint": "vue-cli-service lint","electron:dev": "wait-on tcp:9001 && cross-env NODE_ENV=development  electron ./","electron:build": "rimraf dist &&  vue-cli-service build &&  electron-builder","electron:build2": "electron-builder"},"dependencies": {"@vueuse/core": "^8.4.2","agora-rtc-sdk-ng": "^4.14.0","axios": "^0.27.2","benz-amr-recorder": "^1.1.3","core-js": "^3.8.3","easemob-websdk": "^4.1.6","element-plus": "^2.2.5","nprogress": "^0.2.0","pinyin-pro": "^3.10.2","vue": "^3.2.13","vue-router": "^4.0.3","vuex": "^4.0.0"},"devDependencies": {"@babel/core": "^7.12.16","@babel/eslint-parser": "^7.12.16","@vue/cli-plugin-babel": "~5.0.0","@vue/cli-plugin-eslint": "~5.0.0","@vue/cli-plugin-router": "~5.0.0","@vue/cli-plugin-vuex": "~5.0.0","@vue/cli-service": "~5.0.0","cross-env": "^7.0.3","electron": "^24.3.1","electron-builder": "^23.6.0","eslint": "^7.32.0","eslint-plugin-vue": "^8.0.3","sass": "^1.51.0","sass-loader": "^12.6.0","wait-on": "^7.0.1"},"build": {"productName": "webim-electron","appId": "com.lvais","copyright": "2023@easemob","directories": {"output": "output"},"extraResources": [{"from": "./src/assets","to": "./assets"}],"files": ["dist/**/*", "electron/**/*"],"mac": {"artifactName": "${productName}_${version}.${ext}","target": ["dmg"]},"win": {"target": [{"target": "nsis","arch": ["x64"]}],"artifactName": "${productName}_${version}.${ext}"},"nsis": {"oneClick": false,"allowElevation": true,"allowToChangeInstallationDirectory": true,"createDesktopShortcut": true},"linux": {}}
}

3、开始 build

  • 先这样

build 原始 vue 项目

yarn run build
  • 再那样

build electron 项目

yarn run electron:build

可能会进入漫长的等待,但是不要慌,可能与网络关系比较大,需要耐心等待。

image.png

打包成功之后可以看到有一个 output 文件夹的生成,打开之后可以选择双击打开软件验证看下是否可以正常开启应用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-btaer10P-1685947556717)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/80e038c5acb14055afa55d5b92c41e47~tplv-k3u1fbpfcp-watermark.image?)]
正常开启页面的话,证明没有问题,如果遇到了问题,下方会有一些我遇到的问题,可以作为参考。
在这里插入图片描述

令人痛苦的问题汇总

问题一、打包后页面空白,并且出现类似(Failed to load resource: net::ERR_FILE_NOT_FOUND)报错

问题简述:发现只有在打包之后的 electron 应用,启动后存在页面空白,dev 情况下正常。

解决手段之一:

经排查,更改vue.config.jspublicPath的配置为’./’

const { defineConfig } = require('@vue/cli-service');
module.exports = defineConfig({transpileDependencies: true,lintOnSave: false,devServer: {host: 'localhost',port: 9001,// https:true},publicPath: './',chainWebpack: (config) => {//最小化代码config.optimization.minimize(true);//分割代码config.optimization.splitChunks({chunks: 'all',});},
});

原因打包后的应用 electron 会从相对路径开始找资源,所以经过此配置可以所有资源则开始从相对路径寻找。

    默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上,例如 `https://www.my-app.com/`。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 `https://www.my-app.com/my-app/`,则设置 `publicPath` 为 `/my-app/`。这个值也可以被设置为空字符串 (`''`) 或是相对路径 (`'./'`),这样所有的资源都会被链接为相对路径,这样打出来的包可以被部署在任意路径,也可以用在类似 Cordova hybrid 应用的文件系统中。

解决手段之二:

经过一顿操作之后发现仍然还是空白,并且打开控制台看到页面可以正常加载资源文件,但是 index.html 返回此类错误:We're sorry but XXX doesn't work properly without JavaScript,经过查找发现可以通过修改路由模式来解决,经过测试确实有效。

参考文章为:https://www.imgeek.net/article/825363952

修改后的代码示例:

const router = createRouter({//改为#则可以直接变更路由模式history: createWebHistory('#'),routes,
});

问题二、

问题简述:页面展示正常后,调用登录发现出现下图报错
在这里插入图片描述

解决方式:经发现原来是发起 axios 请求环信置换连接 token 接口的时候,协议的获取是通过window.location.protocol来获取的,那么打包之后的协议为file:那么这时发起的请求就会变更为以 file 协议发起的请求,那么修改这里的逻辑,判断如果为 file 协议则默认走 http 协议发起请求,示例代码如下:

import axios from 'axios';
const defaultBaseUrl = '//a1.easemob.com';
console.log('window.location.protocol', window.location.protocol);
// create an axios instance
const service = axios.create({withCredentials: false,// baseURL: process.env.VUE_APP_BASE_API, // url = base url + request urlbaseURL: `${window.location.protocol === 'file:' ? 'https:' : window.location.protocol}${defaultBaseUrl}`,// withCredentials: true, // send cookies when cross-domain requeststimeout: 30000, // request timeoutheaders: { 'Content-Type': 'application/json' },
});
// request interceptor
service.interceptors.request.use((config) => {// do something before request is sentreturn config;},(error) => {// do something with request errorconsole.log('request error', error); // for debugreturn Promise.reject(error);}
);// response interceptor
service.interceptors.response.use(/*** If you want to get http information such as headers or status* Please return  response => response*//*** Determine the request status by custom code* Here is just an example* You can also judge the status by HTTP Status Code*/(response) => {const res = response.data;const code = response.status;// if the custom code is not 20000, it is judged as an error.if (code >= 400) {return Promise.reject(new Error(res.desc || 'Error'));} else {return res;}},(error) => {if (error.response) {const res = error.response.data; // for debugif (error.response.status === 401 && res.code !== '001') {console.log('>>>>>无权限');}if (error.response.status === 403) {res.desc = '您没有权限进行查询和操作!';}return Promise.reject(res.desc || error);}return Promise.reject(error);}
);export default service;

参考资料

  • electron 中文文档

特别鸣谢两位道友文章非常有用,可以作为参考:

  • Electron + Vue3 +Ant Design Vue 桌面应用从项目搭建到打包发布

  • Electron + Vue3 + TS + Vite 桌面应用项目搭建教程!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/350235.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Nginx location匹配优先级 与 Rewrite

目录 前言locationlocation 常用的匹配规则location 优先级实例演示 rewrite前言rewrite跳转实现rewrite 执行顺序语法格式rewrite全局变量实例演示 前言 从功能看 rewrite 和 location 似乎有点像,都能实现跳转,主要区别在于 rewrite 是在同一个域名内…

小白必看!轻松理解和解决MySQL幻读问题!

大家好,我是小米!今天我来给大家分享一下关于MySQL数据库中常见的一个问题——幻读,以及如何解决它。相信对于数据库开发和管理的小伙伴们来说,幻读是一个相对棘手的问题,但只要我们掌握了正确的解决方法,它…

绿色荧光试剂210236-90-1,FITC Tyramide,Fluorescein-Tyramide

●中文名:荧光素酪胺 ●英文名:FITC Tyramide,Fluorescein-Tyramide,FITC TSA (文章编辑资料汇总来源于:陕西新研博美生物科技有限公司小编MISSwu)​ ●外观以及性质: 荧光素酪胺…

emz文件打开

1. 打开word 2. 插入图片 3. 选择需要打开的emz文件 4. done

Windows11系统下解压文件后缀为.tar(.gz)的压缩文件

第一步:进入解压文件所在的当前文件夹内右键点击在终端打开 第二步:在终端内输入tar -zxvf xxx.tar.gz(如果是.tar.gz文件就输入该行指令,如果是.tar文件就输入tar -zxvf xxx.tar指令,其中xxx为文件名) 第三…

成熟GPT小程序源码分享,快速搭建GPT小程序

本文中分享成熟的GPT小程序源码,帮助你快速搭建自己的GPT小程序。 GPT小程序源码介绍 GPT小程序源码是一套成熟的GPT编程框架,可以帮助你快速开发高质量的GPT小程序。该源码包含了丰富的功能模块和优秀的编程实践,可以帮助你轻松实现GPT小程…

.ziw文件是什么?如何打开.ziw文件?

.ziw文件是为知笔记的一种文档格式打开方式:找到为知笔记的官网,下载它的windows安装包即可 [缺点:该软件会有一个使用的有效期] 打开.ziw文件时,右击选择发送到“为知笔记”,选择相应的文件夹保存即可

GDS文件如何打开?

GDS文件是一种“版图”文件。用于生产 光刻工艺所需的 掩膜版。 使用 KLayout 软件打开 KLayout 是一个 GDS 和 OASIS 文件 查看器 KLayout 也是一个允许更改 GDS 和 OASIS 文件并从头开始创建它们的 编辑器 KLayout 是 免费的 KLayout 官网:https://www.klayou…

html解压zip文件怎么打开方式,zip文件是什么文件,如何打开zip格式的文件?

zip文件是小编经常要用到的文件,因为zip文件不仅在windows平台里面有用,而且在linux平台里面也可以用,二个平台都兼容,压缩的也很好, 所以,小编非常喜欢zip压缩的文件。下面,小编就来为大家介绍…

linux下压缩gz文件怎么打开,在Linux系统中打开或解压缩.gz文件及提取tar.gz文件的方法...

本文本文介绍如何打开(或解压缩).gz文件的方法。Gzip是一种流行的压缩算法,可在保持原始文件模式、所有权和时间戳的同时减小文件大小,此算法通常用于压缩Web元素,以加快页面加载速度。按照约定,使用gzip压缩的文件以.gz或.z结尾。…

linux显示 zbj目录下的文件,ZBJ 文件扩展名: 它是什么以及如何打开它?

解决难以打开 ZBJ 文件的问题 打开 ZBJ 文件过程中所遇到的常见问题 Unknown Software 已删除 尝试打开 ZBJ 时,你会遇到一条错误消息,例如 “%%os%% 无法打开 ZBJ 文件”。 通常情况下,这意味着 Unknown Software 没有安装在 %%os%% 上。 您…

计算机用户名uz,UZ 文件扩展名: 它是什么以及如何打开它?

UZ 文件并发症 打开 UZ 文件的问题 Unreal Tournament 消失 你尝试加载 UZ 文件并收到错误,例如 “%%os%% 无法打开 UZ 文件扩展名”。 如果是这种情况,通常是因为 你的计算机上没有安装 Unreal Tournament for %%os%%。 操作系统不知道如何处理你的 UZ …

vue3+element-plus的后台管理系统模板 和 vue3+ant-design-vue的后台管理系统模板

项目介绍 规范:后台系统模板,按照企业级别的规范搭建的。 权限控制:通过后端返回的路由表(这个路由表是由前端这边在系统配好的然后存储在后端的)来动态渲染菜单和注册路由,同时也根据页面内的接口权限对页…

科研热点|科研人专属身份证来了,国产ORCID ID启动!

2023年6月1日,国家自然科学基金委员会发布了《国家自然科学基金委员会关于推广和发布基础研究科研人员标识(BRID)有关工作安排的通告》,宣布从即日起,国家自然科学基金委员会(以下简称自然科学基金委&#…

技术分享 | App常见bug解析

【摘要】 功能Bug内容显示错误前端页面展示的内容有误。这种错误的产生有两种可能1、前端代码写的文案错误2、接口返回值错误功能错误功能错误是在测试过程中最常见的类型之一,也就是产品的功能没有实现。比如图中的公众号登录不成功的问题。界面展示错乱产品界面上…

yolov3

文章目录 前言一、主干网络darknet53二、从特征获取预测结果 前言 本文主要讲解yolov3的基本知识,如有错误请指出。 本文主要来自 博客1 博客2 一、主干网络darknet53 53是因为有53层。 1、darknet53没有使用pooling 来进行下采样,而是用一个33&…

C语言:计算n的阶乘(不考虑溢出)

题目: 从键盘输入一个值n,计算n的阶乘, 如:输入5,计算5的阶乘 --> 5! 1 * 2 * 3 * 4 * 5 思路: 第一步: 创建一个变量 ret ,用来存放每次相乘后的值, 因为 0 乘 任何…

java排列组合(递归算法)

一、排列 1、计算公式如下: 2、使用方法,例如在1,2,3,4,5中取3个数排列: 3、全排列 当mn时,结果为全排列。例如1,2,3,4的全排列如下&#xff1…

算法中的排列与组合

排列组合公式 不含重复元素的排列组合 含有重复元素的排列组合 如果产生的组合和排列可以包含有重复的元素,其实这类问题在苏荷数学上是多种集的排列和组合问题。 多重集的排列问题 设S是有k种不同类型对象的多重集合,每个元素都有无限的重复数。那么…