docs.sheetjs.com/docz/docs/03-demos/06-desktop/04-tauri.md
2023-09-26 00:26:16 -04:00

12 KiB

title sidebar_label description pagination_prev pagination_next sidebar_position sidebar_custom_props
Data Wrangling in Tauri Apps Tauri Build data-intensive desktop apps using Tauri. Seamlessly integrate spreadsheets into your app using SheetJS. Modernize Excel-powered business processes with confidence. demos/mobile/index demos/data/index 4
summary
Webview + Rust Backend

Data Wrangling in Tauri Apps

import current from '/version.js'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock';

Tauri is a modern toolkit for building desktop apps. Tauri apps leverage platform-native browser engines to build lightweight programs.

SheetJS is a JavaScript library for reading and writing data from spreadsheets.

This demo uses Tauri and SheetJS to pull data from a spreadsheet and display the data in the app. We'll explore how to load SheetJS in a Tauri app and exchange file data between the JavaScript frontend and Rust backend.

The "Complete Example" section covers a complete desktop app to read and write workbooks. The app will look like the screenshots below:

Win10 macOS Linux

Win10 screenshot

macOS screenshot

Linux screenshot

Integration Details

The SheetJS NodeJS Module can be installed and imported from JavaScript code.

:::note pass

Tauri currently does not provide the equivalent of NodeJS fs module. The raw @tauri-apps/api methods used in the examples are not expected to change.

:::

For security reasons, Tauri apps must explicitly enable system features.1 They are enabled in src-tauri/tauri.conf.json in the allowlist subsection of the tauri section of the config.

  • The fs entitlement2 enables reading and writing file data.
  "tauri": {
    "allowlist": {
      //highlight-start
      "fs": {
        "all": true
      }
      // highlight-end
  • The dialog entitlement3 enables the open and save dialog methods.
  "tauri": {
    "allowlist": {
      //highlight-start
      "dialog": {
        "all": true
      }
      // highlight-end
  • The http entitlement4 enables downloading files. Note that http is not needed for reading or writing files in the local filesystem.
  "tauri": {
    "allowlist": {
      //highlight-start
      "http": {
        "all": true,
        "request": true,
        "scope": ["https://**"]
      }
      // highlight-end

Reading Files

There are three steps to reading files:

  1. Show an open file dialog to allow users to select a path. The open method in @tauri-apps/api/dialog5 simplifies this process.

  2. Read raw data from the selected file using the readBinaryFile method in @tauri-apps/api/fs6. This method resolves to a standard Uint8Array

  3. Parse the data with the SheetJS read method7. This method returns a SheetJS workbook object.

The following code example defines a single function openFile that performs all three steps and returns a SheetJS workbook object:

import { read } from 'xlsx';
import { open } from '@tauri-apps/api/dialog';
import { readBinaryFile } from '@tauri-apps/api/fs';

const filters = [
  {name: "Excel Binary Workbook", extensions: ["xlsb"]},
  {name: "Excel Workbook", extensions: ["xlsx"]},
  {name: "Excel 97-2004 Workbook", extensions: ["xls"]},
  // ... other desired formats ...
];

async function openFile() {
  /* show open file dialog */
  const selected = await open({
    title: "Open Spreadsheet",
    multiple: false,
    directory: false,
    filters
  });

  /* read data into a Uint8Array */
  const d = await readBinaryFile(selected);

  /* parse with SheetJS */
  const wb = read(d);
  return wb;
}

At this point, standard SheetJS utility functions8 can extract data from the workbook object. The demo includes a button that calls sheet_to_json9 to generate an array of arrays of data. The following snippet uses VueJS framework but the same logic works with ReactJS and other front-end frameworks:

import { utils } from 'xlsx';
import { shallowRef } from 'vue';
const data = shallowRef([[]]); // update data by setting `data.value`

const open_button_callback = async() => {
  const wb = await openFile();

  /* get the first worksheet */
  // highlight-start
  const ws = wb.Sheets[wb.SheetNames[0]];
  // highlight-end

  /* get data from the first worksheet */
  // highlight-start
  const array = utils.sheet_to_json(ws, { header: 1 });
  // highlight-end
  data.value = array;
};

Writing Files

There are three steps to writing files:

  1. Show a save file dialog to allow users to select a path. The save method in @tauri-apps/api/dialog10 simplifies this process.

  2. Write the data with the SheetJS write method11. The output book type can be inferred from the selected file path. Using the buffer output type12, the method will return a Uint8Array object that plays nice with Tauri.

  3. Write the data using writeBinaryFile in @tauri-apps/api/fs13.

The following code example defines a single function saveFile that performs all three steps starting from a SheetJS workbook object:

import { write } from 'xlsx';
import { save } from '@tauri-apps/api/dialog';
import { writeBinaryFile } from '@tauri-apps/api/fs';

const filters = [
  {name: "Excel Binary Workbook", extensions: ["xlsb"]},
  {name: "Excel Workbook", extensions: ["xlsx"]},
  {name: "Excel 97-2004 Workbook", extensions: ["xls"]},
  // ... other desired formats ...
];

async function saveFile(wb) {
  /* show save file dialog */
  const selected = await save({
    title: "Save to Spreadsheet",
    filters
  });
  if(!selected) return;

  /* Generate workbook */
  const bookType = selected.slice(selected.lastIndexOf(".") + 1);
  const d = write(wb, {type: "buffer", bookType});

  /* save data to file */
  await writeBinaryFile(selected, d);
}

The demo includes a button that calls aoa_to_sheet14 to generate a sheet from array of arrays of data. A workbook is constructed using book_new and book_append_sheet15. The following snippet uses VueJS framework but the same logic works with ReactJS and other front-end frameworks:

import { utils } from 'xlsx';
import { shallowRef } from 'vue';
const data = shallowRef([[]]); // `data.value` is an array of arrays

const save_button_callback = async() => {
  /* generate worksheet from the data */
  // highlight-start
  const ws = utils.aoa_to_sheet(data.value);
  // highlight-end

  /* create a new workbook object */
  // highlight-start
  const wb = utils.book_new();
  // highlight-end

  /* append the worksheet to the workbook using the sheet name "SheetJSTauri" */
  // highlight-start
  utils.book_append_sheet(wb, ws, "SheetJSTauri");
  // highlight-end

  await saveFile(wb);
}

Complete Example

:::note pass

This demo was tested in the following environments:

OS and Version Arch Tauri Date
macOS 13.4.0 x64 v1.4.0 2023-06-25
macOS 13.4.1 ARM v1.4.0 2023-06-29
Windows 10 x64 v1.4.1 2023-07-30
Linux (HoloOS) x64 v1.4.1 2023-07-30

:::

  1. Read Tauri "Getting Started" guide and install prerequisites.16
Installation Notes (click to show)

At a high level, the following software is required for building Tauri apps:

  • a native platform-specific C/C++ compiler (for example, macOS requires Xcode)
  • a browser engine integration (for example, linux requires webkit2gtk)
  • Rust

The platform configuration can be verified by running:

npx @tauri-apps/cli info

If required dependencies are installed, the output will show a checkmark next to "Environment". The output from the most recent macOS test is shown below:

[✔] Environment
    - OS: Mac OS 13.4.0 X64
    ✔ Xcode Command Line Tools: installed
    ✔ rustc: 1.70.0 (90c541806 2023-05-31)
    ✔ Cargo: 1.70.0 (ec8a8a0ca 2023-04-25)
    ✔ rustup: 1.26.0 (5af9b9484 2023-04-05)
    ✔ Rust toolchain: stable-x86_64-apple-darwin (default)
    - node: 18.16.1
    - npm: 9.5.1

:::caution pass

When the demo was last tested on ARM64 macOS, the output mentioned X64. The build step will correctly detect the platform architecture.

:::

  1. Create a new Tauri app:
npm create tauri-app

When prompted:

  • Project Name: SheetJSTauri
  • Choose which language to use for your frontend: TypeScript / JavaScript
  • Choose your package manager: npm
  • Choose your UI template: Vue
  • Choose your UI flavor: TypeScript
  1. Enter the directory and install dependencies:

{\ cd SheetJSTauri npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz npm i --save @tauri-apps/api npm i --save-dev @tauri-apps/cli}

  1. Add the highlighted lines to src-tauri/tauri.conf.json in the tauri.allowlist section:
  "tauri": {
    "allowlist": {
// highlight-start
      "http": {
        "all": true,
        "request": true,
        "scope": ["https://**"]
      },
      "dialog": {
        "all": true
      },
      "fs": {
        "all": true
      },
// highlight-end

In the same file, look for the "identifier" key and replace the value with com.sheetjs.tauri:

        "icons/icon.ico"
      ],
      // highlight-next-line
      "identifier": "com.sheetjs.tauri",
      "longDescription": "",
  1. Download App.vue and replace src/App.vue with the downloaded script.
curl -o src/App.vue https://docs.sheetjs.com/tauri/App.vue
  1. Build the app with
npm run tauri build

At the end, it will print the path to the generated program. If the program path is not listed, it is typically found in the src-tauri/target/release folder.

:::info pass

During the last Linux test, the build had failed with an error:

'openssl/opensslv.h' file not found

This error was resolved installing OpenSSL. On Arch Linux and HoloOS:

sudo pacman -S openssl

:::

  1. Run the program. The following features should be manually verified:
  • When it is opened, the app will download https://sheetjs.com/pres.numbers and display the data in a table.
  • Clicking "Save Data" will show a save dialog. After selecting a path and name, the app will write a file. That file can be opened in a spreadsheet editor.
  • Edit the file in a spreadsheet editor, then click "Load Data" and select the edited file. The table will refresh with new contents.

  1. See "Security" in the Tauri documentation ↩︎

  2. See FsAllowlistConfig in the Tauri documentation ↩︎

  3. See DialogAllowlistConfig in the Tauri documentation ↩︎

  4. See HttpAllowlistConfig in the Tauri documentation ↩︎

  5. See dialog in the Tauri documentation ↩︎

  6. See fs in the Tauri documentation ↩︎

  7. See read in "Reading Files" ↩︎

  8. See "Utility Functions" ↩︎

  9. See "Array Output" in "Utility Functions" ↩︎

  10. See dialog in the Tauri documentation ↩︎

  11. See write in "Writing Files" ↩︎

  12. See "Supported Output Formats" ↩︎

  13. See fs in the Tauri documentation ↩︎

  14. See "Array of Arrays Input" in "Utility Functions" ↩︎

  15. See "Workbook Helpers" in "Utility Functions" ↩︎

  16. See "Prerequisites" in the Tauri documentation ↩︎