Tauri and Puppeteer/Playwright have different use cases. So it seems nothing to compare. But there is (at least) one use case where you may try to use Tuari instead of a headless browser - “snapshots”. For example:
- react-snap - HTML snapshot, uses Puppeteer
- mermaid-cli - SVG/image snapshot, uses Puppeteer
- cytosnap - image snapshot, uses Puppeteer
Why? Because Tauri uses provided by OS browser and produces small binaries (let’s say ~10 MB). While Puppeteer and Playwright need a full browser (let’s say ~200 MB). And Tauri probably can be faster.
Experiment
Let’s see if this will work in practice. For an experiment, I decided to recreate cytosnap
with Tauri. Functionality is trivial:
- read input from file or STDIN (Elements JSON)
- generate a graph with the help of Cytoscape.js
- write result (image from canvas) to file or STDOUT
- and this is supposed to be CLI, not GUI-app
CLI
CLI applications are not a typical use case for Tauri, but it is possible.
Hide window (tauri.conf.json
):
"windows": [{ "visible": false, ...
Hide icon from Dock bar (Mac OS only):
#[cfg(target_os = "macos")] use tauri::ActivationPolicy; tauri::Builder::default() .setup(|app| { #[cfg(target_os = "macos")] app.set_activation_policy(ActivationPolicy::Accessory); Ok(()) })
Add CLI arguments (tauri.conf.json
):
"cli": { "description": "Render graphs on the server side with Cytoscape.js, getting image file as output", "args": [ { "name": "source", "short": "s", "takesValue": true, "multiple": false, "multipleOccurrences": false }, { "name": "destination", "short": "d", "takesValue": true, "multiple": false, "multipleOccurrences": false } ], },
Overcome security fences
Because Tauri’s main use case is GUI, they care about security and limit what files/folders the application can access. Which doesn’t work for the way people use CLI. So I had to write my own Tauri commands to write and read files, for example:
#[tauri::command] fn write_destination(dst: String, res: String) -> Result<String, String> { if dst == "" { print!("{}", res); Ok(String::from("ok")) } else { let bytes = base64::engine::general_purpose::STANDARD.decode(res); let path = absolute_path(PathBuf::from(dst)).unwrap(); match bytes { std::result::Result::Ok(v) => { std::fs::write(path, v).unwrap(); Ok(String::from("ok")) } std::result::Result::Err(e) => Err(e.to_string()), } } }
Note : I need to pass binary data from the front end to the rust, so I use Base64.
Distribution
Initially, I wanted to distribute this CLI as binary inside the npm package. But then I realized that Tauri can’t really produce portable binaries. Tauri relies on the OS’s browser - which is a neat trick to shrink down the size of the binary, but this is what makes it less portable. Trade-offs as always.
Not to stop an experiment I decided to distribute at least binary for Mac OS in npm. And it works (Mac OS only):
npx @stereobooster/cyto-snap -s g2.json -d g2.png
Size of the npm package
npm notice package size: 2.9 MB npm notice unpacked size: 7.4 MB
I didn’t do any Tauri optimizations, so it probably can be smaller. Also, this is Mac OS-only binary, it will be bigger if we pack binaries for all platforms in one npm package.
And it has 0 dependencies.
Source code
Warning : because this is an experiment, I didn’t try to make it perfect. Just made it work.
Source code: https://github.com/stereobooster/cyto-snap
Next steps
Homebrew
The idea of distributing binary in npm failed, so I think to try to distribute it via Homebrew. Homebrew works on Mac OS, Windows (WSL 2), and Linux (though they have their own package managers).
- Produce standard desktop installers for Tauri (
tauri-apps/tauri-action
) - Upload installers to GitHub releases
- Run installers in silent mode with the Homebrew formula
Full automation with GitHub Actions
It has a lot of steps to produce the final package. I started automation but didn’t finish it. Ideally, it should:
- Build application
- Run tests (I do integration tests with odiff)
- Create a tag and push it
- Create release and upload all binaries
- Update the Homebrew formula and publish it
- Publish the npm package (but it is not very useful without portable binaries)
Conclusion
- This approach may work with Homebrew distribution
- It is sad that you can’t publish binaries to npm, which would make JS-developer use other means to install it (Homebrew, apt-get, cURL, etc)
- On the other hand, it is fully independent of npm (and Node.js ecosystem in general), so can be used by none-JS developers
- This was my first time using Tauri, and it is awesome
Top comments (0)