跳转到主要内容

WRITING

From Streamlit to Tauri: Bringing Water Engineering Tools to the Desktop

April 10, 20263 min readTianli Zeng
developer-toolstauriindie-devstreamlitreact
From Streamlit to Tauri: Bringing Water Engineering Tools to the Desktop

Background

Computational tools in the water conservancy industry come with one peculiar requirement: many users work in environments without internet access (think field surveys at remote sites). The Streamlit version was quick to build, but it can only be used online.

So I started a Streamlit → Tauri migration plan, with the goal of progressively turning 12 hydro-* water computation tools into desktop applications.

Migration Strategy

It's Not a Rewrite — It's a Separation

The core idea is to separate the compute engine from the UI:

Streamlit coupled monolith vs. Tauri three-layer architecture: the compute engine is extracted as-is, only the UI layer is rewritten
Migration is separation, not a rewrite: the Python compute engine is lifted out of the monolith unchanged — the only real rewrite is the UI, with React replacing Streamlit and a Rust backend calling the same engine through a sidecar.

Three Phases

  1. Extract the compute engine: peel the core computational logic out of the Streamlit code into an independent Python module
  2. Rewrite the frontend in React: replicate the Streamlit interface with shadcn/ui, keeping functional parity
  3. Tauri integration: the Rust backend invokes the Python compute engine through a sidecar
Three-step migration route: extract the compute engine, rewrite the frontend in React, integrate with Tauri; 2 of 12 tools done
The order is what matters: once the compute engine is cleanly extracted, the React rewrite and Tauri integration become routine work. 2 of the 12 hydro-series tools have completed this route.

Pitfalls

By default, rsync doesn't follow symlinks during deployment, which causes linked files inside node_modules to disappear.

Fix: rsync -aL (the L flag follows symlinks).

2. Native modules

Native modules like better-sqlite3 behave differently inside Tauri's sidecar environment.

Fix: keep the compute layer pure Python and avoid native modules on the frontend.

3. Webpack crash

Some React components cause webpack memory blowups inside Tauri's webview.

Fix: split chunks and lazy-load the heavy components.

4. CSS hash mismatch

When the standalone build and the static files come from different builds, CSS filenames carry different hashes — and styles vanish.

Fix: rm -rf .next before every deploy to guarantee both come from the same build.

Migration Progress

Two tools have been migrated so far:

  • hydro-capacity: Pollutant Assimilation Capacity calculator
  • hydro-efficiency: Water Efficiency Assessment system

Each tool ships as both web and desktop. The web version runs on the VPS; the desktop version works offline.

Lessons Learned

  1. A standalone compute engine is the key — the difficulty and risk of migration sit in the UI, not the math
  2. Don't aim for one-shot completion — migrate the most-used tool first, validate the pattern, then scale up
  3. Tauri is far lighter than Electron — packaged binaries are tens of MB instead of 100+ MB
  4. Keep the web version online — desktop is a complement, not a replacement
Bundle size comparison: Tauri around 10 MB vs. Electron over 100 MB — an order of magnitude apart
An order-of-magnitude gap in bundle size: Tauri ships at around 10 MB while Electron routinely exceeds 100 MB — a direct reason to pick Tauri when distributing desktop tools to offline environments.

FOLLOW

New posts land here first. Subscribe via RSS: /feed.xml

AUTHOR

Tianli Zeng

Hydraulic engineer. I write about AI methodology, daily investment reviews, and engineering practice.

Found a mistake, or have something to add?