V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
teawithlife
V2EX  ›  问与答

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

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

    五一期间花时间学习了一下 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 的方法,然后把端口号传给前端,这个方案就是担心有点不通用

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

    34 条回复    2023-11-15 12:25:02 +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  
       2022-06-23 14:52:30 +08:00
    思路不错,准备这么干,但有个疑问。我直接已 nodejs 来写后台服务和用 Go 来写有什么优劣呢。感觉 nodejs 直接在 electron 的主进程启动更加方便,但 go 的话性能更好,可以直接放在云上,不止是个本地服务了。纠结。
    teawithlife
        33
    teawithlife  
    OP
       2022-06-25 10:27:11 +08:00
    @lizhenda #32 我个人是熟悉 go ,前端只是半吊子,所以选择用 go ,如果你熟悉 js 的话,用 nodejs 也是可以的,至于放到云上运行的需求,套个 docker 就可以了,还有性能问题,不必过早考虑,先把业务跑起来再说,等日活上来了,再考虑优化也不迟
    qqshenhan
        34
    qqshenhan  
       134 天前
    @teawithlife 楼主觉得 wails 怎么样
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2618 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 15:52 · PVG 23:52 · LAX 08:52 · JFK 11:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.