electron踩坑
electron开发起来确实有几点比较坑的地方,在这里说一下。
打包工具
首先我是用electron+vue开发的,那么打包工具有两个,一个是用vue/cli,一个是用vite。前期开发我一直用vue-cli-plugin-electron-builder来打包的,缺点有两个,一个是作者近一年都没有更新了,虽然半年前有两个beta版本,导致对vue/cli@5的支持比较差,只能用那个beta版本的,vue/cli4用的是webpack4,有些新的插件不支持了,需要webpack5,所以这个打包工具最后还是被我舍弃了。
之后用的vite,正好vite3也在这一个月内发布了,所以就决定用vite。vite打包工具非常的快,而且只支持模块化的写法,对于个人开发来说非常的合适吧。这个没有第三方工具,而是用的一个模版做的——vite-electron-builder。这个模版非常的重要,可以说没有这个模板就没有我的项目的重构,因为我对打包工具这块不熟,这种模板能够快速直接上手,只需要你专注于渲染代码的建构。这个模板里面包含了挺多的,还包括CI交付,但这块我也不会,而且我也不想用github,因为网络实在是太差了,虽然我也有节点,但是我也不想用。如果是新的项目,建议就从这个模板开始入手,他这个模板用的依赖库也都是最新的,不像你百度出来的,用的还是过时好久的electron-vue,真男人就应该用vue3和electron的最新版,走在时代的前列腺前。
还有建议项目包管理工具建议用yarn,又快又稳,我换到pnpm快是快了,但是感觉没有那么稳定,打包的时候甚至出错了,说缺少某个模块。众所周知,pnpm用了软链接,所以electron-builder没有识别出来,还得是这篇文章救我狗命,需要建立一个.npmrc,把node-link改一下,这样子会不会失去pnpm的优点我不知道,但我只知道我不这样子根本打包不成功。所以换工具的时候要三思啊,成熟的yarn错不了的,呜呜呜。
项目结构
项目结构需要在前期就分好,这点其实也是学的vite-electron-builder,因为electron分为主进程和渲染进程,所以就需要两个文件夹了,又因为开启了一些安全选项,所以又需要一个预加载脚本,总共就三个文件夹,这样子分开来比较清晰,不像我以前写在一坨,渲染进程和主进程共用一个文件夹,找半天都找不到在哪里,每次都要找半天。
有些静态资源,可以放在主进程文件夹里面,vite.config.js可以设置publicDir,这样子打包的时候就会打包过去,因为打包后的目录还是以主进程为主,直接放在主进程文件夹里面方便直接读取,比如我有个 示例.md 需要读取,这种肯定不是渲染进程直接import进来的,肯定是通过Node.js的fs读取出来的。
安全问题
这个其实是开发electron最头疼的问题,至少有一半的问题都来自于此。electron甚至单独开了一个界面来解释这个问题:安全 | Electron (electronjs.org)
由于我前期特别遵守官方文档手册,而且我也非常注重安全问题,所以我就认真遵守这些规范,但是导致后续开发一系列的问题。
众所周知,electron分为主进程和渲染进程,主进程包括electron本身,能够使用Node.js,能够调用操作系统的API,能够创建和管理渲染进程。比如应用的原生菜单栏就是electron本身的一部分。渲染进程呢就是类似咱们网页开发的那部分,比如用vue框架的那部分,显示界面,控制用户交互逻辑,操作DOM的这部分,甚至可以说,你直接拿纯网页开发的代码直接当做渲染进程,没有问题(当然可能有部分需要调整)。最重要的是渲染进程支持Node.js操作,这对网页开发来说可是降维度的打击,因为网页是在chromium提供的沙盒里面操作的,对于本地文件的操作是非常受限的,如果在渲染进程里面可以使用Node.js,那还不爽!这就是electron能够快速壮大的原因之一。
但是!真的是成也Node.js,败也Node.js,那为什么浏览器不提供Node.js呢?是因为谷歌没能力么?就是因为安全问题,容易引发巨大的漏洞,所以从electron5开始,就默认nodeintegration这个属性为false,这个其实是可以理解的,比如攻击者可以在渲染进程中执行恶意脚本,从而远程执行访问你本地的文件,这确实非常危险!
但是关闭了这个,那渲染进程想要使用Node.js的API那怎么办呢?一个就是预加载脚本,一个就是通过主进程之间通信来解决。
在使用预加载脚本之前,建议开启上下文隔离,这能让我们的预加载脚本和electron的内部逻辑运行在渲染进程之外的另一个独立的上下文环境。但是开启了上下文隔离,并不意味着我们所做的一切操作都是安全的,比如我们直接暴露fs模块的某个功能,不做任何过滤,也是存在一定的安全隐患,但是这条我并没有遵守,因为为预加载的每个方法都写过滤的方法,很麻烦,我就直接暴露一些公共方法,但又失去了安全的意义,可以说是既丢失了安全,又丢失了写代码的便利性,双输。很麻,但我也无所谓了,因为我做的本身就是一个本地软件,一切安全都不遵守都没有问题!!!
但是走上了安全这条黑路,就得一路走到黑,还有开启webSecurity,这会禁止同源策略,意味着我开启了这个之后,连TM网络请求都发不出去!就很麻,麻中麻。那么网络请求发不出去该怎么办呢?一种方式就是通过上述的预加载脚本,提前写好一段发送的函数,然后你在渲染进程就可以调用这个函数,往里面传入url等参数,他执行完返回给你结果。那么我就是这么做的,其实这样子也还好,相当于你本来要在渲染进程里面写的部分,挪到预加载脚本里面,问题不是很大。
还有一种就是之前讲的,主进程之间通信来解决。渲染进程和主进程之间可以互相通信。通过IPC可以通信,乍一听感觉很高大上,其实就是主进程里面通过ipcMain.on监听某个参数,然后渲染进程通过ipcRender.send发送某个参数,但这样子只能渲染进程单方向发给主进程,如果想要返回来,一种是异步,一种是同步,异步就是在主进程ipcMain.on执行完之后,再调用ipcMain.send发送回来,那么对应渲染进程也有个ipcRender.on监听函数,所以想要异步执行,主进程和渲染进程分别都需要发送和监听函数,这样子折腾一下,就要写四个函数!!!!原本一个网络请求只要随便fetch、axios一下,现在你要把这部分代码挪到主进程里面,并编写这四个函数!!虽然这四个函数可以抽取出来单独做一个小模块,但还是要调用四遍,麻了真的。同步的方法就稍微简单一点,主进程里面的ipcMain.on用同步的方法返回,渲染进程用ipcRender.sendSync发送,之后会同步收到传回来的值,这也是我经常用的一个方法。但是缺点就是:万一那个方法需要运行很久,就会阻塞整个进程,也就是渲染进程和卡住,没反应了。只能传送一些比较简单的。咱就说网络请求吧,这肯定不能用同步方法是吧,诶,但是你用异步方法,写四个调用方法就先不说了,这个异步只能过通过回调函数的方法来实现写后面的函数,那些promise方法和await这些语法糖你都享受不到了啊,太麻瓜了,简直是简直了!
而且最最最蛋疼的问题是什么呢?ipc只能够传文本!
进程之间的通信过程中,发送的json对象都会被序列化和反序列化,所以传递的时候需要注意其方法和原型链上的数据是不会被传递的。
我靠,这个真的是太龙鸣了,我tm一开始不知道,我写的有一部分,是把网络图片上传到wordpress,我就用这个方法,我把有个方法给传给了ipc,后来发现怎么都不能够成功,怎么都不对,我单独在另一个测试环境中,一模一样的代码都能实现,就是执行的地方不同嘛,我在渲染进程里面都打印那些对象看,都没问题啊,搞了好久,后来打印了一下方法(谁tm会想到打印方法?),好家伙,发现坏了,tmd方法传过去就是文本,wdnmd,心态崩了,而且JSON对象也被序列化,就很麻,有种我好好的对象怎么变成纸片人了的生草感。反正这个IPC通信怎么不爽怎么来,最终我把大部分操作写在了预加载脚本里面,只有渲染进程获取主进程的一些环境参数和主进程单方面传给渲染进程,比如菜单栏改变了主题之后,发送消息给渲染进程换皮肤。
好家伙,本来觉得这样子差不多了,结果我electron一更新20,就发现炸锅了,主要我还没怀疑到更新的问题,不知道是缓存的问题还是啥的,我把electron回退回去发现还是有问题,反正就是尝试了好几个小时,代码文件都一个一个看过来,愣是没找出问题,干到晚上一点也没找到,夜不能眠,第二天起来继续找,才发现这个问题。原来是**electron20默认开启了sandbox!!!**我之前弄安全的时候,没弄过这个参数,貌似没见过,好家伙,这个参数绝了,直接进程沙盒化了,预加载脚本大大受限,只能载入 Electron 和 Node 内置模块的一个子集,好家伙,我真的蚌埠住了,path、fs这些都不能用了!!!!你妈的,这一手默认化真的把我气到了,我找问题找半天!!!而且你直接砍掉预加载脚本这么多功能,只剩下几个残废的,有🔨用!!你那个IPC跟个残废一样,能用嘛?气得我孙笑川上身了。我也不管什么垃圾安全化了,直接把sandbox给关了,结果官方说法你看看。
尽管已经有一些成功案例(例如 Beaker 浏览器),但在 Electron 中渲染不受信任的内容仍有未知的风险。 我们的目标是尽可能达到与 Chrome 中沙盒化的内容一样的安全性,但由于一些现实因素还没法做到:
- 我们不像 Chromium 团队那样在产品安全方面有专属的资源与专业知识。 虽然已经尽可能地继承 Chromium 中的一切,并且尽快响应安全问题,但缺少 Chromium 可调动的那些资源,我们做不到和它一样安全。
- Chrome 的一些安全特性(例如安全浏览和证书透明度)依赖于中心化授权和专属服务器,这些都超出了 Electron 项目的目标。 因此我们在 Electron 中禁用了它们,同时也损失了它们带来的安全性。
- Chromium 只有一个,但基于 Electron 构建的应用却成千上万,并且千差万别。 这些差异带来了太多的可能性,很难在各种特殊的应用场景下都保证平台的安全。
- 我们没法向终端用户直接推送安全更新,只能靠应用供应商更新依赖的 Electron 版本,来让更新覆盖到用户。
虽然我们会尽可能将 Chromium 的安全修复应用到老版本的 Electron 中,但没法保证每一个修复都能移植过去。 为了保证安全,最好的办法还是始终使用最新的稳定版 Electron。
他这个什么意思呢,就是我们不知道这个渲染风险是什么样的,但是为了甩锅,我们默认开启了。这样子我electron默认都是安全的,你们把这些关了,是你们自己主动不安全的啊,出了事儿别怪我们啊,而且我们没钱没精力,已经尽力了。
但我想说,如果全都开启了安全,我还用你们electron开发个锤子,我直接原生开发他不香吗?可以说electron就是因为Node.js才茁壮成长的,结果现在努力向着chrome靠拢,默认不给开发者足够的权限开发,把Node.js砍来砍去,我只能👍。
所以安全这块到底怎么拿捏呢?如果你只是本地工具开发,并且有很强的文件管理交互,那么就别tm管安全了,扎不多得了。如果稍微有点网络请求,那么可以和我一样,做点安全的事情,但是可以取舍。如果是有很多的网络请求,那建议浏览器原生开发,用什么垃圾electron。如果是既有大量本地操作又要大量网络请求,那就用原生开发,用什么垃圾electron。你看看那个bilibili,放着好好的UWP不优化,又出了一个electron套壳网页版本,评论里面10条里面有5条是骂垃圾electron,体积又大,性能又很一般,活该被骂,不管是bilibili还是electron。
最后
electron好用吗?对于开发者来说却是方便,网页代码直接拿过来一套,再添加点Node.js,相当于能够对浏览器本身做出一些调整了,但是你要是没有这个需求,还是老老实实网页开发好了,还能多端适应,手机也能用,这electron虽然多平台,但他哪有移动端,而且编译还要相同的平台才能编译,虽然用github的actions能够多平台编译,但。
但是electron也有非常明显的缺点,安全这点我已经阐述过了,最大的诟病其实是内置chromium内核,如果electron框架能够直接集成到操作系统里面,就和.net一样(我不知道.net是哪样子的,我一直是觉得应该可能差不多),那将绝杀,可惜换不得。我现在打包完的应用有80MB,真的算大了,我还记得我一开始刚打包,什么东西都没有的时候,那时候已经50MB+,是真的大好吧。解压完之后,整个文件夹甚至有好几百M,真的夸张,打开又占内存空间。所以有没有一个这样子的东西,就是大家共享他的内核,不管开多少个应用,就只占他那个应用的内存,没错,他就是浏览器!
electron真的是有点矛盾的,因为单纯网页类的应用其实不需要使用electron,用浏览器会更好,用electron能增加的优点就是能够离线使用,毕竟网页都是写在你本地了,但是换来的代价就是急剧增加空间。
你要说要是操作系统能够内置electron框架,相当于就是浏览器+Node.js开发,那开发起来确实香,但鉴于现在越来越严苛的安全隐患,Node.js被极力打压,各种骚操作弄来弄去目的就是不让接触本地系统,把你隔离起来,这样子反过来看不就是剩下一个纯浏览器的功能了?
所以electron的前途真的是迷茫,现如今人人都唾弃electron,连我也加入了这一员,我现在找开源软件,碰到是electron写的,我都绕道远离,是真的不行,那些原生开发的,安装包就几M,真的是轻便。除非是特别优质的,基本上没有可替代性的,比如我现在正在用的typora,功能基本上都有,缺点对我来说就是性能不够,写长了就不行,我估计是渲染也是实时渲染的,每次渲染都是重新再次渲染,所以写多了会卡。还有vscode,当然这个应该排除在外,因为他大量魔改,而且微软有钱有精力去深层优化,所以不是问题,但是vscode写项目大起来,也会非常占用空间,飙升。
当然electron也不是没有优点,除了开发起来方便快捷外,最重要就是很适合个人或者小团队写跨平台的应用。我觉的这是最大的优点。当然,我写的应用并没有跨平台,只在windows平台。什么,你问我为什么骂的这么凶,自己却在用?当然是和众多开源的electron一样,用来学习练手😊😊😊





