各位观众老爷们,大家好!今天咱们开个小讲座,主题是“Vue 应用变身记:Tauri 和 Electron 助你打造桌面超能力”。 咱们要让 Vue 应用从网页小清新,摇身一变,成为功能强大的桌面应用,还能跟系统 API 亲密互动,想想是不是有点小激动?
开场白:网页到桌面,不止是换个壳
咱们都知道 Vue 是个前端框架,擅长构建用户界面。但浏览器毕竟有它的局限性,有些系统级别的操作,比如访问摄像头、操作文件系统、监听硬件事件,浏览器出于安全考虑,一般是不允许的。这时候,我们就需要 Tauri 和 Electron 这两个神器来帮忙了。
它们俩的作用,简单来说,就是给你的 Vue 应用套上一层“桌面外壳”,让它可以像普通的桌面应用一样运行,并且可以通过特定的 API,调用操作系统的功能。
第一幕:主角登场,Tauri vs. Electron
在开始“变身”之前,我们先来认识一下今天的主角:Tauri 和 Electron。
特性 | Tauri | Electron |
---|---|---|
底层技术 | Rust + 系统 WebView | Chromium + Node.js |
包大小 | 非常小 (几 MB) | 较大 (几十 MB) |
性能 | 优秀,接近原生应用 | 相对较好,但资源占用较高 |
安全性 | 更安全,Rust 语言特性提供保障 | 相对安全,但需要注意安全漏洞 |
语言 | 主要使用 Rust,前端仍可用 HTML/CSS/JS | 主要使用 JavaScript/HTML/CSS |
开发难度 | 相对较高,需要学习 Rust | 相对较低,JavaScript 开发者更容易上手 |
跨平台支持 | 支持 Windows, macOS, Linux 等 | 支持 Windows, macOS, Linux 等 |
简单总结一下:
- Electron: 优点是上手快,JavaScript 开发者友好,生态系统完善。缺点是包体积大,资源占用高。
- Tauri: 优点是包体积小,性能好,安全性高。缺点是学习曲线陡峭,需要学习 Rust。
所以,选择哪个,取决于你的项目需求和团队技术栈。如果你追求性能和安全,并且愿意学习 Rust,Tauri 是个不错的选择。如果你更看重开发效率和生态系统,Electron 可能更适合你。
第二幕:Tauri 初体验,Hello World!
咱们先来用 Tauri 创建一个简单的 Hello World 应用。
-
安装 Rust 和 Tauri CLI:
首先,确保你的电脑上安装了 Rust。没有的话,去 Rust 官网下载安装:https://www.rust-lang.org/
安装完成后,打开终端,安装 Tauri CLI:
cargo install create-tauri-app
-
创建 Tauri 项目:
cargo create-tauri-app
这个命令会问你一些问题,比如项目名称、使用哪个前端框架等等。选择 Vue.js,然后一路回车就行。
-
运行 Tauri 应用:
进入项目目录:
cd <你的项目名称>
运行开发模式:
npm install # 安装依赖 npm run tauri dev
恭喜你,一个简单的 Tauri 应用就跑起来了!
-
修改前端代码:
打开
src/App.vue
文件,修改内容,让它显示 "Hello World!"。<template> <div class="container"> <h1>Hello World!</h1> </div> </template> <script setup> </script> <style scoped> .container { display: flex; justify-content: center; align-items: center; height: 100vh; } h1 { font-size: 3em; color: #42b983; } </style>
保存文件,你会发现应用自动刷新,显示 "Hello World!"。
第三幕:Electron 入门,同样 Hello World!
接下来,咱们用 Electron 也创建一个 Hello World 应用。
-
创建 Electron 项目:
创建一个新的目录,初始化 npm 项目:
mkdir electron-hello-world cd electron-hello-world npm init -y
-
安装 Electron:
npm install electron --save-dev
-
创建主进程文件
main.js
:const { app, BrowserWindow } = require('electron'); const path = require('path'); function createWindow() { const mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: path.join(__dirname, 'preload.js'), // 预加载脚本,后面会讲到 nodeIntegration: true, // 允许在渲染进程中使用 Node.js API contextIsolation: false // 关闭上下文隔离,方便使用 Node.js API } }); mainWindow.loadFile('index.html'); // 加载 HTML 文件 // mainWindow.webContents.openDevTools() // 打开开发者工具 } app.whenReady().then(() => { createWindow(); app.on('activate', function () { if (BrowserWindow.getAllWindows().length === 0) createWindow(); }); }); app.on('window-all-closed', function () { if (process.platform !== 'darwin') app.quit(); });
-
创建预加载脚本
preload.js
(可选):这个文件主要用于在渲染进程中安全地访问 Node.js API。 简单起见,这里可以先创建一个空文件,后面再详细介绍它的作用。
// preload.js
-
创建 HTML 文件
index.html
:<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Hello World!</title> </head> <body> <h1>Hello World!</h1> </body> </html>
-
配置
package.json
:在
package.json
文件中添加一个start
脚本:{ "name": "electron-hello-world", "version": "1.0.0", "description": "", "main": "main.js", "scripts": { "start": "electron ." }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "electron": "^28.2.0" } }
-
运行 Electron 应用:
npm start
搞定!Electron 的 Hello World 应用也跑起来了。
第四幕:Vue + Tauri/Electron,强强联合
现在,咱们把 Vue 应用集成到 Tauri 和 Electron 中。
Tauri + Vue:
Tauri 项目默认已经集成了 Vue,所以你只需要把你的 Vue 应用代码复制到 src
目录下即可。然后修改 src-tauri/tauri.conf.json
文件,将 distDir
指向你的 Vue 应用的构建目录(通常是 dist
)。
{
"build": {
"beforeBuildCommand": "npm run build", // 构建 Vue 应用的命令
"beforeDevCommand": "npm run dev", // 开发模式下运行 Vue 应用的命令
"devPath": "http://localhost:3000", // 开发模式下的 URL
"distDir": "../dist" // Vue 应用的构建目录
},
// ... 其他配置
}
在 Vue 项目中运行 npm run build
构建应用,然后运行 npm run tauri dev
启动 Tauri 应用。
Electron + Vue:
-
安装 Vue CLI:
npm install -g @vue/cli
-
创建 Vue 项目:
vue create vue-electron-app
选择你喜欢的预设。
-
在 Electron 项目中集成 Vue 应用:
将 Vue 应用的构建目录(
dist
)复制到 Electron 项目的根目录下。修改
main.js
文件,加载 Vue 应用的index.html
文件:// main.js const { app, BrowserWindow } = require('electron'); const path = require('path'); function createWindow() { const mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: path.join(__dirname, 'preload.js'), nodeIntegration: true, contextIsolation: false } }); mainWindow.loadFile(path.join(__dirname, 'dist/index.html')); // 加载 Vue 应用的 HTML 文件 // mainWindow.webContents.openDevTools() } app.whenReady().then(() => { createWindow(); app.on('activate', function () { if (BrowserWindow.getAllWindows().length === 0) createWindow(); }); }); app.on('window-all-closed', function () { if (process.platform !== 'darwin') app.quit(); });
在 Vue 项目中运行
npm run build
构建应用,然后运行npm start
启动 Electron 应用。
第五幕:与原生 API 交互,释放桌面超能力
重头戏来了!咱们要让 Vue 应用与操作系统 API 交互。
Tauri:
Tauri 提供了一套强大的 API,可以通过 Rust 代码调用操作系统功能。
-
定义 Rust 函数:
在
src-tauri/src/main.rs
文件中,定义一个 Rust 函数,用于读取文件内容:// src-tauri/src/main.rs use tauri::{Manager, State, AppHandle, Window}; use std::fs; #[tauri::command] async fn read_file(path: String) -> Result<String, String> { match fs::read_to_string(path) { Ok(content) => Ok(content), Err(e) => Err(e.to_string()), } } fn main() { tauri::Builder::default() .invoke_handler(tauri::generate_handler![read_file]) // 注册 Rust 函数 .run(tauri::generate_context!()) .expect("error while running tauri application"); }
-
在 Vue 代码中调用 Rust 函数:
在 Vue 组件中,使用
invoke
函数调用 Rust 函数:// src/App.vue <template> <div> <button @click="readFile">读取文件</button> <p>{{ fileContent }}</p> </div> </template> <script setup> import { ref } from 'vue'; import { invoke } from '@tauri-apps/api/tauri'; const fileContent = ref(''); const readFile = async () => { try { const content = await invoke('read_file', { path: '/path/to/your/file.txt' }); fileContent.value = content; } catch (error) { console.error(error); } }; </script>
Electron:
Electron 可以通过 nodeIntegration
和 contextIsolation
两种方式访问 Node.js API。
-
nodeIntegration: true, contextIsolation: false
: 这种方式最简单,可以直接在渲染进程中使用require
函数引入 Node.js 模块。但是安全性较低,不推荐在生产环境中使用。 -
nodeIntegration: false, contextIsolation: true
: 这种方式更安全,需要在主进程中定义 API,然后通过preload.js
脚本暴露给渲染进程。
咱们以更安全的 contextIsolation: true
方式为例:
-
在主进程中定义 API:
// main.js const { app, BrowserWindow, ipcMain } = require('electron'); const path = require('path'); const fs = require('fs'); function createWindow() { const mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: path.join(__dirname, 'preload.js'), nodeIntegration: false, contextIsolation: true } }); mainWindow.loadFile(path.join(__dirname, 'dist/index.html')); // mainWindow.webContents.openDevTools() } app.whenReady().then(() => { createWindow(); app.on('activate', function () { if (BrowserWindow.getAllWindows().length === 0) createWindow(); }); }); app.on('window-all-closed', function () { if (process.platform !== 'darwin') app.quit(); }); ipcMain.handle('read-file', async (event, path) => { try { const content = fs.readFileSync(path, 'utf-8'); return content; } catch (error) { console.error(error); return error.message; } });
-
在
preload.js
中暴露 API:// preload.js const { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeAPI({ readFile: async (path) => { return await ipcRenderer.invoke('read-file', path); } });
-
在 Vue 代码中调用 API:
// src/App.vue <template> <div> <button @click="readFile">读取文件</button> <p>{{ fileContent }}</p> </div> </template> <script setup> import { ref } from 'vue'; const fileContent = ref(''); const readFile = async () => { try { const content = await window.readFile('/path/to/your/file.txt'); fileContent.value = content; } catch (error) { console.error(error); } }; </script>
第六幕:打包发布,让世界看到你的作品
最后,咱们要把应用打包成可执行文件,让大家都能使用。
Tauri:
npm run tauri build
打包后的文件会在 src-tauri/target/release/bundle
目录下。
Electron:
需要使用 electron-builder
或 electron-packager
等工具进行打包。
-
安装
electron-builder
:npm install electron-builder --save-dev
-
配置
package.json
:{ "name": "electron-hello-world", "version": "1.0.0", "description": "", "main": "main.js", "scripts": { "start": "electron .", "build": "vue-cli-service build", "electron:build": "vue-cli-service electron:build", "electron:serve": "vue-cli-service electron:serve", "postinstall": "electron-builder install-app-deps", "pack": "electron-builder --dir", "dist": "electron-builder" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "electron": "^28.2.0", "electron-builder": "^24.9.1", "@vue/cli-plugin-electron-builder": "~5.0.0", "@vue/cli-service": "~5.0.0" }, "build": { "appId": "com.example.app", "productName": "MyApp", "copyright": "Copyright © 2024 Example", "directories": { "output": "dist_electron" }, "files": [ "dist/**/*", "main.js", "preload.js" ], "asar": true, "mac": { "category": "public.app-category.utilities" }, "win": { "target": [ "nsis" ] }, "linux": { "target": [ "deb", "rpm", "snap" ] } } }
-
打包应用:
npm run dist
打包后的文件会在
dist_electron
目录下。
总结:Vue 应用的无限可能
通过 Tauri 和 Electron,我们可以将 Vue 应用打包成功能强大的桌面应用,并且可以与操作系统 API 交互,实现更多更强大的功能。 无论你选择哪个框架,都要记住安全第一,避免滥用 Node.js API,确保你的应用安全可靠。
希望这次讲座能帮助你更好地理解 Tauri 和 Electron,让你在 Vue 应用的开发道路上更上一层楼。 感谢大家的观看!