블로그 목록
데스크톱TauriRust

Tauri 2.0으로 데스크톱 앱 만들기 — Electron 없이 가볍게

Electron으로 데스크톱 앱을 만들다 보면 번들 크기가 항상 걸린다. Hello World 수준 앱이 100MB를 넘는 건 기본이다. Tauri 2.0을 써보니 같은 기능을 4MB 수준으로 만들 수 있었다.

Tauri vs Electron

Electron은 앱마다 Chromium + Node.js를 번들링한다. 이게 크기의 주범이다.

Tauri는 OS 내장 웹뷰를 쓴다. macOS는 WebKit, Windows는 WebView2, Linux는 WebKitGTK. Node.js 대신 Rust로 백엔드를 짠다. 번들 크기가 극적으로 작아지고, 메모리 사용량도 훨씬 낮다.

단점은 플랫폼마다 렌더링 엔진이 달라서 CSS 호환성 이슈가 생길 수 있다는 거다. 특히 Windows의 WebView2는 Chromium 기반이라 비교적 낫지만, macOS WebKit에서 간간이 렌더링 차이가 보인다.

프로젝트 생성

npm create tauri-app@latest my-app
cd my-app
npm install
npm run tauri dev

프론트엔드 프레임워크는 React, Vue, Svelte, Solid 등 고를 수 있다. 내부적으로 Vite를 쓴다. 구조는 이렇다.

my-app/
├── src/              # 프론트엔드 (React 등)
├── src-tauri/
│   ├── src/
│   │   └── main.rs   # Rust 백엔드 진입점
│   ├── tauri.conf.json
│   └── Cargo.toml

Rust 백엔드 ↔ JS 통신

Tauri에서 Rust 함수를 커맨드로 노출하면 JS에서 호출할 수 있다.

// src-tauri/src/main.rs
#[tauri::command]
fn read_file(path: String) -> Result<String, String> {
    std::fs::read_to_string(&path).map_err(|e| e.to_string())
}

fn main() {
    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![read_file])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

프론트엔드에서는 invoke로 호출한다.

import { invoke } from '@tauri-apps/api/core';

async function loadFile(path: string) {
  try {
    const content = await invoke<string>('read_file', { path });
    console.log(content);
  } catch (err) {
    console.error('파일 읽기 실패:', err);
  }
}

Rust 함수 이름이 snake_case여도 JS에서 그대로 snake_case로 호출한다. Result<T, String> 반환 시 에러가 나면 JS에서 catch로 잡힌다.

권한 시스템 (2.0에서 크게 달라진 부분)

Tauri 2.0에서 가장 많이 헷갈리는 게 권한 시스템이다. 1.x에서는 tauri.conf.jsonallowlist로 열고 싶은 API를 지정했는데, 2.0에서는 세분화된 capabilities 기반으로 바뀌었다.

// src-tauri/capabilities/default.json
{
  "identifier": "default",
  "description": "기본 권한 설정",
  "windows": ["main"],
  "permissions": ["core:default", "fs:read-all", "dialog:open"]
}

파일 시스템, 네트워크, 쉘, 다이얼로그 등 각 도메인별로 권한을 따로 부여한다. 처음엔 복잡해 보이지만 공식 문서에 각 권한 목록이 잘 정리돼 있어서, 필요한 것만 찾아서 추가하면 된다. 보안 측면에서는 1.x보다 훨씬 낫다.

빌드

npm run tauri build

src-tauri/target/release/bundle/에 플랫폼별 설치 파일이 생긴다. macOS는 .dmg, Windows는 .msi.exe, Linux는 .deb.rpm. 크로스 컴파일은 공식적으로 지원하지 않아서, GitHub Actions에서 각 OS별로 빌드하는 방식을 많이 쓴다.

Rust를 모르면 어떻게 하나

솔직히 Rust를 아예 모르면 진입 장벽이 있다. 그런데 Tauri 커맨드 수준에서는 복잡한 Rust 코드가 필요 없는 경우도 많다. 파일 읽기, 시스템 API 호출, 간단한 데이터 처리 정도는 ChatGPT나 Claude에 물어보면서도 충분히 할 수 있다.

무거운 로직은 Rust로 짜고, UI는 그대로 React/Vue를 쓴다는 구조 자체가 역할 분리가 잘 된다. Rust 배우는 게 부담이라도, Electron 번들 크기 문제가 항상 걸렸다면 한 번 써볼 만 하다.


사이드 프로젝트로 간단한 로컬 앱을 만들 때 Tauri를 써봤는데 생각보다 개발 경험이 좋았다. 핫 리로드도 잘 되고, 개발 속도도 Electron이랑 크게 차이 안 났다. 배포 파일 크기가 4MB로 줄어드는 건 확실히 기분 좋다.