从0搭建项目
项目搭建将会使用到的技术栈及组件库有如下,后续实际开发还会使用不同的库就不一一列举了:
Vue3+Vite+Pinia+Electron+Vue-router+axios+Element Plus等

搭建基础的版本限制
针对
vue3需要16以上的node版本,这里安装了16.17.1,npm安装了8.15.0

根据上面的要求搭建完成后的各基础版本如下

构建Vue3项目
1 | yarn create vite [项目名称] --template vue |
进入项目中安装依赖
1 | yarn |
安装Electron
1 | yarn add electron@22 -D |
应要求和Electron官网公告,22版本是最后支持Windows7的主版本,遂使用Electron22
规范文件目录
在根目录下新建electorn文件夹,内部新建main和preload文件夹,其中main文件夹为主进程代码,preload是预加载脚本代码
src下为渲染进程相关代码
安装electorn和vite
electron-builder 用于 electron 应用打包
vite-plugin-electron 方便用 vite 热更新 electron
1 | yarn add electron-builder@23.1.0 vite-plugin-electron@0.7.5 -D |
上面为固定版本,其他版本测试出现了问题
编辑基础vite.config.js文件
1 | import { defineConfig } from "vite"; |
修改package.json
将
"type":"module"删除,因为项目中会用到commonJS类型包,增加"main":"dist/electron/main/index.js"项目入口
基础代码
electron>main>index.js
1 | import { app, BrowserWindow } from "electron"; |
简单修改vue中的内容
1 | <template> |
预览和打包
1 | yarn dev |
使用上面指令可以正常查看效果
打包指令
将package.json中的脚本改为
1 | "build": "vite build && electron-builder", |
新建基础打包构建配置文件
在根目录下新建
electron-builder.json文件内容如下
1 | { |
打包后,会输出在release文件夹下,其中的exe文件就是应用程序的可执行文件了
打包可能的报错
在上方打包过程中可能会遇到下载对应版本electron失败的问题;一直卡在再downloading,可以用如下方法解决:
多尝试几次
electron-builder 在打包时会检测cache中是否有electron 包,从报错中提供的地址下载zip并放在本地cache文件夹下
Windows: %LOCALAPPDATA%/electron/Cache or ~/AppData/Local/electron/Cache/1
2
3
4
5
6
7
## 安装vue-router
>根据`vue-router`的更新日志,认为4.2.0是一个较为稳定的版本
yarn add vue-router@4.2.0
1 |
|
yarn add pinia@2.1.0
1 |
|
yarn add element-plus
yarn add unplugin-vue-components unplugin-auto-import -D
1 |
|
遇到问题
在搭建初期,应用的控制台上会有如下黄色警告,是因为

通过搜索,有一个解决办法是修改index.html的meta标签的属性,如下

确实加上后CSP的警告消失了,但是在我安装Element Plus组件的时候,发现无论怎么调试,组件样式不生效。
找了半天原因,发现是这里阻止了其他资源的引入
后续改回原来的meta后显示组件正常了,再次加上内容安全策略后警告没了,组件又可以正常展示了,暂时不知道啥原因。
这里的话,不用上面的解决策略了,还有另一个官方给出的强制关闭方法,可以在主进程文件顶部加上下面的内容就没有警告提示了
1 | // 屏蔽不安全的协议http 提示 |
安装axios
使用一月份的较新的版本1.2.3
1 | yarn add axios@1.2.3 |
拦截器的设置具体根据项目要求制定
Vue3的Api自动导入
由于在上面我们安装过unplugin-auto-import插件了,我们只需要在vite.config.js中添加配置:
1 | plugins: [ |
注意
如果项目使用了eslint,直接在文件中使用vue的api而没有导入的话,会提示报错,这里我们需要安装另一个插件: vue-global-api
1 | yarn add vue-global-api -D |
1 | // eslintrc.js |
1 | // main.js |
安装初始化样式
安装
normalize.css并导入,最近的版本还是18年的8.0.1,应该较为稳定
1 | yarn add normalize.css@8.0.1 |
1 | import "normalize.css/normalize.css"; |
安装eslint
eslint-plugin-vue:Vue.js的官方ESLint插件
eslint-plugin-simple-import-sort:自动排序import的插件
eslint在版本8之后用官方的话来说有一些面向用户的破坏性变更,其中就有不再支持Node.js10、13、15,因为我们使用的是16.17.1,所以暂时决定使用23年一月发布的8.33版本
eslint-plugin-vue使用6个月前的9.9.0版本,下载次数较多暂时选择这个https://www.npmjs.com/package/eslint-plugin-vue?activeTab=versions
eslint-plugin-simple-import-sort更新频率不高,暂决定使用10个月前的下载较多的8.0.0版本https://www.npmjs.com/package/eslint-plugin-simple-import-sort?activeTab=versions
1 | yarn add eslint@8.33.0 eslint-plugin-vue@9.9.0 eslint-plugin-simple-import-sort@8.0.0 -D |
暂时不确定是否校验是否有什么冲突之类的问题(存在问题⚠,上面的版本存在坑,详情见最后问题>关于eslint和prettier版本)
根目录下新建.eslintrc.js文件
1 | module.exports = { |
安装prettier
prettier直接安装七月最新的3.0版本相关博客:https://prettier.io/blog/
eslint-config-prettier安装4个月前也是最新的版本8.8.0https://www.npmjs.com/package/eslint-config-prettier?activeTab=versions
eslint-plugin-prettier还是安装一年前的版本(4.2.1)最稳定https://www.npmjs.com/package/eslint-plugin-prettier?activeTab=versions
1 | yarn add prettier@3.0 eslint-config-prettier@8.8.0 eslint-plugin-prettier@4.2.1 -D |
(存在问题⚠,上面的版本存在坑,详情见最后问题>关于eslint和prettier版本)
在根目录下新建.prettierrc.js文件
大致配置如下内容:
1 | module.exports = { |
详细需要配置哪些内容可以参考下面的博客:
https://juejin.cn/post/7216182414699003965
代码提交规范和版本更新规范等
后续会输出一个关于代码提交、版本迭代、版本日志生成的规范化流程
生成图标electron-icon-builder
用于生成electron包所需要的所有图标文件
1 | yarn add electron-icon-builder -D |
根目录新建文件夹resources,放一个名为icon.png的图片,在package.json脚本中新增指令
1 | "build-icon": "electron-icon-builder --input=./resources/icon.png --output=./resources/ --flatten" |
如果不加--flatten的话,会在resources文件夹下生成icons文件夹,下面分别生成mac、png、win三个文件夹,这里需要注意是否使用–flatten。会影响后面路径的填入。
运行yarn build-icon就能够看到resources下生成了一个文件夹,内有各种格式图片文件
接着在electron>main下新建utils文件夹,内新增icon.js文件
1 | import path from 'path' |
修改electron-builder.json文件的图片打包路径相关
1 | { |
安装调试工具vue devtools
暂时不安装了,
vue3的扩展工具用起来很卡
生成日志electron-log
通过此工具可以知道当前安装的应用的运行情况,生成本地日志
1 | yarn add electron-log -D |
在electron>main>utils下新建log.js文件
1 | import {app} from 'electron' |
多窗口的实现
应用启动后可能存在一个加载界面,然后加载进程完成后,加载界面窗口自动关闭,然后自动打开一个新的主界面的窗口,所以需要考虑多窗口的实现方法
- 因为一个窗口的实现,是将渲染进程的内容挂在了
index.html中,如果需要多渲染一个窗口的话,可以新建一个index.html,然后新建一个新的newWindow.vue、newWindow.js文件,用相同的方式去渲染另一个窗口;但是这种方法需要配置vite.config.js中的多路径等配置 - 或者使用访问其他路由的方法去新开窗口,实现方式就是重新
new BrowserWindow(),然后去loadURL()的地址改成新窗口的路由
通过ipcRenderer和ipcMain的方法通信,根据需要开启和关闭相应的窗口即可
总结
自此,整体框架大致就如此了,后续需要注意的是各个组件库的选型和安装的库的版本兼容以及接口调通相关的问题,以及细节部分还得考究,除此之外,我还会将代码提交规范和提交日志的方法总结实现一下。
问题
安装问题
上面安装过程可能遇到下载
phantomjs失败,可以通过手动下载解决,放到:
C:\Users\xxxx\AppData\Local\Temp\phantomjs\phantomjs-2.1.1-windows.zip下即可
渲染进程组件内不能导入node的相关API
背景:在
Vue+vite+electron项目里,如果在app.vue文件中使用import {electron} form 'electron',会报xxx is not defined或者使用require的CMJ方式也会报类似__dirname is not defined的错误,即使加了nodeIntegration: true,也不起作用。不知道是不是vite导致的加了上面配置也无法在渲染进程集成Node环境。我们要在渲染进程去监听主进程的事件,或者向主进程发送事件等,所以,有在渲染进程使用
ipcRenderer.on的场景,所以需要找到解决办法
解决方案:我们需要使用预加载的方式提前将一些Node的
API暴露出来,这里可以使用electron官方提供的方法:contextBridge官方解释如下:在隔离的上下文中创建一个安全的、双向的、同步的桥梁。
使用
contextBridge的方法,我们可以从隔离的预加载脚本将API暴露给渲染器
preload>index.js
1 | import {contextBridge, ipcRenderer} from 'electron' |
通过这个方法,可以将ipcRenderer暴露给渲染进程使用
同时我们需要在创建窗口时添加属性配置以实现预加载:
1 | contextIsolation: true, |
这时启动后就可以在渲染进程使用contextBridge暴露出来的Node的API了(contextIsolation在electron12之后默认为true,同样必须开启此项,contextBridge才能启动,否则会报错)
关于eslint和prettier版本
问题发现过程是在安装
lint-staged后,在package.json中配置校验脚本时,需要用到yarn lint检测代码中是否存在不合理处,使用yarn lint时会出现一系列问题,下面说下过程。
在实现代码提交规范的过程中,需要安装lint-staged插件,安装后,在提交代码时会做自动校验,所以我们需要通过一个脚本指令实现自动校验,这里用到了eslint的指令,如下
1 | "scripts": { |
当跑yarn lint时,会报下面错误

经过调查,发现是prettier3和eslint-plugin-prettier4不兼容,遂将prettier降到了2.3.0版本,为了防止还有什么bug,我将eslint升级到了最新的版本8.44.0
升降级结束后一切回归正常
参考
以及Vue、Vite、Pinia等各个官网和npmjs等
开发遇到的问题
Element-plus的样式穿透问题
部分弹出框的组件使用:deep()无法样式穿透,需要在一个文件内进行样式穿透然后将文件导入,使用组件自定义类名
vite的动态导入图片问题
正常的动态导入,无法识别图片路径,需要使用new URL()的方法,将图片路径转化`
1 | <img class="item-icon" :src="getIconPath(item.iconName)" alt="" /> |
electron开启上下文隔离后的双向通信
由于开启了上下文隔离,在渲染进程无法直接使用electron的api,由此需要在预加载脚本中通过contextBridge将指令抛出给渲染进程使用,再在主进程通过ipcMain.handle去监听事件并调取api然后返回通信内容
Teleport不能放在v-for中
Electron应用的接口跨域需要开启配置
webSecurity: false // 允许跨域
Vue Router4传参不要使用params
在4.14版本以上好像会有使用
params传参route.params接受不到使用query: { sid: xxxxxxx }或者回退版本
vue3使用hooks
如果需要共享的变量是位于全局,需要在外层定义
1 | import {ref} from 'vue' |
axios使用delete传入请求体参数存在数组的方法
1 | deleteService: (body) => service.delete(`/data_services`, {data: body}) |
1 | let params = { |
修改项目的字体
当前可能存在一种情况:我们在项目中使用了一种特定的字体,但是在项目运行的设备上却不存在该字体,我们设置的字体就会不生效,这时候需要我们将我们使用的字体文件放在项目中,手动导入字体
- 我们要如何知道使用设备上是否存在我们需要的字体呢?
在windows种我们打开控制面板找到字体,这里显示的是我们可直接使用的所有字体种类,如果我们期望使用的不存在这些范围内,那么我们就需要手动导入对应的字体了
如何导入字体?
- 首先我们需要拿到字体的文件,字体文件我们可以从字体网站上去下载,拿到otf或者ttf扩展名的字体文件,将其放入到项目的某一个目录下
- 在该目录下创建一个css文件,如font.css,导入对应字体文件,如下:
1
2
3
4
5
6@font-face {
font-family: 'Source Han Sans CN'; /* 重命名字体名 */
src: url('SourceHanSansSC-VF.ttf');
font-weight: 500;
font-style: normal;
}
在App.vue种导入该文件
1 | @import './assets/font/font.css'; |
- 在全局中使用该字体
1 | body { |
electron请求管理员权限
当应用内某个特定场景需要使用管理员权限,可以在启动应用时询问是否以管理员身份启动
- 当我们使用electron-builder打包应用,我们可以在
electron-builder.json文件中增加配置
1 | "win": { |
关于electron-builder.json文件配置详情见官网https://www.electron.build/configuration/win
此配置存在三种情况
asInvoker:默认配置requireAdministrator:管理员权限highestAvailable:可用的最高权限
实现界面多数据加载的滚动效果
我们模拟安装时的进度信息滚动效果,当滚动高度多达几万行时,界面节点过多导致界面渲染压力增大,导致界面卡顿崩溃。
问题在于节点过多,并且节点快速增加,我们需要使用虚拟节点,使得在当前可视范围内展示少量的节点,可以手动写一个组件去实现虚拟节点,但是这里我们为了实现信息滚动的效果,我们使用一个插件
xTerm.js- 这个插件是用于模仿命令行的输入输出窗口
- 但是这个插件内部实现了虚拟节点的效果,几万行数据也只会在界面渲染可视范围的几行内容,并且可以设置为canvas渲染。
- 设置写入的字体颜色文档:https://www.cnblogs.com/goloving/p/15015053.html
1
2
3
4term.value.writeln(`\x1b[33;2;235;147;20;1m警告:可能存在不当地方1\x1b[0m`)
term.value.writeln(`\x1b[33m警告:可能存在不当地方2\x1b[0m`)
term.value.writeln(`\x1b[31;2;227;77;89;1m错误:预处理任务失败1\x1b[0m`)
term.value.writeln(`\x1b[31m错误:预处理任务失败2\x1b[0m`)
setInterval在浏览器非激活状态的误差
因为浏览器的优化原因,setTimeout()和setInterval(),在浏览器窗口非激活的状态下会停止工作或者以极慢的速度工作。
在项目中,在数据预处理阶段需要使用到计时效果,而且我们的预处理可能时间长达几天,这期间电脑会锁屏等情况,还可能最小化我们的应用,这时候浏览器会让setInterval以极慢的速度工作,导致与实际计时时间不一致,几天过去,可能计时才显示过几小时。
问题描述
- 当待预处理的文件体量很大的情况下,预处理可能会持续几小时或几天,在用户将窗口最小化或者锁屏后,预处理界面上的计时会存在很大的误差,可能预处理了几天界面上的已用时才显示几小时。
问题原因
- 界面上的已用时使用的是setInterval做的计时器。然而setInterval会存在下面的问题。
- 因为浏览器的性能优化策略,为了减少非激活状态下的资源消耗,setTimeout()和setInterval(),在浏览器窗口非激活的状态下会停止工作或者以极慢的速度工作。当浏览器窗口被最小化或切换到后台标签页时,浏览器可能会将该标签页的 JavaScript 执行降低到最小程度,以减少 CPU 和内存的使用。这是为了确保活动标签页能够获得更多的系统资源,提高用户体验。
解决方案
- 使用Web Workers,Web Workers 可以在后台线程中执行任务,不受主线程执行的影响。这可以提高定时器的准确性。
- 具体做法是,将主线程中的 js 计时移到Web Workers中的线程中,计时在后台线程中进行,即使主界面处于不活跃状态,主进程js受性能优化策略影响,Web Workers线程中依旧可以进行正常的计时操作并返回相对准确的内容。
代码
1 | // timeCountWorker.js |
1 | // 需要用到的位置 Vite项目 |
app.asar打包体积逐渐变大
问题
在项目运转多月后发现前端打包的app.asar文件已经由一开始的20多M变为了300多M
原因
通过在仓库中下载之前tag下的源文件,和当前代码进行了对比,发现dist目录体积存在很大差异,点进去发现是由于每次打包后生成的js源文件名称都不一致以至历史打包产物全都累积在dist文件夹内。
解决
通过每次build之前将该dist文件夹删除,保证每次build产出的dist文件夹内文件是该次编译的结果,具体方法通过编写编译脚本时,加上该段逻辑
其他
还有就是减少dependencies中的依赖