Dans ce didacticiel, nous allons explorer Épreuvesun cadre multiplateforme moderne pour la création d’applications de bureau.
Contenu:
- Qu’est-ce que Tauri ?
- Tauri vs Electron : une comparaison rapide
- Créer une application de prise de notes
- Conclusion
Pendant de nombreuses années, Électron était le cadre multiplateforme de facto pour la création d’applications de bureau. Visual Studio Code, MongoDB Compass et Postman sont tous d’excellents exemples d’applications créées avec ce framework. Electron est vraiment génial, mais il présente des inconvénients importants, que d’autres frameworks modernes ont surmontés – Tauri étant l’un des meilleurs d’entre eux.
Qu’est-ce que Tauri ?
Tauri est un cadre moderne qui vous permet de concevoir, développer et créer des applications multiplateformes à l’aide de technologies Web familières telles que HTML, CSS et JavaScript sur le frontend, tout en tirant parti du puissant Langage de programmation Rust sur le backend.
Tauri est indépendant du framework. Cela signifie que vous pouvez l’utiliser avec n’importe quelle bibliothèque frontale de votre choix, telle que Vue, React, Svelte, etc. De plus, l’utilisation de Rust dans un projet basé sur Tauri est totalement facultative. Vous pouvez utiliser uniquement l’API JavaScript fournie par Tauri pour créer l’intégralité de votre application. Cela permet non seulement de créer une nouvelle application, mais également de prendre la base de code d’une application Web que vous avez déjà créée et de la transformer en une application de bureau native tout en ayant à peine besoin de modifier le code d’origine.
Regardons pourquoi nous devrions utiliser Tauri au lieu d’Electron.
Tauri vs Electron : une comparaison rapide
Il y a trois éléments importants pour créer une très bonne application. L’application doit être petite, rapide et sécurisée. Tauri surpasse Electron dans les trois :
- Tauri produit des binaires beaucoup plus petits. Comme vous pouvez le voir sur benchmarks résultats publiés par Taurimême un super simple Bonjour le monde! L’application peut avoir une taille énorme (plus de 120 Mo) lorsqu’elle est construite avec Electron. En revanche, la taille binaire de la même application Tauri est beaucoup plus petite, inférieure à 2 Mo. C’est assez impressionnant à mon avis.
- Les applications Tauri fonctionnent beaucoup plus rapidement. À partir de la même page mentionnée ci-dessus, vous pouvez également voir que l’utilisation de la mémoire des applications Tauri pourrait être près de la moitié de celle d’une application Electron équivalente.
- Les applications Tauri sont hautement sécurisées. Sur le site Web de Tauri, vous pouvez lire sur toutes les fonctions de sécurité intégrées Tauri fournit par défaut. Mais une caractéristique notable que je veux mentionner ici est que les développeurs peuvent explicitement activer ou désactiver certaines API. Cela permet non seulement de sécuriser votre application, mais également de réduire la taille binaire.
Créer une application de prise de notes
Dans cette section, nous allons créer une application de prise de notes simple avec les fonctionnalités suivantes :
- ajouter et supprimer des notes
- renommer le titre d’une note
- modifier le contenu d’une note dans Markdown
- prévisualiser le contenu d’une note en HTML
- enregistrer des notes dans le stockage local
- importer et exporter des notes sur le disque dur du système
Vous pouvez trouver tous les fichiers de projet sur GitHub.
Commencer
Pour démarrer avec Tauri, vous devez d’abord installer Rust et ses dépendances système. Ils sont différents selon le système d’exploitation de l’utilisateur, je ne vais donc pas les explorer ici. Veuillez suivre les instructions de votre système d’exploitation dans la documentation.
Lorsque vous êtes prêt, dans un répertoire de votre choix, exécutez la commande suivante :
Cela vous guidera tout au long du processus d’installation comme indiqué ci-dessous :
$ 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/
? 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
Veuillez vous assurer que vos choix correspondent à ceux que j’ai faits, qui sont principalement l’échafaudage d’une application React avec le support Vite et TypeScript et l’installation du package API Tauri.
Ne lancez pas encore l’application. Nous devons d’abord installer quelques packages supplémentaires nécessaires à notre projet. Exécutez les commandes suivantes dans votre terminal :
npm install @mantine/core @mantine/hooks @tabler/icons @emotion/react marked-react
Cela installera les packages suivants :
Nous sommes maintenant prêts à tester l’application, mais avant cela, voyons comment le projet est structuré :
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
La chose la plus importante ici est que la partie React de l’application est stockée dans le src
répertoire et Rust et d’autres fichiers spécifiques à Tauri sont stockés dans src-tauri
. Le seul fichier que nous devons toucher dans le répertoire Tauri est tauri.conf.json
, où nous pouvons configurer l’application. Ouvrez ce fichier et trouvez le allowlist
clé. Remplacez son contenu par ce qui suit :
"allowlist": {
"dialog": {
"save": true,
"open": true,
"ask": true
},
"fs": {
"writeFile": true,
"readFile": true,
"scope": ["$DOCUMENT/*", "$DESKTOP/*"]
},
"path": {
"all": true
},
"notification": {
"all": true
}
},
Ici, pour des raisons de sécurité, comme je l’ai mentionné ci-dessus, nous n’activons que les API que nous allons utiliser dans notre application. Nous restreignons également l’accès au système de fichiers avec seulement deux exceptions — le Documents
et Desktop
répertoires. Cela permettra aux utilisateurs d’exporter leurs notes uniquement vers ces répertoires.
Nous devons changer encore une chose avant de fermer le fichier. Trouvez le bundle
clé. Sous cette clé, vous trouverez le identifier
clé. Modifiez sa valeur en com.mynotes.dev
. Ceci est nécessaire lors de la création de l’application, car l’identifiant doit être unique.
La dernière chose que je veux mentionner est que, dans la dernière windows
clé, vous pouvez configurer tous les paramètres liés à la fenêtre :
"windows": [
{
"fullscreen": false,
"height": 600,
"resizable": true,
"title": "My Notes",
"width": 800
}
]
Comme vous pouvez le voir, le title
clé a été configurée pour vous en fonction de la valeur que vous lui avez donnée lors de l’installation.
OK, alors lançons enfin l’application. Dans le my-notes
répertoire, exécutez la commande suivante :
Vous devrez attendre un moment jusqu’à ce que l’installation de Tauri soit terminée et que tous les fichiers aient été compilés pour la première fois. Ne t’inquiète pas. Dans les versions suivantes, le processus sera beaucoup plus rapide. Lorsque Tauri est prêt, il ouvre automatiquement la fenêtre de l’application. L’image ci-dessous montre ce que vous devriez voir.
Remarque : après l’exécution de l’application en mode développement ou sa génération, un nouveau target
répertoire est créé à l’intérieur src-tauri
, qui contient tous les fichiers compilés. En mode dev, ils sont placés dans le debug
sous-répertoire, et en mode construction, ils sont placés dans le release
sous-répertoire.
OK, adaptons maintenant les fichiers à nos besoins. Tout d’abord, supprimez le index.css
et App.css
des dossiers. Ouvrez ensuite le main.tsx
fichier et remplacez son contenu par ce qui suit :
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(
<React.StrictMode>
<MantineProvider withGlobalStyles withNormalizeCSS>
<App />
</MantineProvider>
</React.StrictMode>
)
Cela configure les composants de Mantine à utiliser.
Ensuite, ouvrez le App.tsx
fichier et remplacez son contenu par ce qui suit :
import { useState } from 'react'
import { Button } from '@mantine/core'
function App() {
const [count, setCount] = useState(0)
return (
<div>
<Button onClick={() => setCount((count) => count + 1)}>count is {count}</Button>
</div>
)
}
export default App
Maintenant, si vous regardez dans la fenêtre de l’application, vous devriez voir ce qui suit :
Assurez-vous que l’application fonctionne correctement en cliquant sur le bouton. Si quelque chose ne va pas, vous devrez peut-être le déboguer. (Voir la remarque suivante.)
Remarque : lorsque l’application s’exécute en mode développement, vous pouvez ouvrir les DevTools en cliquant avec le bouton droit sur la fenêtre de l’application et en sélectionnant Inspecter du menu.
Création de la fonctionnalité de l’application de base
Créons maintenant le squelette de notre application. Remplacer le contenu du App.tsx
fichier avec les éléments suivants :
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 (
<div>
<Grid grow m={10}>
<Grid.Col span="auto">
<Flex gap="xl" justify="flex-start" align="center" wrap="wrap">
<Flex>
<ThemeIcon size="lg" variant="gradient" gradient={{ from: "teal", to: "lime", deg: 90 }}>
<IconNotebook size={32} />
</ThemeIcon>
<Text color="green" fz="xl" fw={500} ml={5}>My Notes</Text>
</Flex>
<Button onClick={addNote} leftIcon={<IconFilePlus />}>Add note</Button>
<Button.Group>
<Button variant="light" leftIcon={<IconFileArrowLeft />}>Import</Button>
<Button variant="light" leftIcon={<IconFileArrowRight />}>Export</Button>
</Button.Group>
</Flex>
<Divider my="sm" />
{notes.map((note, index) => (
<Flex key={index}>
<NavLink onClick={() => handleSelection(note.title, note.content, index)} active={index === active} label={note.title} />
<CloseButton onClick={() => deleteNote(index)} title="Delete note" size="xl" iconSize={20} />
</Flex>
))}
</Grid.Col>
<Grid.Col span={2}>
<Switch label="Toggle Editor / Markdown Preview" checked={checked} onChange={(event) => setChecked(event.currentTarget.checked)}/>
<Divider my="sm" />
{checked === false && (
<div>
<TextInput mb={5} />
<Textarea minRows={10} />
</div>
)}
{checked && (
<Paper shadow="lg" p={10}>
<Text fz="xl" fw={500} tt="capitalize">{title}</Text>
<Divider my="sm" />
<Markdown>{content}</Markdown>
</Paper>
)}
</Grid.Col>
</Grid>
</div>
)
}
export default App
Il y a beaucoup de code ici, alors explorons-le petit à petit.
Importation des packages nécessaires
Au début, nous importons tous les packages nécessaires comme suit :
- Analyseur Markdown
- Composants de la mantine
- un crochet Mantine
- Icônes
- API Taurus
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'
Configuration du stockage et des variables de l’application
Dans la partie suivante, nous utilisons le useLocalStorage
crochet pour configurer le stockage des notes.
Nous définissons également quelques variables pour le titre et le contenu de la note actuelle, et deux autres pour déterminer quelle note est sélectionnée (active
) et si l’aperçu Markdown est activé (checked
).
Enfin, nous créons une fonction utilitaire pour gérer la sélection d’une note. Lorsqu’une note est sélectionnée, elle met à jour les propriétés de la note actuelle en conséquence :
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)
}
Ajout de la fonctionnalité d’ajout/suppression de note
Les deux fonctions suivantes servent à ajouter/supprimer une note.
addNote()
insère un nouvel objet note dans le notes
déployer. Il utilise handleSelection()
pour sélectionner automatiquement la nouvelle note après l’avoir ajoutée. Et enfin il met à jour les notes. La raison pour laquelle nous utilisons l’opérateur de propagation ici est que sinon l’état ne sera pas mis à jour. De cette façon, nous forçons l’état à se mettre à jour et le composant à restituer, afin que les notes s’affichent correctement :
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])
}
}
deleteNote()
utilise le ask
boîte de dialogue pour confirmer que l’utilisateur souhaite supprimer la note et qu’il n’a pas cliqué accidentellement sur le bouton de suppression. Si l’utilisateur confirme la suppression (deleteNote = true
) puis le if
instruction est exécutée :
- la note est supprimée du
notes
déployer - le
active
la variable est mise à jour - le titre et le contenu de la note actuelle sont mis à jour
- le
notes
le tableau est mis à jour
Création du modèle JSX
Dans la section modèle, nous avons deux colonnes.
Dans la première colonne, nous créons le logo et le nom de l’application, ainsi que des boutons pour ajouter, importer et exporter des notes. Nous faisons également une boucle à travers le notes
tableau pour rendre les notes. Ici on utilise handleSelection()
à nouveau pour mettre à jour correctement les propriétés de la note actuelle lorsqu’un lien de titre de note est cliqué :
<Grid.Col span="auto">
<Flex gap="xl" justify="flex-start" align="center" wrap="wrap">
<Flex>
<ThemeIcon size="lg" variant="gradient" gradient={{ from: "teal", to: "lime", deg: 90 }}>
<IconNotebook size={32} />
</ThemeIcon>
<Text color="green" fz="xl" fw={500} ml={5}>My Notes</Text>
</Flex>
<Button onClick={addNote} leftIcon={<IconFilePlus />}>Add note</Button>
<Button.Group>
<Button variant="light" leftIcon={<IconFileArrowLeft />}>Import</Button>
<Button variant="light" leftIcon={<IconFileArrowRight />}>Export</Button>
</Button.Group>
</Flex>
<Divider my="sm" />
{notes.map((note, index) => (
<Flex key={index}>
<NavLink onClick={() => handleSelection(note.title, note.content, index)} active={index === active} label={note.title} />
<CloseButton onClick={() => deleteNote(index)} title="Delete note" size="xl" iconSize={20} />
</Flex>
))}
</Grid.Col>
Dans la deuxième colonne, nous ajoutons un bouton bascule pour basculer entre les modes d’édition de note et de prévisualisation. En mode édition, il y a une entrée de texte pour le titre de la note actuelle et une zone de texte pour le contenu de la note actuelle. En mode aperçu, le titre est rendu par Mantine’s Text
composant, et le contenu est rendu par le marked-react
c’est Markdown
composant:
<Grid.Col span={2}>
<Switch label="Toggle Editor / Markdown Preview" checked={checked} onChange={(event) => setChecked(event.currentTarget.checked)}/>
<Divider my="sm" />
{checked === false && (
<div>
<TextInput mb={5} />
<Textarea minRows={10} />
</div>
)}
{checked && (
<Paper shadow="lg" p={10}>
<Text fz="xl" fw={500} tt="capitalize">{title}</Text>
<Divider my="sm" />
<Markdown>{content}</Markdown>
</Paper>
)}
</Grid.Col>
Phew! C’était beaucoup de code. L’image ci-dessous montre à quoi notre application devrait ressembler à ce stade.
Super! Nous pouvons ajouter et supprimer des notes maintenant, mais il n’y a aucun moyen de les modifier. Nous ajouterons cette fonctionnalité dans la section suivante.
Ajouter le titre d’une note et la fonctionnalité de mise à jour du contenu
Ajoutez le code suivant après le deleteNote()
fonction:
const updateNoteTitle = ({ target: { value } }: { target: { value: string } }) => {
notes.splice(active, 1, { title: value, content: content })
setTitle(value)
setNotes([...notes])
}
const updateNoteContent = ({target: { value } }: { target: { value: string } }) => {
notes.splice(active, 1, { title: title, content: value })
setContent(value)
setNotes([...notes])
}
Ces deux fonctions remplacent respectivement le titre et/ou le contenu de la note en cours. Pour les faire fonctionner, nous devons les ajouter dans le modèle :
<TextInput value={title} onChange={updateNoteTitle} mb={5} />
<Textarea value={content} onChange={updateNoteContent} minRows={10} />
Désormais, lorsqu’une note est sélectionnée, son titre et son contenu seront affichés respectivement dans le texte d’entrée et la zone de texte. Lorsque nous modifions une note, son titre sera mis à jour en conséquence.
J’ai ajouté plusieurs notes pour montrer à quoi ressemblera l’application. L’application avec une note sélectionnée et son contenu est illustrée ci-dessous.
L’image ci-dessous montre l’aperçu de notre note.
Et l’image suivante montre la boîte de dialogue de confirmation qui s’affiche lors de la suppression de la note.
Super! La dernière chose dont nous avons besoin pour rendre notre application vraiment cool est d’ajouter une fonctionnalité pour exporter et importer les notes de l’utilisateur sur le disque dur du système.
Ajout de fonctionnalités pour importer et exporter des notes
Ajoutez le code suivant après le updateNoteContent()
fonction:
const exportNotes = async () => {
const exportedNotes = JSON.stringify(notes)
const filePath = await save({
filters: [{
name: "JSON",
extensions: ["json"]
}]
})
await writeTextFile(`${filePath}`, exportedNotes)
sendNotification(`Your notes have been successfully saved in ${filePath} file.`)
}
const importNotes = async () => {
const selectedFile = await open({
filters: [{
name: "JSON",
extensions: ["json"]
}]
})
const fileContent = await readTextFile(`${selectedFile}`)
const importedNotes = JSON.parse(fileContent)
setNotes(importedNotes)
}
Dans la première fonction, nous convertissons les notes en JSON. Ensuite on utilise le save
boîte de dialogue pour enregistrer les notes. Ensuite, nous utilisons le writeTextFile()
fonction pour écrire le fichier physiquement sur le disque. Enfin, nous utilisons le sendNotification()
fonction pour informer l’utilisateur que les notes ont été enregistrées avec succès et également où elles ont été enregistrées.
Dans la deuxième fonction, nous utilisons le open
boîte de dialogue pour sélectionner un fichier JSON, contenant des notes, à partir du disque. Ensuite, le fichier est lu avec le readTextFile()
fonction, son contenu JSON est converti en objet, et enfin le stockage des notes est mis à jour avec le nouveau contenu.
La dernière chose que nous devons faire est de changer le modèle pour utiliser les fonctions ci-dessus :
<Button variant="light" onClick={importNotes} leftIcon={<IconFileArrowLeft />}>Import</Button>
<Button variant="light" onClick={exportNotes} leftIcon={<IconFileArrowRight />}>Export</Button>
Voici ce que le final App.tsx
déposer devrait ressembler.
Dans les captures d’écran suivantes, vous pouvez voir le Enregistrer sous et Ouvrir les boîtes de dialogue et la notification système apparaissant sous forme de notes sont enregistrées.
Bravo! Vous venez de créer une application de bureau de prise de notes entièrement fonctionnelle avec la puissance de Tauri.
Créer l’application
Maintenant, si tout fonctionne bien et que vous êtes satisfait du résultat final, vous pouvez créer l’application et obtenir un package d’installation pour votre système d’exploitation. Pour ce faire, exécutez la commande suivante :
Conclusion
Dans ce tutoriel, nous avons exploré ce qu’est Tauri, pourquoi c’est un meilleur choix pour créer des applications de bureau natives par rapport à Electron, et enfin comment créer une application Tauri simple mais entièrement fonctionnelle.
J’espère que vous avez apprécié ce court voyage autant que moi. Pour plonger plus profondément dans le monde de Tauri, découvrez son Documentation et continuez à expérimenter avec ses fonctionnalités puissantes.
Lecture connexe :
Source link