编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

Tauri:快速、跨平台的桌面应用程序

wxchong 2025-04-11 08:44:50 开源技术 20 ℃ 0 评论

多年来,Electron是构建桌面应用程序的实际跨平台框架。 Visual Studio Code,MongoDB Compass和Postman都是使用此框架构建的应用程序的很好的例子。Electron绝对很棒,但它有一些明显的缺点,其他一些现代框架已经克服了这些缺点 - Tauri是其中最好的之一。

什么是Tauri?

Tauri 是一个现代框架,允许您在前端使用熟悉的 Web 技术(如 HTML、CSS 和 JavaScript)设计、开发和构建跨平台应用程序,同时利用后端强大的 Rust 编程语言。

Tauri 与框架无关。这意味着你可以将它与你选择的任何前端库一起使用——比如 Vue、React、Svelte 等。此外,在基于 Tauri 的项目中使用 Rust 是完全可选的。你可以只使用 Tauri 提供的 JavaScript API 来构建你的整个应用程序。这样,不仅可以轻松构建新应用程序,还可以将已构建的 Web 应用程序的代码库转换为本机桌面应用程序,而几乎不需要更改原始代码。

让我们看看为什么我们应该使用Tauri而不是Electron。

Tauri与Electron:快速比较

构建一个真正伟大的应用程序有三个重要元素。应用必须小巧、快速且安全。Tauri在所有三个方面都优于Electron:

  • Tauri产生更小的二进制文件。正如你从Tauri发布的基准测试结果中看到的那样,即使是一个超级简单的Hello,World!应用程序在使用Electron构建时也可能是一个巨大的大小(超过120 MB)。相比之下,同一个 Tauri 应用程序的二进制大小要小得多,小于 2 MB。在我看来,这令人印象深刻。
  • Tauri应用程序执行得更快。从上面提到的同一页面,您还可以看到Tauri应用程序的内存使用量可能接近同等Electron应用程序的一半。
  • Tauri应用程序是高度安全的。在Tauri网站上,您可以阅读Tauri默认提供的所有内置安全功能。但我想在这里提到的一个值得注意的功能是开发人员可以显式启用或禁用某些 API。这不仅使应用更安全,而且还减小了二进制大小。

构建笔记应用

在本节中,我们将构建一个简单的笔记应用,具有以下功能:

  • 添加和删除笔记
  • 重命名备忘录的标题
  • 在 Markdown 中编辑备忘录的内容
  • 在 HTML 中预览笔记的内容
  • 将笔记保存在本地存储中
  • 将笔记导入和导出到系统硬盘驱动器

您可以在 GitHub 上找到所有项目文件。

开始

要开始使用 Tauri,您首先需要安装 Rust 及其系统依赖项。它们因用户的操作系统而异,因此我不打算在这里探讨它们。请按照文档中适用于您的操作系统的说明进行操作。

准备就绪后,在所选目录中运行以下命令:

npm create tauri-app

这将指导您完成安装过程,如下所示:

$ npm create tauri-app

We hope to help you create something special with Tauri!
You will have a choice of one of the UI frameworks supported by the greater web tech community.
This tool should get you quickly started. See our docs at https://tauri.app/

If you haven't already, please take a moment to setup your system.
You may find the requirements here: https://tauri.app/v1/guides/getting-started/prerequisites  
    
Press any key to continue...
? What is your app name? my-notes
? What should the window title be? My Notes
? What UI recipe would you like to add? create-vite (vanilla, vue, react, svelte, preact, lit) (https://vitejs.dev/guide/#scaffolding-your-first-vite-project)
? Add "@tauri-apps/api" npm package? Yes
? Which vite template would you like to use? react-ts
>> Running initial command(s)
Need to install the following packages:
  create-vite@3.2.1
Ok to proceed? (y) y

>> Installing any additional needed dependencies

added 87 packages, and audited 88 packages in 19s

9 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

added 2 packages, and audited 90 packages in 7s

10 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
>> Updating "package.json"
>> Running "tauri init"

> my-notes@0.0.0 tauri
> tauri init --app-name my-notes --window-title My Notes --dist-dir ../dist --dev-path http://localhost:5173

 What is your frontend dev command? · npm run dev
 What is your frontend build command? · npm run build
>> Updating "tauri.conf.json"
>> Running final command(s)

    Your installation completed.

    $ cd my-notes
    $ npm run tauri dev

请确保您的选择与我所做的选择相匹配,这些选择主要是为具有 Vite 和 TypeScript 支持的 React 应用程序搭建脚手架,并安装 Tauri API 包。

暂时不要运行该应用。首先,我们需要安装项目所需的一些其他软件包。在终端中运行以下命令:

npm install @mantine/core @mantine/hooks @tabler/icons @emotion/react marked-react

这将安装以下软件包:

  • Mantine:一个功能齐全的 React 组件库
  • 桌面图标:超过3000个像素完美的网页设计图标
  • React的情感:用于React 中的简单样式
  • marked-react:用于使用 Markdown 渲染为 React 组件

现在我们已经准备好测试应用程序,但在此之前,让我们看看项目是如何构建的:

my-notes/
├─ node_modules/
├─ public/
├─ src/
│   ├─ assets/
│   │   └─ react.svg
│   ├─ App.css
│   ├─ App.tsx
│   ├─ index.css
│   ├─ main.tsx
│   └─ vite-env.d.ts
├─ src-tauri/
│   ├─ icons/
│   ├─ src/
│   ├─ .gitignore
│   ├─ build.rs
│   ├─ Cargo.toml
│   └─ tauri.config.json
├─ .gitignore
├─ index.html
├─ package-lock.json
├─ package.json
├─ tsconfig.json
├─ tsconfig.node.json
└─ vite.config.ts

这里最重要的是,应用程序的 React 部分存储在目录中,而 Rust 和其他特定于 Tauri 的文件存储在 .我们需要在Tauri目录中触摸的唯一文件是 ,我们可以在其中配置应用程序。打开此文件并找到密钥。将其内容替换为以下内容:
srcsrc-tauritauri.conf.jsonallowlist

"allowlist": {
  "dialog": {
    "save": true,
    "open": true,
    "ask": true
  },
  "fs": {
    "writeFile": true,
    "readFile": true,
    "scope": ["$DOCUMENT/*", "$DESKTOP/*"]
  },
  "path": {
    "all": true
  },
  "notification": {
    "all": true
  }
},

在这里,出于安全原因,正如我上面提到的,我们只启用我们将在应用中使用的 API。我们还限制对文件系统的访问,只有两个例外 — 和目录。这将允许用户将其笔记仅导出到这些目录。DocumentsDesktop

在关闭文件之前,我们需要再更改一件事。找到密钥。在该密钥下,您将找到该密钥。将其值更改为 。这在应用构建时是必需的,因为标识符必须是唯一的。
bundleidentifiercom.mynotes.dev

我想提到的最后一件事是,在最后一个键中,您可以设置所有与窗口相关的设置:windows

"windows": [
  {
    "fullscreen": false,
    "height": 600,
    "resizable": true,
    "title": "My Notes",
    "width": 800
  }
]

如您所见,密钥是根据您在安装过程中为其提供的值为您设置的。title

好的,让我们终于启动应用程序了。在目录中,运行以下命令:my-notes

npm run tauri dev 

您需要等待一段时间,直到 Tauri 设置完成并且所有文件都已首次编译。不用担心。在后续构建中,该过程将快得多。当Tauri准备就绪时,它将自动打开应用程序窗口。下图显示了您应该看到的内容。

注意:在开发模式下运行或构建应用程序后,将在 src-tauri 中创建一个新的目标目录,其中包含所有编译的文件。在开发模式下,它们放置在调试子目录中,在生成模式下,它们放置在发布子目录中。

好的,现在让我们根据我们的需求调整文件。首先,删除 和 文件。然后打开该文件并将其内容替换为以下内容:index.cssApp.cssmain.tsx

import React from 'react'
import ReactDOM from 'react-dom/client'
import { MantineProvider } from '@mantine/core'
import App from './App'

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  
    
      
    
  
)

这将设置Mantine的组件以供使用。

接下来,打开文件并将其内容替换为以下内容:App.tsx

import { useState } from 'react'
import { Button } from '@mantine/core'

function App() {
  const [count, setCount] = useState(0)

  return (
    
) } export default App

现在,如果您查看应用程序窗口,您应该会看到以下内容:

通过单击按钮确保应用程序正常运行。如果出现问题,您可能需要对其进行调试。(请参阅以下注释。

注意:当应用在开发模式下运行时,可以通过右键单击应用窗口并从菜单中选择“检查”来打开 DevTools。

创建基本应用功能

现在,让我们创建应用的框架。将文件的内容替换为以下内容:App.tsx

import { useState } from 'react'
import Markdown from 'marked-react'

import { ThemeIcon, Button, CloseButton, Switch, NavLink, Flex, Grid, Divider, Paper, Text, TextInput, Textarea } from '@mantine/core'
import { useLocalStorage } from '@mantine/hooks'
import { IconNotebook, IconFilePlus, IconFileArrowLeft, IconFileArrowRight } from '@tabler/icons'

import { save, open, ask } from '@tauri-apps/api/dialog'
import { writeTextFile, readTextFile } from '@tauri-apps/api/fs'
import { sendNotification } from '@tauri-apps/api/notification'

function App() {
  const [notes, setNotes] = useLocalStorage({ key: "my-notes", defaultValue: [  {
    "title": "New note",
    "content": ""
  }] })

  const [active, setActive] = useState(0)
  const [title, setTitle] = useState("")
  const [content, setContent] = useState("")
  const [checked, setChecked] = useState(false)

  const handleSelection = (title: string, content: string, index: number) => {
    setTitle(title)
    setContent(content)
    setActive(index)
  }

  const addNote = () => {
    notes.splice(0, 0, {title: "New note", content: ""})
    handleSelection("New note", "", 0)
    setNotes([...notes])
  }

  const deleteNote = async (index: number) => {
    let deleteNote = await ask("Are you sure you want to delete this note?", {
      title: "My Notes",
      type: "warning",
    })
    if (deleteNote) {
      notes.splice(index,1)
      if (active >= index) {
        setActive(active >= 1 ? active - 1 : 0)
      }
      if (notes.length >= 1) {
        setContent(notes[index-1].content)
      } else {
        setTitle("")
        setContent("")
      } 
      setNotes([...notes]) 
    }
  }

  return (
    
My Notes <Button onClick={addNote} leftIcon={}>Add note <Button variant="light" leftIcon={}>Import <Button variant="light" leftIcon={}>Export {notes.map((note, index) => ( handleSelection(note.title, note.content, index)} active={index === active} label={note.title} /> deleteNote(index)} title="Delete note" size="xl" iconSize={20} /> ))} setChecked(event.currentTarget.checked)}/> {checked === false && (
最近发表
标签列表