当前位置: 首页 > 后端技术 > Node.js

浅谈基于Web的跨平台桌面应用开发

时间:2023-04-03 14:21:48 Node.js

作者:京东物流王泽智近年来,跨平台跨终端一直是热门话题。一次编写,到处运行一直是我们开发人员所期望的。跨平台解决方案的优势是显而易见的。对于开发者来说,可以实现一次性开发和多端复用,一套代码可以运行在不同的设备上,可以大大降低研发成本,提升产品性能。实现快速验证、快速上线。现在有很多优秀的跨终端、跨平台的技术方案。移动端:ReactNative、Flutter、Weex;小程序端:太郎、Uniapp;桌面端:NW.js、Electron、Flutterfordesktop、Tauri、Wails,今天我们来说说桌面应用开发。[]()1什么是跨平台,泛指编程语言、软件或硬件设备可以运行在具有多种操作系统或不同硬件架构的计算机上。总体来说有几种场景,即跨设备平台(比如PC和手机),跨操作系统(Android,IOSformobile,Windows,macOS,LinuxforPC),国内小程序(微信,京东,百度),支付宝,字节跳动等)[]()2跨平台技术方案跨平台编程并不是一件容易的事,因为有很多细小而复杂的差异需要仔细考虑。现在我们有了成熟的跨平台技术方案,可以降低开发者的开发成本和跨平台的难度。NW.jsElectronFlutterforDesktopTauriWails[]()2.1NW.js官网:https://nwjs.io/GitHub:https://github.com/nwjs/nw.js语言:Nodejs+任意前端框架代表项目:微信小程序IDE,京东小程序IDENW.js(node-webkit)是一个基于Chromium和Node.js的Web运行环境,可以直接调用DOM中的Node.js模块,使用任何现有的Web技术来实现编写本机应用程序。[]()2.2Electron官网:https://www.electronjs.org/GitHub:https://github.com/electron/electron语言:Nodejs+任意前端框架代表项目:VSCode、百度小程序IDE,北京ME,脸书留言,Electron的前身叫做Atom-Shell,本来是GitHub发布开源编辑器Atom时发布的副产品,后来这个副产品的影响力远远超过了Atom本身,所以它更名为一个独立的项目,也就是现在的Electron。Electron的本质很简单,就是Chromium+Node.js的组合,两者之间的通信是通过IPC。类似于NW.js,表面上看起来很相似,但是两个项目有着根本的区别,使得Electron和NW.js是两个完全不同的产品。申请入口不同。NW.js的主要入口是HTML,而Electron的主要入口是JavaScript,可操作性更强。节点集成方式不同。NW.js中,网页中的Node需要通过给Chromium打补丁的方式来实现,而Electron使用各平台的消息循环集成了libuv循环,避免了直接在Chromium上修改函数,两者差距明显支持的功能数量。Electron拥有庞大的社区和社区活跃度,拥有大量成熟的npm功能模块。[]()2.3Tauri官网:https://tauri.app/GitHub:https://github.com/tauri-apps/tauri语言:Rust+任意前端框架代表项目:仅几个开源应用Tauri是2021JavaScript明星项目(https://risingstars.js.org/2021/zh#section-all)最受欢迎项目...)满意度和关注度排名第一,感谢Vite、esbuild、swc、Rome等工具的大火,让基于Go和Rust的高效构建工具进入爆发期。再加上Bundleless的构建体验,Rust和Go成为了前端开发者的另一扇门。由于Tauri的Rust背景,加上构建产品小,内存占用低,值得长期关注。题外话:Rust的前景还是很不错的。比如Linux内核采用Rust,Deno采用Rust,微软拥抱Rust,fuchsia的Rust代码占比超过50%,苹果底层all-inrust,stackoverflow连续6年成为最流行的语言.只是学习门槛有点高[]()2.4Wails官网:https://wails.io/GitHub:https://github.com/wailsapp/wails语言:Go+任意前端框架代表项目:NoWails是一个允许您使用Go和Web技术编写桌面应用程序的项目。将其视为Go的快速轻量级Electron替代品。您可以使用Go的灵活性和强大功能以及丰富的现代前端轻松构建应用程序。与Tauri类似,Windows上使用的是Webview2。[]()2.5FlutterforDesktop官网:https://flutter.dev/multi-platform/desktopGitHub:https://github.com/flutter/flutter语言:Dart代表项目:NoFlutterisskiafromtherendering原理自绘性能优于Electron,但需要考虑稳定性和生态性。[]()3跨平台架构原理本期我们讨论使用最多的Electron和比较有前途的Tauri架构原理。通过Web技术编写UI,赋予底层能力,实现跨平台的能力和体验。[]()3.1Chromium多进程架构现代网页浏览器大多采用多进程架构,主要包括浏览器主进程、渲染进程、插件进程、网络进程、GPU进程,Chromium也是一样。IPC=Inter-ProcessCommunication进程间通信Chromium是Chrome和浏览器的开源版本。主进程的RenderProcessHost和渲染进程的RenderProcess负责处理IPC事件渲染进程的RenderView。这里页面的显示是基于Webkit排版出来的ResourceDispatcher来处理资源请求的。当页面需要请求资源时,通过ResourceDispather创建请求ID并转发给IPC,在Browser进程中处理后返回[]()3.2Electron架构在各个进程中暴露了NativeAPI(MainNativeAPI,RendererNativeAPI)引入Node.jsWeb技术实现UI[]()3.3Electron进程模型Electron继承Chromium的多进程架构使得该框架在架构上与现代Web浏览器非常相似。为什么要使用多进程架构?Web浏览器是一个极其复杂的应用程序。除了显示Web内容的主要能力外,它们还有许多次要职责,例如:管理大量窗口(或选项卡)和加载第三方扩展。在早期,浏览器通常使用单个进程来处理这些功能。虽然这种模式可以减少打开每个选项卡的开销,但这也意味着网站崩溃或变得无响应会影响整个浏览器。为了解决这个问题,Chrome团队决定让每个选项卡在自己的进程中呈现,从而限制一个网页上的不良或恶意代码可能对整个应用程序造成的损害。然后使用单个浏览器进程来控制这些标签页进程,以及整个应用程序的生命周期。Electron也是如此。作为应用开发者,它控制着两类进程,主进程和渲染进程。主进程负责应用窗口管理,应用生命周期,原生API等渲染进程负责UI显示。对于这部分,我们可以选择任何前端框架Vue、React、Svelte、Preact[]()3.4Tauri进程模型Tauri采用了与Electron和大多数现代Web浏览器一样的多进程架构。包括主进程和WebView进程,一个主进程管理一个或多个WebView进程。[]()3.5进程间通信Electron的进程通信renderer进程->主进程(单向)ipcRenderer.sendAPI发送消息,然后使用ipcMain.onAPI接收(双向)ipcRenderer.invoke和ipcMain.handle一起使用Complete[]()4Combat-NavigationLauncher为了比较Electron和Tauri的区别,用Electron和Tauri做了一个简单的应用,navigationlauncher,类似Alfred和Spotlight。[]()4.1功能描述首先描述一下本应用的功能。启动应用程序后,使用快捷键Ctrl/Command+K调出应用程序界面——一个输入框,在输入框中输入关键字git,会显示出git相关的系统名称列表,选择并回车打开github.com,相当于另类书签。[]()4.2设计思路[]()4.3项目结构及实现这里Electron使用ElectronReactBoilerplate脚手架,使用webpack搭建UI部分。Tauri使用官方脚手架工具create-tauri-app,内置Vite。选择React作为前端框架。导航启动器主要涉及以下功能:整个应用程序不显示关闭、最小化、最大化按钮和整个菜单栏(menuBar)。无边框窗口在视觉上看起来整个应用程序就是一个输入框。应用窗口高度根据网页内容高度自适应注册显示应用,隐藏应用监控按钮,使用默认浏览器打开链接[]()4.3.1功能点,Electron由主窗口初始化修改配置时,将frame设置为false即可实现无边框窗口在Tauri中,实现无边框窗口有三种方式:通过tauri.conf.json配置,通过Tauri提供的JSAPI-@tauri-apps/api,通过Rust原生修改窗口;这里我们选择在tauri.config.json中配置[]()4.3.2功能点2的输入框部分由React实现。主要区别在于表单的高度是根据内容的高度动态调整的。就是根据document.body.offsetHeight的高度来设置mainWindow的高度。在Electron中,可以在渲染进程中发送IPC通知主进程修改。主进程可以在监听消息后修改高度。在陶里,还是比较方便的。对于常用的所有函数的功能都封装了JSAPI,也就是上面提到的@tauri-apps/api,可以直接导入方法call[]()4.3.3对于功能点3,注册全局快捷键即可控制mainWindow的显示和隐藏在Electron中,首先定义registerGlobalShortcut方法,在app启动后注册快捷键,主要在主进程中操作。在Tauri中,得益于JSAPI的方便,可以在渲染进程中注册,所以只需要在React生命周期中注册[]()4.3.4为了方便演示功能点4,这里我们直接.body进行onkeydown监听,光标上下选择对应的选项,回车或者点击默认浏览器打开对应的链接,至此两者的实现非常相似,主要功能已经完成,下一步是看如何打包多平台应用程序。[]()4.4应用打包在Electron中,有两种常见的打包方式,electron-packager和electron-builder。electron-builder的生态比较好,所以这里选择electron-builder。在Tauri中,cli中内置了打包解决方案。运行yarntauribuild来比较相同的应用程序。同样的React版本没有使用UI框架。以上数据对比与Tauri主页上的数值基本一致。它体积小,内存占用小。[]()4.5应用更新两者都有相应的解决方案。详情请参考官方文档。本文不做过多介绍。[]()5总结一下,NW.js的时代已经过去了,考虑NW.js的可以优先考虑Electron。金牛座表现不错,前途无量。解决了Electron存在的诸多问题,带来了简单便捷的开发体验。也期望将Deno作为应用的后端处理集成到Tauri的路线图中,从而可以继续使用JavaScript/TypeSrupt来实现应用后端逻辑。新的项目可以考虑使用,但是还有一些问题需要改进,Rust的学习曲线比较曲折,有一定的学习成本。Electron仍然是目前最多的选择,得益于其庞大的社区、丰富的功能和工程实践,性能优化对开发者来说是一个挑战。