Flutter、Electron、Tauri框架对比及Electron+Vue项目实战

打印 上一主题 下一主题

主题 1002|帖子 1002|积分 3006

Flutter、Electron、Tauri框架对比及Electron+Vue项目实战

随着移动互联网和桌面应用的快速发展,开发者们越来越倾向于使用跨平台框架来进步开发效率和降低资本。Flutter、Electron和Tauri作为当前最受欢迎的几种跨平台框架,各自拥有独特的优势和应用场景。本文旨在深入探究这三种框架的特点、优缺点,并分享一个基于Electron+Vue的项目实战经验。
背景

XXXX团队:我们想在断网环境下通过 RuntimeAI 运行 Python 程序,给用户输出日志、执行效果等需求的桌面端程序。
我:好的,上菜。
三大框架对比

Flutter简介

Flutter是Google推出的开源UI软件开发工具包,用于构建在iOS、Android、Web和桌面端高质量的原生界面。Flutter的一大特点是其“一次编写,处处运行”的本事,极大地进步了开发效率。Flutter使用Dart语言,拥有丰富的组件库和精良的性能。
Electron简介

Electron是一个使用JavaScript、HTML和CSS构建桌面应用的框架,由GitHub开发。它允许开发者将Web技能用于桌面软件的开发,使得原本只能在网络欣赏器中运行的应用能够被作为独立的桌面应用来分发和安装。Electron应用本质上是Chromium欣赏器的变种,这意味着它相对较重,但开发速率快,易于上手。
Tauri简介

Tauri 是一个相对较新的框架,旨在提供一个安全、轻量级的平台,用于将Web技能包装成桌面应用。与Electron相比,Tauri的最大优势在于其对安全性的强调以及更小的应用体积。Tauri应用使用Rust语言进行系统调用,提供了更好的性能和更低的资源消耗。
特点FlutterElectronTauri开发语言DartJavaScript, HTML, CSSJavaScript, HTML, CSS跨平台移动、Web和桌面应用开发桌面应用开发桌面应用开发性能高(Flutter直接编译到机器代码,淘汰了桥接层)中(基于Chromium和Node.js,可能占用更多资源)高(天生的应用体积小,性能优化)用户界面丰富的UI组件库,可高度自定义使用Web技能构建UI,机动使用Web技能构建UI,机动应用体积小较大(包含Chromium和Node.js)中安全性依赖于框架自己和开发实践依赖于框架自己和开发实践,可能需要注意Web安全问题高(Rust的安全性优势)实用场景得当需要高性能和高度定制UI的跨平台应用得当希望快速将Web应用转为桌面应用的项目得当对应用体积和性能有严酷要求,注重安全的桌面应用开发社区支持强强弱GitHub Star161k111k75.5k 数据对比


根据三大框架官方文档,安装了开发和构建依赖、配置环境变量和乐成启动后,我将通过启动速率、目次结构、打包体积做真实对比。
   统一开发IDE为 VS Code
  

  • 启动速率:Electron > Tauri > Flutter
   启动速率只做大概预估,因为跟机器性能、网速和Tauri是否有新的依赖需要更新有关。
  

  • 目次结构:Electron 、Tauri > Flutter


  • 打包体积:Flutter > Tauri > Electron

框架选择

基于以上对比数据,我选择Electron,来由是:

  • 开发难度小
  • 安装依赖方便
  • 更加得当本次需求
  • VS Code也是使用Electron开发
  • 社区庞大
Electron+Vue3项目实战底子版)

   如果安装 electron、electron-builder和打包出错。中央思想就是自己下载好所需依赖,放至对应目次下。
    搭建Electron应用参考文章,部分需要做修改。
  

  • 项目初始化
首先,按照 Vue 官网步骤创建一个Vite+Vue+Ts项目:
  1. npm create vue@latest
  2. cd my-project
  3. code .
  4. npm install
复制代码

  • 添加Electron依赖:
  1. npm install electron vite-plugin-electron -D
复制代码

  • 修改package.json
   dist-electron:vite-plugin-electron插件运行后,会将electron主进程文件编译到dist-electron/index.js
  chcp 65001:解决中文乱码
  去掉 “type”: “module”
  1. "main": "dist-electron/index.js"
  2. "scripts": {
  3.   "dev": "chcp 65001 && vite"
  4.   ...
  5. }
复制代码

  • 配置vite.config.ts
  1. import { fileURLToPath, URL } from 'node:url'
  2. import { defineConfig } from 'vite'
  3. import vue from '@vitejs/plugin-vue'
  4. import electron from 'vite-plugin-electron'
  5. export default defineConfig({
  6.   plugins: [
  7.     vue(),
  8.     electron({
  9.       entry: "electron/index.ts"
  10.     })
  11.   ]
  12. })
复制代码

  • 创建 electron/index.ts 主进程文件
  1. import { app, BrowserWindow } from "electron";
  2. let win;
  3. const createWindow = () => {
  4.   win = new BrowserWindow({
  5.     webPreferences: {
  6.       contextIsolation: false, // 允许渲染器脚本访问预加载脚本中的全局变量和模块
  7.       nodeIntegration: true // 允许在渲染进程中使用node
  8.     },
  9.     title: "Main window",
  10.     width: 800,
  11.     height: 600
  12.   });
  13.   // 判断当前环境,加载不同html文件
  14.   if (process.env.NODE_ENV != "development") {
  15.     win.loadFile("dist/index.html");
  16.   } else {
  17.     win.loadURL(`${process.env["VITE_DEV_SERVER_URL"]}`);
  18.   }
  19. };
  20. // electron资源加载完毕,创建窗口
  21. app.whenReady().then(createWindow);
  22. // 窗口关闭,退出electron
  23. app.on("window-all-closed", () => {
  24.   app.quit();
  25. });
复制代码

  • 运行Electron应用
  1. npm run dev
复制代码


  • 添加打包应用的依赖
  1. npm i electron-builder -D
复制代码

  • package.json添加打包脚本和build配置
   可以自定义应用的logo,详情参考官方文档
  1. "scripts": {
  2.         "build": "vite build && electron-builder"
  3. },
  4. "build": {
  5.         "appId": "electron.desktop",
  6.     "productName": "vue-electron",
  7.     "asar": true,
  8.     "copyright": "Copyright © 2024",
  9.     "directories": {
  10.       // exe文件输出到release下
  11.       "output": "release/"
  12.     },
  13.     "files": [
  14.       "dist/**",
  15.       "dist-electron/**"
  16.     ],
  17.     "win": {
  18.       "target": [
  19.         {
  20.           "target": "nsis",
  21.           "arch": [
  22.             "x64"
  23.           ]
  24.         }
  25.       ],
  26.       "artifactName": "${productName}_${version}.${ext}"
  27.     },
  28.     "nsis": {
  29.       "oneClick": false,
  30.       "perMachine": false,
  31.       "allowToChangeInstallationDirectory": true,
  32.       "deleteAppDataOnUninstall": false
  33.     },
  34. }
复制代码

  • 打包并运行
  1. npm run build
复制代码
运行命令后,会天生release文件夹,此中包含了可执行文件vue-electron_0.0.0.exe。安装即可

Electron+Vue3项目实战(进阶版)

   给底子版添加新功能:前端点击按钮 --> 调用机器的Python程序 --> 执行自定义py脚本 --> 返回效果给前端
  前提:机器已经乐成安装 Python3
  

  • 新增py脚本
  1. # 根目录下新增scripts/script.py
  2. print("hello world")
复制代码

  • 使用node调用Python并执行py脚本
  1. import { app, BrowserWindow } from 'electron'
  2. import { spawn } from 'child_process'
  3. import path from 'path'
  4. let win;
  5. const createWindow = () => {
  6.   win = new BrowserWindow({
  7.     webPreferences: {
  8.       contextIsolation: false,
  9.       nodeIntegration: true,
  10.     },
  11.     title: "Main window",
  12.     width: 800,
  13.     height: 600
  14.   })
  15.   if(process.env.NODE_ENV != "development") {
  16.     win.loadFile("dist/index.html")
  17.   } else {
  18.     win.loadURL(`${process.env["VITE_DEV_SERVER_URL"]}`)
  19.   }
  20. }
  21. // start 创建node子进程,执行脚本
  22. const pythonProcess = spawn('python', [path.join(process.cwd(), 'scripts/script.py')])
  23. pythonProcess.stdout.on('data', res => {
  24.     //                  res为buffer格式,需要转换字符格式
  25.   console.log('success',res.toString());
  26. })
  27. pythonProcess.stderr.on('data', err => {
  28.   console.log('err', err.toString());
  29. })
  30. // end
  31. app.whenReady().then(createWindow);
  32. app.on('window-all-closed', () => {
  33.   app.quit()
  34. })
复制代码

  • 终端查看效果
  1. build started...
  2. ✓ 1 modules transformed.
  3. dist-electron/index.js  0.95 kB │ gzip: 0.55 kB
  4. built in 33ms.
  5. success hello world
复制代码

  • 结合渲染进程获取执行效果(进程通讯)
   主进程与渲染进程
  1. npm i vite-plugin-electron-renderer -D
复制代码
  1. // vite.config.ts
  2. import electronRender from 'vite-plugin-electron-renderer'
  3. plugins: [
  4.     vue(),
  5.     electron({
  6.       entry: "electron/index.ts"
  7.     }),
  8.     electronRender()
  9. ],
复制代码

  • 前端发送消息给主进程
  1. <script setup lang="ts">
  2. import { ipcRenderer } from 'electron'
  3. // 添加点击事件,发送消息给主进程
  4. const runPy = () => {
  5.   ipcRenderer.send('run')
  6. }
  7. </script>
  8. <template>
  9.   <header>
  10.     <img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" @click="runPy"/>
  11.   </header>
  12. </template>
复制代码

  • 主进程开始执行
  1. // 首先将执行的子进程提取出来
  2. const run = () => {
  3.   return new Promise((resolve, reject) => {
  4.     const pythonProcess = spawn('python', [path.join(process.cwd(), 'scripts/script.py')])
  5.     pythonProcess.stdout.on('data', res => {
  6.       resolve(res.toString())
  7.     })
  8.     pythonProcess.stderr.on('data', err => {
  9.       reject(err.toString())
  10.     })
  11.   })
  12. }
  13. // 主进程监听到渲染进程的消息后,立马执行run函数,执行结束后再通知渲染进程
  14. ipcMain.on('run', () => {
  15.   run()
  16.     .then(res => {
  17.       win.webContents.send("finish", res)
  18.     })
  19.     .catch(err => {
  20.       win.webContents.send("finish", err)
  21.     })
  22. })
复制代码

  • 前端吸收效果
  1. <script setup lang="ts">
  2. import { ipcRenderer } from 'electron'
  3. import { ref } from 'vue'
  4. const runPy = () => {
  5.   ipcRenderer.send('run')
  6. }
  7. const result = ref()
  8. // 监听主进程发送的finish消息。实际发送的数据在回调的第二个参数中
  9. ipcRenderer.on('finish', (_, data:any) => {
  10.   result.value = data
  11. })
  12. </script>
  13. <template>
  14.   <header>
  15.     <img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" @click="runPy"/>
  16.     <p>子进程执行Python后的结果:<b>{{ result }}</b></p>
  17.   </header>
  18. </template>
复制代码

结语


  • Electron、nodejs有大量api需要在实践中慢慢摸索,以上只是冰山一角
  • 奇希奇怪的报错,大概率是node版本过低导致
  • 打包后的Flutter可执行文件无法显示,但有对应的进程在跑。修改如下代码:
  1. // windows\runner\flutter_window.cpp
  2. // 只留下 this->Show();
  3. //flutter_controller_->engine()->SetNextFrameCallback([&]() {
  4.   this->Show();
  5. //});
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

半亩花草

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表