2019年 Electron7 + Vue 项目实战总结 —— 那些年挖的坑还得自己来填

前言 这篇文章不是Electron的教程, 而是作者在去年做的一个大型项目的总结, 我会从立项到技术选型到开发一一道来, 如果大家能在看作者自己给自己挖坑的过程中有所收获, 那就再好不过了。 使用技术 这里先罗列一下用到的主要技术,其中也有一部分在发现问题后放弃的 Electron5 - Electron7(没错, 从开始立项时的Electron5的版本, 到最后的Electron7, 鬼知道经历了什么) Vue.js sqlite3 sequelize(ORM框架,搭配数据库使用可以不用写sql语句) vue-cli-plugin-electron-builder(使用这个插件来整合vue-cli和electron) ant-design-vue element-ui pdf.js electron-edge-js(使用这个包来调用dll) log4js(用来记log) amqplib(rabbitmq的node实现) grpc 项目背景 因为是公司的商业产品,具体名字就不写了,这个系统包括服务端,PC客户端和iPad端。这次的Electron项目是对该产品的PC客户端的重构,原客户端是用WPF技术完成的,因为公司的战略需要将以前老的WPF技术写的所有软件用Electorn重构,所以就有了这个项目。开发人员加上作者一共有三位,只有作者是前端,其余两位都是.net工程师,负责维护原项目的,开始现学Electron。作者以前也没完整开发过Electron项目,就在这样的情况下,项目启动了。 项目功能 因为公司的这个产品是针对酒店行业的,所以这个PC客户端的主要功能包括对酒店客人入住、离店、消费单据的签字、打印,包括支付以及对接服务端对客人住店对处理等等。 前期调研 因为只有作者一个人是前端,所以建项目这个事情只能交给本人来做了。 前端开发的三大框架当然得用上,虽然我挺想用React的,但是公司的技术栈是Vue,考虑到成本当然选择了Vue。 当时立项的时候Electron稳定版更新到了5.x.x版本,所以直接使用了Electron5。 接下了就是就是结合Vue和Electron,公司以前有一个老项目用的是vue-electron,但是这个库的作者已经好久没更新了,而且集成的还是vue-cli 2的版本,所以综合考虑了一下,没有使用以前的方案。采用了vue-cli-plugin-electron-builder这个vue插件来整合vue和electron,这里推荐大家看下这篇文章手把手教你使用Electron5+vue-cli3开发跨平台桌面应用,讲的很详细。 接下来是数据库的选择,其实这个项目对数据库对要求很少,基本上就是存一下配置文件和最多几百个PDF文件,当时也考虑过直接用文件形式存储,但在和老大聊过之后,谈到了以后功能的扩展问题,还是决定使用数据库。然后是在像sqlite3这样需要build的native库,还是一些不需要build进electron的JSON格式的轻量数据库之间进行选择。还是考虑到用户可能有比较多的PDF的数据的情况下,选择了sqlite。然后又在老大的要求下加入了ORM框架Sequelize来配合sqlite3使用。 我们开发组很早就想要引进TypeScript,加上组内有很多写C#的.net工程师,学习成本还是比较低的,虽然Vue用TS写有些别扭,但是我还是趁这次机会和老大提出了引入TS的想法。结果老大还是想要等到用TS重写的Vue3.0发布后再引入(已经2020年了vue3.0还没有发布),所以TS没能用到项目上来。 正式开发 项目结构 整个项目的目录结构基本上是按照vue的结构来建的,但是在开发到后期发现存在一些问题,关于项目目录如何建这个问题我会单独再写一篇文章来分享自己的看法,这里就暂且不提了。 Native编译问题 使用Electron开发之后,我发现问题最难解决的就是Native包的编译问题,凡是需要调用其他语言写的工具都有编译这一步,本项目需要编译的当然是Sqlite3了。 走过了数不尽的弯路之后,我先来提出最后的成功解决方案,在npm的后置钩子postinstall中运行这条命令electron-builder install-app-deps,这条命令的意思就是安装编译相关的依赖。 先来讲讲第一个坑,其实在使用vue-cli-plugin-electron-builder生成项目后,这个命令是默认就在postinsatll里面的,但是我一开始没有编译成功的原因就是因为我的electron不是从npm官方源下载的,而是从公司自己的npm源,公司的npm源是连接的淘宝源结果造成了这个问题。所以无论下任何npm包一定一定要从npm官方源下载,有些资源太慢就挂代理(这个是程序员必备技能了吧),即使是用淘宝源也千万不要用cnpm命令,cnpm真的是坑太多了。 还是splite3的问题,我在Mac上可以跑起来了。但是当放到windows10上就又出问题了,看报错是node-gyp在编译过程中出现的问题。最后发现在windows上使用sqlite3和electron得配置以下环境。 python2.7(有的同事电脑安装python3.5会报错) windows-build-tools(这个非常非常重要,如果你的电脑安装了VS的话,可能不需要这个东西,但是如果没有安装VS,务必安装这个包,它会配置node-gyp在编译c++等语言的代码时必须的环境,非常重要) 数据库问题 sqlite3官方的api不太好用,所以我封装了一套Promise格式的api,需要的可以参考我以前的文章Electron中sqlite3的安装以及Promise形式API的封装。 在这个项目中我们使用了Sequelize,这是一个ORM框架,配合sqlite3使用可以让我们不用写sql语句,而是通过对象的形式来使用数据库,但是当配合vue脚手架使用的时候会出现问题,控制台又报了sqlite3的错误。这个问题是关于数据库这块我处理时间最长的一个,最后借助Goole搜索引擎,在某个外国作者的个人博客上找到了解决方法,在vue.config.js里这样配置 configureWebpack: { externals: { sequelize: "require('sequelize')", sqlite3: "require('sqlite3')" } } 使用electronBuilder打包的话同样需要配置 pluginOptions: { electronBuilder: { externals: ['sequelize'] } } 如果是直接用的webpack,把externals属性配置到配置文件里就可以了。 UI框架的选择 一开始这个项目使用的是ant-design-vue,在UI基本完成之后的某一天,我和一个做混合开发也在用ant-design-vue的同事互相吐槽了一下这个UI库里面table组件(确实操作反人类啊)。没想到这事被旁边的老大关注了,在经过8个人的UI库选型讨论大会之后,最终决定使用element-ui,而且没有彻底完成的项目都要使用element-ui重写。我。。。。。。。心里苦啊。 其实就我作为前端对角度而言,使用element-ui没有问题,但是重写现有的项目UI就真的没有必要了,毕竟我们前端使用这些库的组件的时候都是按需引入的,而且其实很多时候都需要前端来调整组件的样式。老大可能是从前端组整体的角度来看希望能使用统一的UI库,总之,我之后又把所有ant-design-vue的组件全部替换成element-ui的组件。 PDF的展示 我们这个项目最主要的功能之一就是对各种单据进行签字,所以如何展示单据并签字就要用到pdf.js了,这部分功能是由另一位同事调研了半个月之后负责开发的,这位同事是.net开发,对前端不太熟悉,最后导致这部分的功能成了我们项目开发中最大的难点。 pdf.js是将pdf文档通过canvas显示在页面上,然后我们再将应用窗口推到wacom的设备上让用户签字,然后问题就产生了。 签字字迹不圆润, 有断点的存在。 pdf展示模糊。 如何无损缩放。 笔迹和pdf合成后变模糊。 pdf文档切换闪烁问题。 下面是填坑的过程: 参考了一些开源项目对笔迹的点的算法处理,绘制出了比较圆润的曲线。 参考pdf.js官方Demo,初始化时渲染高精度pdf 使用pdf.js读取高精度倍数的pdf绘制到canvas上, 而字迹我则是通过Path2D来记录绘制轨迹然后重绘来实现无损的缩放。 我们是通过公司同事使用C#来写的一个dll来将pdf和字迹的canvas合成的,这个最后通过给这个dll传高精度的pdf和字迹实现比较清晰的合成。 参考pdf.js官方Demo,使用两个canvas交替显示,消除闪烁现象。 虽然问题看似解决了,但最后我们发现实际效果还是差强人意,在最终有调整了半个月之后,老大看了我们的最终演示,最后决定签字部分直接使用原来的exe程序来实现,我们的应用仅展示pdf文件。 虽然这部分工作并不是我负责的,但是我也参与其中改了不少东西,所以到最后换方案还是比较难受的,就好像自己考试考砸了一样。 打印 pdf的打印真的是让人奔溃,因为我们项目对打印对要求还是比较高的,比如说可以配置打印机的纸张来源、纸张大小、指定打印机静默打印等等。而electron的打印api不能完全实现这些功能。所以一开始这个打印功能到底是要在electron上用js做还是调用c#写的dll或exe,我就进行过研究,因为这是个重构项目,这部分功能有以前写好的c#代码可以用,调用dll应该是比较方便的。但是。。,老大想要使用electron自带的api,他本人尽量想要少使用dll,哪怕功能得削减。 既然这样,那就决定用electron的打印api了,但是刚成功打出两张之后就发现了一个问题。electron的打印api有个静默打印的设置,设置后不会弹出系统的打印对话框,但是如果我开了这个设置,那么指定的打印机就会失效,系统会使用默认的打印机打印。 又是Google找问题时间,最后我到electron的github主页上看到了别人提的issue,作者回复这是个bug,而且由于底层代码问题只能在electron7中才能修复。心累啊,我建项目的时候才electron5,现在就要用electron7了?但是没办法,这个时候的稳定版是electron6,我只好在npm下了electron7.0.0-beta.3,这是我用的最长的一个npm版本。 这之后还有不少问题,比如说打印出来多了页边距,获取不到实际打印结果,打印次数多直接奔溃之类的。最后虽然磕磕绊绊的完成了打印的功能,但是如果有人想要在electron上打印的话,如果需求比较复杂,强烈建议不要用electron的打印api,尽早换别的方案,这个坑就不要再踩了。 错误日志记录 这部分用了log4.js这个库,这个功能还是比较顺利的,照着官方文档基本上没有什么坑。 与IPAD通信 我们一般是将文档推到wacom上让客人签字,不过也有些客户想用IPAD,所以后来就开发了一个ios应用,用来接收pc端推过去的pdf文档,然后在IPAD上签字,完成后在推送到pc端。 这个功能在老项目上是用rabbitmq来通信的,使用electron重构的新项目我本来是想要看看能不能使用grpc来实现,结果在大概看了官方文档也用node写了个简单demo之后,发现在electron上不能使用,因为会编译失败。在查阅来一些资料后,我认为是electron版本太新了,但是因为低版本的打印api有bug,又不能降版本,所以只好改用rabbitmq,和老版本保持一致的方案。rabbitmq的node实现是amqplib,使用amqplib顺利完成了这个功能。 小结 项目暂且就记录到这里吧,总而言之,在这个项目的开发中我学到了很多,也遇到了很多问题。看到这篇文章的人如果对于我踩的坑有更好的处理方式,欢迎留言指教。

本文章由javascript技术分享原创和收集

发表评论 (审核通过后显示评论):