4.1 前端技术栈接入:Vite、Vue与纯HTML


装壳第一问:面板用什么工艺。Tauri 对前端栈的态度是"来者不拒"——壳只加载页面,不关心页面用什么框架生成。本节用三种代表性姿势(纯 HTML、Vue、React)接入同一扇壳,讲清共同原理与各自的接线差异,并给出选栈建议。读完本节,你既能给新项目选型,也能把存量前端工程"平移"进壳。

原理先行:壳只认两个地址

不管什么栈,接入的本质是回答 build 段的两个问题:开发时壳去哪个地址加载页面(devUrl),交付时静态文件在哪个目录(frontendDist)。纯 HTML 项目的两个答案是"本地文件"与"根目录";Vite 工程的答案是"本地服务端口"与"产物目录 dist"。框架差异在壳眼里只是这两个答案的差异——这就是"换栈只改三行配置"的原因。

姿势一:纯 HTML 加 withGlobalTauri

第 3 章的 Vanilla 工程用了 npm 走 @tauri-apps/api。如果连 npm 都不想要——写个单文件页面就想跑——打开配置里的全局开关:

{ "app": { "withGlobalTauri": true } }

构建后 Tauri 会在页面里注入全局对象,前端不用打包器直接调:

<script> const { invoke } = window.__TAURI__.core; document.querySelector('#save').addEventListener('click', async () => { const title = document.querySelector('#title').value; const note = await invoke('add_note', { title, body: '' }); console.log('已保存', note.id); }); </script>

适用边界要诚实:适合原型、工具页、极简内部工具;页面一复杂(组件化、状态管理、类型检查),缺失工程化的代价立刻超过省下的配置。逃生门存在,但别把它当正门。

姿势二:Vue 工程接入

用 create-tauri-app 选 Vue 模板,或给存量 Vue 工程手动接线。手动接线只有三处:

{ "build": { "beforeDevCommand": "npm run dev", "devUrl": "http://localhost:5173", "beforeBuildCommand": "npm run build", "frontendDist": "../dist" } }
// 前端侧封装一个 invoke 模块,全工程统一出口 // src/lib/bridge.ts import { invoke } from '@tauri-apps/api/core'; export interface Note { id: number; title: string; body: string; createdAt: number; } export async function addNote(title: string, body: string): Promise<Note> { return invoke('add_note', { title, body }); } export async function listNotes(): Promise<Note[]> { return invoke('list_notes'); }

组件里把 bridge 当普通异步函数用:

<script setup lang="ts"> import { ref, onMounted } from 'vue'; import { addNote, listNotes, type Note } from './lib/bridge'; const notes = ref<Note[]>([]); const title = ref(''); async function save() { if (!title.value.trim()) return; const note = await addNote(title.value.trim(), ''); notes.value.push(note); title.value = ''; } onMounted(async () => { notes.value = await listNotes(); }); </script> <template> <input v-model="title" placeholder="记点什么,回车保存" @keyup.enter="save" /> <ul> <li v-for="n in notes" :key="n.id">{{ n.title }}</li> </ul> </template>

两个工程细节点透:bridge 模块是全工程唯一出现 invoke 的地方——命令改名、参数调整只动一个文件;TypeScript 接口与 Rust 结构体在这里第一次手写对齐(Note 的字段与第 5 章的 Rust 结构一一对应),字段拼写错误要到运行时才暴露,所以大型项目值得上代码生成(5.1 节给方案)。

姿势三:React 接入的差异

React 工程接入与 Vue 完全同构:build 段三行照抄(devUrl 对准 Vite 端口),bridge 模块原样可用,组件层写法换成 hooks:

import { useEffect, useState } from 'react'; import { listNotes, type Note } from './lib/bridge'; export function NoteList() { const [notes, setNotes] = useState<Note[]>([]); useEffect(() => { listNotes().then(setNotes); }, []); return <ul>{notes.map(n => <li key={n.id}>{n.title}</li>)}</ul>; }

选 Vue 还是 React 不由 Tauri 决定——壳对两者无感知,团队既有栈优先。真正值得权衡的是"要不要框架":界面简单到两三个页面,Vanilla 加构建器反而清爽;有组件化与状态管理需求,再上框架不迟。

选栈速查

情形 建议 理由
存量 Web 应用桌面化 原栈直接接入 壳无感知,改动集中在 build 段
新项目、界面简单 Vanilla 或轻框架 减少依赖面,构建更快
团队有既定栈 跟团队栈 Tauri 不构成换栈理由
极客原型、单页面 withGlobalTauri 零依赖直跑,复杂化再迁移

本节要点回顾

  • 接入的本质是回答 devUrl 与 frontendDist 两个地址问题,框架差异被压缩在这两行;
  • withGlobalTauri 是逃生门:零打包器直调,适合原型不适合正餐;
  • bridge 模块收口:invoke 只出现在一个文件,命令变更单点维护;
  • 类型两头手写要谨慎:字段对齐靠约定,大项目上代码生成(第 5 章);
  • 壳对框架无感知:选栈跟团队与项目复杂度走,不由 Tauri 决定。

面板装上了,下一颗螺丝是让它转起来:invoke 实战——参数、返回、错误三件套的完整落地。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U