各位观众,欢迎来到今天的 "Vue 应用变身桌面侠" 讲座现场! 今天咱们不聊虚的,直接上手,把 Vue 写的网页应用,摇身一变,变成能在电脑上跑的桌面程序,还能跟系统玩点“亲密互动”。 咱们就拿 Tauri
和 Electron
这俩“神器”开刀,手把手教你把 Vue 应用打包成桌面应用,还能调用原生 API,让你的应用“上天入地,无所不能”。
第一节:热身运动:Tauri vs Electron,谁才是你的菜?
先来个小小的“选秀”环节,Tauri
和 Electron
都是桌面应用开发的利器,但风格不太一样。
特性 | Tauri | Electron |
---|---|---|
技术栈 | Rust + WebView (系统自带) | JavaScript + Chromium |
体积 | 小巧玲珑 (几 MB) | 略显臃肿 (几十 MB 起步) |
性能 | 优秀 (Rust 扛把子) | 还可以 (毕竟 JS) |
资源占用 | 低 (省电小能手) | 较高 (吃内存小能手) |
安全性 | 高 (Rust 的优势) | 相对较低 (JS 的锅) |
跨平台 | 支持 (主流平台) | 支持 (主流平台) |
学习曲线 | 稍高 (Rust 需要啃一下) | 较低 (JS 老朋友) |
生态系统 | 相对较新,但发展迅速 | 成熟,社区庞大 |
简单来说,Tauri
就像一个精简版的跑车,性能好,体积小,但需要你懂点 Rust 的驾驶技巧。 Electron
就像一个舒适的房车,上手容易,功能齐全,但油耗可能稍微高一点。
选哪个,看你的需求和口味。 如果你追求极致性能和安全性,又不怕啃 Rust 这块“硬骨头”,Tauri
绝对是你的不二之选。 如果你只想快速上手,用熟悉的 JavaScript 技术栈搞定一切,Electron
也能满足你的需求。
第二节:Tauri 实战:Vue 应用的华丽变身
咱们先来用 Tauri
把一个简单的 Vue 应用打包成桌面程序。
-
准备 Vue 应用
如果你已经有一个 Vue 应用,可以直接跳到下一步。 如果没有,那就创建一个简单的 Vue 应用:
vue create my-tauri-app cd my-tauri-app
选择你喜欢的配置,一路回车就好。
-
安装 Tauri CLI
npm install -g @tauri-apps/cli
-
初始化 Tauri
在 Vue 项目根目录下运行:
tauri init
根据提示,填写项目名称、窗口标题等信息。 重要的一点,要选择
dist
目录作为你的 Vue 应用构建输出目录。 默认情况下,Vue CLI 会把构建好的文件放在dist
目录里。 -
构建 Vue 应用
npm run build
这会在
dist
目录生成你的 Vue 应用。 -
运行 Tauri 应用
tauri dev
见证奇迹的时刻到了! 你的 Vue 应用现在应该在一个独立的窗口里运行了,这就是你的桌面应用雏形。
-
打包 Tauri 应用
tauri build
这条命令会把你的 Vue 应用打包成一个可执行文件,放在
src-tauri/target/release/bundle
目录下。 你可以把这个可执行文件分发给你的朋友,让他们也能体验你的桌面应用。 -
与原生 API 交互 (Tauri Command)
Tauri
的强大之处在于它可以让你调用原生系统 API。 咱们来写一个简单的例子,让应用可以读取系统信息。- 在
src-tauri/src/main.rs
文件中添加以下代码:
#[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() .invoke_handler(tauri::generate_handler![my_custom_command]) // 注册命令 .run(tauri::generate_context!()) .expect("error while running tauri application"); } use tauri::State; use serde::{Serialize, Deserialize}; #[derive(Debug, Serialize, Deserialize)] pub struct MyState { pub message: String, } #[tauri::command] async fn my_custom_command(state: State<'_, MyState>) -> Result<String, String> { // 在这里调用原生 API // 例如,读取系统信息 let os_type = std::env::consts::OS; let arch = std::env::consts::ARCH; let message = format!("Hello from Rust! OS: {}, Arch: {}, State Message: {}", os_type, arch, state.message); Ok(message) }
- 在
src-tauri/src/main.rs
中添加状态管理代码
use tauri::{State}; use serde::{Serialize, Deserialize}; #[derive(Debug, Serialize, Deserialize)] pub struct MyState { pub message: String, } #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() .manage(MyState { message: "Initial State".to_string() }) // 初始化状态 .invoke_handler(tauri::generate_handler![my_custom_command]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } #[tauri::command] async fn my_custom_command(state: State<'_, MyState>) -> Result<String, String> { let os_type = std::env::consts::OS; let arch = std::env::consts::ARCH; let message = format!("Hello from Rust! OS: {}, Arch: {}, State Message: {}", os_type, arch, state.message); Ok(message) }
- 在 Vue 组件中调用
Tauri
命令:
<template> <button @click="getSystemInfo">获取系统信息</button> <p>{{ systemInfo }}</p> </template> <script> import { invoke } from '@tauri-apps/api/tauri'; export default { data() { return { systemInfo: '', }; }, methods: { async getSystemInfo() { try { this.systemInfo = await invoke('my_custom_command'); // 调用 Rust 命令 } catch (error) { console.error('Error invoking command:', error); this.systemInfo = 'Error: ' + error; } }, }, }; </script>
刷新你的 Tauri 应用,点击按钮,你就能看到系统信息显示在页面上了。 这只是一个简单的例子,你可以用
Tauri
调用各种各样的原生 API,比如读写文件、操作剪贴板、控制窗口等等。 - 在
第三节:Electron 上手:JS 老司机也能轻松驾驭
接下来,咱们用 Electron
来做同样的事情。
-
创建 Electron 项目
npm init -y electron-app cd electron-app npm install electron --save-dev
-
安装 Vue CLI
npm install -g @vue/cli vue create my-electron-vue-app cd my-electron-vue-app
-
集成 Vue 和 Electron
vue add electron-builder
这个命令会自动安装
electron-builder
,并配置好 Vue 项目,让你可以轻松地把 Vue 应用打包成 Electron 应用。 -
修改
main.js
(Electron 主进程)打开
background.js
文件,这是 Electron 的主进程文件,负责创建窗口、加载 Vue 应用等。const { app, BrowserWindow } = require('electron') const path = require('path') const url = require('url') let win function createWindow () { win = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true, contextIsolation: false } }) // 加载 Vue 应用 const startUrl = process.env.ELECTRON_START_URL || url.format({ pathname: path.join(__dirname, '/../dist/index.html'), protocol: 'file:', slashes: true }); win.loadURL(startUrl); // 打开开发者工具 win.webContents.openDevTools() win.on('closed', () => { win = null }) } app.on('ready', createWindow) app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit() } }) app.on('activate', () => { if (win === null) { createWindow() } })
nodeIntegration: true
允许你在 Vue 应用中使用 Node.js 的 API。 注意安全风险,在生产环境中谨慎使用。contextIsolation: false
允许在渲染进程中直接访问主进程的变量和函数。 同样注意安全风险。
-
运行 Electron 应用
npm run electron:serve
你的 Vue 应用现在应该在一个 Electron 窗口里运行了。
-
打包 Electron 应用
npm run electron:build
这条命令会把你的 Vue 应用打包成一个可执行文件,放在
dist_electron
目录下。 -
与原生 API 交互 (Electron ipcRenderer & ipcMain)
Electron 通过
ipcRenderer
(渲染进程) 和ipcMain
(主进程) 进行通信,从而调用原生 API。- 在
background.js
(主进程) 中添加以下代码:
const { app, BrowserWindow, ipcMain } = require('electron') const path = require('path') const url = require('url') const os = require('os'); // 引入 Node.js 的 os 模块 let win function createWindow () { win = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true, contextIsolation: false } }) const startUrl = process.env.ELECTRON_START_URL || url.format({ pathname: path.join(__dirname, '/../dist/index.html'), protocol: 'file:', slashes: true }); win.loadURL(startUrl); win.webContents.openDevTools() win.on('closed', () => { win = null }) } app.on('ready', createWindow) app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit() } }) app.on('activate', () => { if (win === null) { createWindow() } }) // 监听来自渲染进程的消息 ipcMain.on('get-system-info', (event) => { const systemInfo = { osType: os.type(), osRelease: os.release(), arch: os.arch() }; event.reply('system-info', systemInfo); // 发送消息给渲染进程 });
- 在 Vue 组件中调用 Electron API:
<template> <button @click="getSystemInfo">获取系统信息</button> <p>{{ systemInfo }}</p> </template> <script> const { ipcRenderer } = require('electron'); // 引入 ipcRenderer export default { data() { return { systemInfo: '', }; }, methods: { getSystemInfo() { ipcRenderer.send('get-system-info'); // 发送消息给主进程 ipcRenderer.on('system-info', (event, info) => { this.systemInfo = `OS Type: ${info.osType}, OS Release: ${info.osRelease}, Arch: ${info.arch}`; }); }, }, }; </script>
刷新你的 Electron 应用,点击按钮,你就能看到系统信息显示在页面上了。
- 在
第四节:进阶技巧:让你的桌面应用更上一层楼
- 自定义窗口外观:
Tauri
和Electron
都提供了丰富的 API,让你自定义窗口的外观,比如隐藏标题栏、设置窗口大小、添加菜单等等。 - 使用原生 UI 组件: 如果你想让你的应用看起来更像一个原生应用,可以考虑使用
Tauri
的 Wails 或Electron
的remote
模块来调用原生 UI 组件。 不过要注意,这会增加应用的复杂性。 - 优化性能: 对于大型应用,性能优化至关重要。 可以通过代码优化、资源压缩、懒加载等方式来提升应用的性能。
- 安全性: 桌面应用的安全问题不容忽视。 要注意防止 XSS 攻击、SQL 注入、代码注入等安全漏洞。
Tauri
在安全性方面有天然的优势,因为它使用 Rust 编写,可以有效防止内存安全问题。Electron
则需要你更加小心,避免使用不安全的 API,并定期更新 Electron 版本。
第五节:总结与展望
今天咱们一起学习了如何用 Tauri
和 Electron
把 Vue 应用打包成桌面应用,并调用原生 API。 希望通过今天的讲座,你能够掌握桌面应用开发的基本技能,创造出更多有趣、实用的桌面应用。
记住,Tauri
和 Electron
只是工具,真正重要的是你的创意和想法。 祝你在桌面应用开发的道路上越走越远! 感谢大家的观看,咱们下期再见!