V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
Sponsored by
LinkedIn
不坐班的神仙工作 · 去任何你想去的地方远程,赚一线城市的工资
2000 个不用出门 Social 的全球远程工作,帮助 V2EX 的小伙伴开启全新的工作方式。
Promoted by LinkedIn
teawithlife
V2EX  ›  问与答

electron+go 实现跨平台是否可行?

  •  
  •   teawithlife · 2020-05-05 11:22:50 +08:00 · 7633 次点击
    这是一个创建于 873 天前的主题,其中的信息可能已经有所发展或是发生改变。

    五一期间花时间学习了一下 electron,基本算是入门吧

    学习的目的是为了解决跨平台桌面应用的开发问题,虽然也算熟悉 Qt,但是相对目前日新月异的新技术来说,有点太“经典”了

    所以考虑用 electron 来做跨平台桌面应用开发,我的想法是拿 electron 做前端,再用 golang 写个后端,负责一些比较底层,或者对运行效率要求比较高,抑或是有保密需求的工作。electron 和 golang 的跨平台都非常容易实现,这样就可以比较完美的实现这个需求。

    一开始我把后端放在服务器上,但是就要求使用者必须要联网才能使用,这个有些麻烦。后来找到 child_process, 于是可以把可执行程序直接放在程序包中,然后 spawn 出后端程序,再进行进程间通讯即可

    目前有几个问题想请教一下各位大佬:

    1. 有大佬尝试过这种组合吗?有没有什么坑?为什么没怎么看到有人这么搞?

    2. 从 electron 启动后端程序,可以放在 app.ready 事件中,但是程序退出时需要自动关闭后端,放在哪个事件比较合适?因为我看到 before-quit, will-quit, quit 这三个事件,都标注了

      Note: On Windows, this event will not be emitted if the app is closed due to a shutdown/restart of the system or a user logout.

      而 window-all-closed 事件,又说

      If the user pressed Cmd + Q, or the developer called app.quit(), Electron will first try to close all the windows and then emit the will-quit event, and in this case the window-all-closed event would not be emitted.

      那么到底放在哪个事件里更合适呢?

    3. 进程间通讯我用 HTTP 接口,一个原因是开发方便,另一个原因是做成 web 也可以通用,但是这里存在一个后端绑定哪个端口的问题,我想了两个方案:

      • 方案一是 electron 先找一个可用端口,然后通过命令行参数的方法传给后端,缺点在于没有找到一个比较好的查找可用端口的方法(看了几个库,都是通过尝试 listen 的方法,这种方法存在一个小概率竞争的可能性)
      • 方案二是后端随机绑定一个端口,然后通过 ipc 的方法,然后把端口号传给前端,这个方案就是担心有点不通用

      不知道还有没有更好的方法?

    33 条回复    2022-06-25 10:27:11 +08:00
    HuHui
        1
    HuHui  
       2020-05-05 11:53:00 +08:00 via Android
    可以再看看 therecipe/qt
    teawithlife
        2
    teawithlife  
    OP
       2020-05-05 12:09:08 +08:00
    @HuHui #1 这个用到了 cgo 吧? cgo 的交叉编译有些麻烦
    SingeeKing
        3
    SingeeKing  
       2020-05-05 12:29:31 +08:00 via iPhone
    我个人不喜欢 electron 的两大原因是体积大和启动慢,这个似乎优化的点在执行效率
    Jirajine
        4
    Jirajine  
       2020-05-05 12:33:05 +08:00 via Android
    有一个 go 的 electron 绑定 https://github.com/asticode/go-astilectron
    但看起来不太成熟。
    至于你说的起一个后台服务然后 IPC 交互我一个自己用的小玩意就是这么搞的,除了有点套娃没发现什么坑,也没考虑那么多直接 quit 完事。端口直接随机一个然后参数传过去。
    这样做好处就是天然支持后端远程运行,不然还不如传统的 native 扩展方便,或者 wasm 也不错。
    pkwenda
        5
    pkwenda  
       2020-05-05 12:39:35 +08:00
    刚想发就被楼上发了,electron 很重的 。
    teawithlife
        6
    teawithlife  
    OP
       2020-05-05 12:41:40 +08:00
    @SingeeKing #3 体积大显得有份量,有工作量(:P ),启动慢这个确实有点不好,不过现在按现在的平均硬件水平,已经勉强可以接受了。主要优化的点在于 js 我不熟(手动狗头)
    teawithlife
        7
    teawithlife  
    OP
       2020-05-05 12:49:48 +08:00
    @Jirajine #4 感谢推荐,这个库看起来还不错,我好好看看
    你随机一个端口,得先 listen 一下,确定端口没被占用,然后才能传给后端吧?我刚才又想了一个方案,前端可以自己 listen 一个端口 A,然后作为参数传给后端,后端随机 listen 一个端口 B,然后通过端口 A 告知前端。这样虽然有点绕,但是可靠性高,而且确保跨平台
    wasm 还是再等等吧,目前还不算成熟
    SingeeKing
        8
    SingeeKing  
       2020-05-05 12:51:49 +08:00
    @teawithlife #6 这不是简单的「有份量」「勉强可以接受」,electron 大的问题在于无论再小的应用都打包了一个环境进去,而一般个人电脑启动最快也要 1-2 秒,这些在一起就真的对 electron 难以有好感
    murmur
        9
    murmur  
       2020-05-05 13:02:49 +08:00
    electron 目前看到比较成功的应用就是 vscode 了,其余的都不是严格的 electron,尤其是国产那堆软件,你看着是 chrome 套壳,背后辣么一大堆 dll 都不知道干啥的
    jason94
        10
    jason94  
       2020-05-05 13:29:15 +08:00
    1. 之前看到这篇 https://wiredcraft.com/blog/high-security-electron-js-application/,也想这么搞,后来感觉有点麻烦,主要就是不好维护。保密这块可以考虑 js 源码 转字节码(目前在几十万用户运行没问题)
    2. before-quit 或 will-quit 。如果窗口关闭之前不做操作的话,可以丢 before-quit 里
    3. 方案一可以用这个库 https://www.npmjs.com/package/portfinder
    ysc3839
        11
    ysc3839  
       2020-05-05 13:42:00 +08:00 via Android
    不然考虑 Golang + Cef ?
    https://github.com/CzarekTomczak/cef2go
    teawithlife
        12
    teawithlife  
    OP
       2020-05-05 13:51:47 +08:00
    @SingeeKing #8 这个话题记得之前 V2 也有几个主题讨论过,我部分赞同你的观点,对于一个有追求的程序员来说,体积大执行慢确实难以忍受,但同时我认为这是为了实现跨平台所要付出的代价,其实 Qt,golang 都是这么一个套路,把整个 runtime 都打包了(当然他们没 electron 那么臃肿)。所以,算是有舍有得吧,就看你以及你的最终用户看重啥了
    teawithlife
        13
    teawithlife  
    OP
       2020-05-05 14:03:54 +08:00
    @jason94 #10 保密是其中一个原因吧,主要还是我作为 crud boy,对前端只停留在 ctrl+c/v 程序员的程度,所以需要把大部分逻辑工作放到后端来实现
    你说的 portfinder 库我看过源码,就是我说的遍历尝试 listen 的方法,这种方法存在一个极小概率的 race condition,可能前端检查的时候,这个端口是可用的,但是等到后端调用时,这个端口已经被其他进程抢先占用了(虽然概率极低,但这确实是可预见的风险)
    teawithlife
        14
    teawithlife  
    OP
       2020-05-05 14:09:04 +08:00   ❤️ 1
    @ysc3839 #11 这个库的 commit 记录,从 2014 年之后的记录,都是在改 README 了,不敢用。。。
    Jirajine
        15
    Jirajine  
       2020-05-05 14:10:24 +08:00 via Android
    @teawithlife 被占了启动服务会绑定失败,js 处理下错误重新随机一个再次启动,这个几率本身也很小,或者用楼上提到的库。
    wasm 毕竟是未来,高性能扩展不用再包装一堆丑陋的 C 接口了。
    teawithlife
        16
    teawithlife  
    OP
       2020-05-05 14:24:10 +08:00
    @Jirajine #15 对哦,启动不起来换个端口再来一遍就行了,我咋把这个办法给忘了
    optional
        17
    optional  
       2020-05-05 14:39:05 +08:00
    wasm 不二选择啊。
    kuyuzhiqi
        18
    kuyuzhiqi  
       2020-05-05 19:03:28 +08:00
    可以的,不难,不同的平台运行时把 go 的运行环境带上,electron 那边启动 go 的服务就行
    teawithlife
        19
    teawithlife  
    OP
       2020-05-05 22:26:38 +08:00
    从下午到晚上都在研究打包的问题,增加一些额外的信息给需要的朋友:

    1. 目前打包的工具有两个 electron-builder 和 electron-packager,用 electron-vue 建立项目时,可以选择其一作为打包工具

    2. electron-builder 功能较全,配置比较麻烦,除了打包之外,可以制作各种安装包,electron-packager 比较简单易用。我测试了用 electron-packager 在 linux 平台生成 linux 和 windows 的可执行程序,如果要生成 windows 平台程序,需要先自行装 wine (据说是为了改图标),也测试了用 electron-builder 在 linux 平台生成 windows 下的可执行程序和安装程序,没有需要自己安装的工具,生成的过程会自动下载(不清楚是否需要 wine,因为已经装过了),其他的平台就没测试了(注意,为了确保下载成功,请科学上网)

    3. 两个工具在打包的时候都可以设置一个 asar 参数,如果为 true,会把整个 app 打包为一个 asar 文件,这样据说可以提高 IO 效率(特别是在 windows 下),由于程序较小,没有明显感觉,但是在复制的时候有明显区别,因为不打包的话,node_modules 这个文件夹得复制半天

    4. 如果启用 asar 文件,在 child_process 里面的函数,exec, fork, spawn 全部都不能用,只能用 execFile,如果确实想用,可以将需要执行的文件,从 asar 文件中复制出来

    5. 我把后端程序放到了 static 文件夹中,发现打包之后,`dist/static/`文件夹虽然已经有了程序,但是文件属性从 755 变成 644 了,原因是 electron-vue 的打包脚本中,复制 static 文件夹时,用的是 copy-webpack-plugin,它这个 issue 至今未解决。我最后没办法,直接修改 build.js 文件,复制完成之后,手动执行一次`chmod +x`,把权限改回来
    qwe121002
        20
    qwe121002  
       2020-05-06 02:23:01 +08:00 via Android
    有人会做 h5 跳转转账的付款模式吗
    teawithlife
        21
    teawithlife  
    OP
       2020-05-06 07:06:55 +08:00
    @qwe121002 #20 提问的话,最好单独发一个主题,尽量描述清楚你的目的和已经做了哪些尝试,这样会有更多的人帮助你
    buffzty
        22
    buffzty  
       2020-05-06 14:06:21 +08:00
    我的想法跟你一样. 桌面软件用 electron+tsx 做前端展示. 大部分功能用 node 写, 再用 go 起一个 http 服务器 做一些本来需要用 c 完成的功能.
    teawithlife
        23
    teawithlife  
    OP
       2020-05-06 14:16:58 +08:00
    @buffzty #22 对的,就是这么个思路。那你在实际使用过程中,有碰到什么问题吗?
    buffzty
        24
    buffzty  
       2020-05-06 15:34:09 +08:00
    @teawithlife 还没写过 pc 端项目,我们现在全部都是 web. 前端 tsx, 后端 go .我觉得套个 electron 应该问题不大
    teawithlife
        25
    teawithlife  
    OP
       2020-05-06 16:00:50 +08:00
    @buffzty #24 作为业余前端,我的操作是找个 vue+element-ui 模板改一改,搞定显示的内容,所有的逻辑放到后端来实现
    qwe121002
        26
    qwe121002  
       2020-05-08 00:35:35 +08:00 via Android
    @qwe121002
    @teawithlife 好的,谢谢
    zkdfbb
        27
    zkdfbb  
       2020-07-17 00:05:37 +08:00
    @teawithlife 这两天也跑了个 demo,发现了一个很奇怪的问题,使用 asar: true 打包时,child_process 里面的函数,exec, fork, spawn 是可以用的,但是遇到一个很奇怪的问题,使用 go 编译出来一个后台程序,然后通过 electron 来启动它。无论是用 spawn 还是 exec,打包出来的程序在 mac 平台下是可以正常启动的,但是在 windows 下面怎么都启动不了,一启动就退出,exit code 是 1,问题是这个 go 编译出来的程序单独打开是正常的,说明不是程序的问题,而且用一段最简单的程序,比如直接 time.Sleep 一段时间,用 spawn 启动也是马上就退出了。但是用 spawn 启动一个其他的程序,比如 dir,python -m http.server 又都是正常的。崩溃了。。。
    teawithlife
        28
    teawithlife  
    OP
       2020-07-17 09:00:28 +08:00
    @zkdfbb #27 exec, fork, spawn 在启用 asar 时不能使用,我是看文档里面这么写的,倒确实没试过,也可能是操作系统相关。
    你在 windows 平台用 execFile 可以启动这个 go 程序吗?
    进程的启动,不同操作系统的实现区别会比较大,可能有些情况不太好兼容
    zkdfbb
        29
    zkdfbb  
       2020-07-17 10:32:11 +08:00
    @teawithlife execFile 也试过了,就是很奇怪,其他的比如 python -m http.server 都 OK,偏偏 go 程序就不行
    AndyAO
        30
    AndyAO  
       2021-01-09 08:51:39 +08:00
    思源笔记是这种结构
    前端 JavaScript(Electron),后端 Go
    dosgo
        31
    dosgo  
       2021-09-13 23:16:14 +08:00
    挑来跳去,还是 electron 好用,fyne 实在是丑,然后好多复杂功能不好弄,而且官方理念我就看的无语。。。跨平台 GUI 这套目前 electron 最优,毕竟跨平台的 GUI 库投入太大很少公司开发。。。
    lizhenda
        32
    lizhenda  
       94 天前
    思路不错,准备这么干,但有个疑问。我直接已 nodejs 来写后台服务和用 Go 来写有什么优劣呢。感觉 nodejs 直接在 electron 的主进程启动更加方便,但 go 的话性能更好,可以直接放在云上,不止是个本地服务了。纠结。
    teawithlife
        33
    teawithlife  
    OP
       93 天前
    @lizhenda #32 我个人是熟悉 go ,前端只是半吊子,所以选择用 go ,如果你熟悉 js 的话,用 nodejs 也是可以的,至于放到云上运行的需求,套个 docker 就可以了,还有性能问题,不必过早考虑,先把业务跑起来再说,等日活上来了,再考虑优化也不迟
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   4725 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 54ms · UTC 03:05 · PVG 11:05 · LAX 20:05 · JFK 23:05
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.