Table of Contents
API
The Tauri API is a set of opt-in tools that you can enable in order to do things like read and write from the filesystem and pass messages back and forth between the WebView and Rust. There are two parts to it, the Rust API and the JS API. The former is consumed in your src-tauri/src/main.rs file, and the latter is available at either the window.tauri object or just tauri - depending on your integration technique.
Installation
If you want to use the API, you will need to first enable the parts of the API that you want to use by "whitelisting" them:
Whitelist
"tauri": {
"whitelist": { // all whitelist values are default:false
"all": false, // use this flag to enable all API features
"answer": false, // enable rust to direct the UI
"event": false, // enable listening to messages from webview
"execute": false, // enable binary execution
"listFiles": false, // get a list of files in a directory
"open": false, // open link in the user's default browser
"readBinaryFile": false, // read binary file from local filesystem
"readTextFile": false, // read text file from local filesystem
"setTitle": false, // set the webview window title
"writeFile": false // write file to local filesystem
}
}
Then you will have to choose how to integrate it into your UI. There are two suggested methods:
- Use the webpack plugin (tighter integration, more complicated)
- Inject the official helper (easier)
Webpack Plugin
Webpack will take care of everything for you, so after you have this done right, you can use window.tauri wherever you need to.
Installation
yarn add @tauri-apps/tauri-webpack
Integration
In your webpack config, add the following:
chainWebpack (chain) {
require('@tauri-apps/tauri-webpack').chain(chain, {
tauriLazyLoading: !ctx.dev
})
}
Official Helper
Somewhat easier is to add tauri to the dev dependencies of your project:
yarn add --dev tauri
and then import the Tauri api in the file where you want to consume the Tauri API (or in some other rigging location):
import tauri from 'tauri/api'
JS API
Here is the JS API, exposed by the tauri package in the "api" directory.
Dialog
import { open, save } from 'tauri/api/dialog'
Functions
open(options?: undefined | {}): Promise<string | string[]>
Open a file/directory selection dialog
-
Arguments
- options: undefined | {} = {}
-
Returns Promise<string | string[]>
promise resolving to the select path(s)
save(options?: undefined | {}): Promise<string>
Open a file/directory save dialog
-
Arguments
- options: undefined | {} = {}
-
Returns Promise
promise resolving to the select path
Event
import { emit, listen } from 'tauri/api/event'
Functions
emit(event: string, payload: undefined | string): void
Emits an event to the backend
-
Arguments
-
event: string
the event name
-
payload: undefined | string
-
-
Returns void
listen(event: string, handler: {}): void
Listen to an event from the backend
- Arguments
-
event: string
the event name
-
handler: {}
the event handler callback
-
- Returns void
File system
import {
Dir,
copyFile,
createDir,
readBinaryFile,
readDir,
readTextFile,
removeDir,
removeFile,
renameFile,
writeFile
} from 'tauri/api/fs'
Members
Dir
{
Audio: 1,
Cache: 2,
Config: 3,
Data: 4,
LocalData: 5,
Desktop: 6,
Document: 7,
Download: 8,
Executable: 9,
Font: 10,
Home: 11,
Picture: 12,
Public: 13,
Runtime: 14,
Template: 15,
Video: 16,
Resource: 17,
App: 18
}
Functions
copyFile(source: string, destination: string, options?: undefined | {}): Promise<void>
-
Arguments
- source: string
- destination: string
- options: undefined | {} = {}
-
Returns Promise
createDir(dir: string, options?: undefined | {}): Promise<void>
Creates a directory if one of the path's parent components doesn't exist and the recursive option isn't set to true, it will be rejected
-
Arguments
-
dir: string
path to the directory to create
-
options: undefined | {} = {}
-
-
Returns Promise
readBinaryFile(filePath: string, options?: undefined | {}): Promise<any[]>
Reads a file as binary
-
Arguments
-
filePath: string
path to the file
-
options: undefined | {} = {}
-
-
Returns Promise<any[]>
readDir(dir: string, options?: undefined | {}): Promise<{}[]>
List directory files
-
Arguments
-
dir: string
path to the directory to read
-
options: undefined | {} = {}
-
-
Returns Promise<{}[]>
readTextFile(filePath: string, options?: undefined | {}): Promise<string>
Reads a file as text
-
Arguments
-
filePath: string
path to the file
-
options: undefined | {} = {}
-
-
Returns Promise
removeDir(dir: string, options?: undefined | {}): Promise<void>
Removes a directory if the directory is not empty and the recursive option isn't set to true, it will be rejected
-
Arguments
-
dir: string
path to the directory to remove
-
options: undefined | {} = {}
-
-
Returns Promise
removeFile(file: string, options?: undefined | {}): Promise<void>
Removes a file
-
Arguments
-
file: string
path to the file to remove
-
options: undefined | {} = {}
-
-
Returns Promise
renameFile(oldPath: string, newPath: string, options?: undefined | {}): Promise<void>
Renames a file
-
Arguments
- oldPath: string
- newPath: string
- options: undefined | {} = {}
-
Returns Promise
writeFile(file: {}, options?: undefined | {}): Promise<void>
writes a text file
-
Arguments
- file: {}
- options: undefined | {} = {}
-
Returns Promise
Process
import { execute } from 'tauri/api/process'
Functions
execute(command: string, args: undefined | string | string[]): Promise<string>
Spawns a process
-
Arguments
-
command: string
the name of the cmd to execute e.g. 'mkdir' or 'node'
-
args: undefined | string | string[]
-
-
Returns Promise
promise resolving to the stdout text
Window
import { open, setTitle } from 'tauri/api/window'
Functions
open(url: string): void
opens an URL on the user default browser
-
Arguments
-
url: string
the URL to open
-
-
Returns void
setTitle(title: string): void
sets the window title
-
Arguments
-
title: string
the new title
-
-
Returns void
Example API integration
In our kitchensink, you may find a complete collection (written in ES5) of ways to interact with Tauri's JS API.
Let's review some of them here:
Events and communication
With Tauri, you can emit and listen to events or even send messages with a message handler (see communication.js):
Events - JS side
// Register a listener to the "rust-event" event
window.tauri.listen('rust-event', function (res) {
document.getElementById('response').innerHTML = JSON.stringify(res)
})
// Emit an event "js-event" with a string as payload
window.tauri.emit('js-event', 'this is the payload string')
Events - Rust side
// Register a listener to the "js-event" event
tauri::event::listen(String::from("js-event"), move |msg| {
println!("got js-event with message '{:?}'", msg);
let reply = Reply {
data: "something else".to_string(),
};
// Emit an event "rust-event" with a stringified Reply instance
tauri::event::emit(
&handle,
String::from("rust-event"),
Some(serde_json::to_string(&reply).unwrap()),
);
});
Message handler for Rust-side command execution
Here's how's achieved the command execution, JS side
// Tauri will invoke the "logOperation" command
window.tauri.invoke({
cmd: "logOperation",
event: "tauri-click",
payload: "this payload is optional because we used Option in Rust"
});
// promisified will use invoke but with a promise
window.tauri
.promisified({
cmd: "performRequest",
endpoint: "dummy endpoint arg",
body: {
id: 5,
name: "test"
}
})
.then(registerResponse)
.catch(registerResponse);
And here's the Rust part. Note that it's a sample, the following code should live inside the invoke_handler function call but has been skipped for readability purpose:
use cmd::Cmd::*;
match serde_json::from_str(arg) {
Err(e) => {
Err(e.to_string())
}
Ok(command) => {
match command {
LogOperation { event, payload } => {
println!("{} {:?}", event, payload);
},
PerformRequest { endpoint, body, callback, error } => {
// tauri::execute_promise is a helper for APIs that uses the tauri.promisified JS function
// so you can easily communicate between JS and Rust with promises
tauri::execute_promise(
_webview,
move || {
println!("{} {:?}", endpoint, body);
// perform an async operation here
// if the returned value is Ok, the promise will be resolved with its value
// if the returned value is Err, the promise will be rejected with its value
// the value is a string that will be eval'd
Ok("{ key: 'response', value: [{ id: 3 }] }".to_string())
},
callback,
error
)
},
}
Ok(())
}
}
Notice that the command names have been normalized: it has been changed from camelCase in JS to PascalCase in Rust.
File system
Tauri provides a file system API that you can leverage to handle files from your machine.
Here's a sample from fs.js:
var pathToRead = pathInput.value
var isFile = pathToRead.match(/\S+\.\S+$/g)
// Tauri will try to read a file or a directory; those functions return a Promise
var promise = isFile ? window.tauri.readBinaryFile(pathToRead) : window.tauri.readDir(pathToRead)
promise.then(function (response) {
if (isFile) {
if (pathToRead.includes('.png') || pathToRead.includes('.jpg')) {
arrayBufferToBase64(new Uint8Array(response), function (base64) {
var src = 'data:image/png;base64,' + base64
registerResponse('<img src="' + src + '"></img>')
})
} else {
var value = String.fromCharCode.apply(null, response)
registerResponse('<textarea id="file-response" style="height: 400px"></textarea><button id="file-save">Save</button>')
var fileInput = document.getElementById('file-response')
fileInput.value = value
document.getElementById('file-save').addEventListener('click', function () {
window.tauri.writeFile({
file: pathToRead,
contents: fileInput.value
}).catch(registerResponse)
})
}
} else {
registerResponse(response)
}
}).catch(registerResponse)