[3] Tauri Tutorial (button을 통해 프론트엔드와 백엔드를 연결해보자)

2025. 5. 3. 13:10Tauri/Tutorial

우선 Tauri 프로젝트를 생성하고,
src 폴더에서 frontend를 만들어보자

Frontend

src/index.html

<html>

  <button onclick="doLogin()">Login</button>

  <button onclick="getUser()">Get User</button>

  <script>
    const invoke = window.__TAURI__.core.invoke;

    async function doLogin() {
      let result = await invoke("do_login", { username : "test", password : "qwer1234"});
      console.log(result);
    }

    async function getUser() {
      let user = await invoke("get_user");
      console.log(user);
    }
  </script>
</html>

코드 설명

click 버튼을 두 개 만들었다.
Login 버튼에는 doLogin() 함수를, Get User 버튼에는 getUser() 함수를 심었다.

<script> 블럭을 살펴보겠다.

const invoke = window.__TAURI__.core.invoke;

Tauri 프레임워크에서 Rust 백엔드와 JS 프론트엔드 간의 통신을 위한 핵심 함수를 가져온다.

window.__TAURI__ : Tauri 프레임워크가 제공하는 전역 객체
.core.invoke : Rust 백엔드의 함수를 호출할 수 있는 매서드

=> Rust 백엔드 함수를 호출하겠다. 라는 의미가 된다.

async function doLogin() {
      let result = await invoke("do_login", { username : "test", password : "qwer1234"});
      console.log(result);
    }

doLogin()과 getUser() 함수는 거의 비슷한 형태이니 doLogin만 설명하겠다.

js로 doLogin() 함수를 만들고, result 변수에 invoke("~")를 호출해 값을 저장한다.
await은 비동기 호출을 기다린다는 의미.
console.log(result)는 콘솔창에 결과값을 출력한다.

=> Rust 백엔드의 "do_login" 함수를 호출하며 { } 안의 내용은 짐작하겠지만
함수 입력 파라미터가 된다.

그럼 do_login 함수는 Rust로 입력 파라미터에 따라 결과를 출력하게 구성하면 된다.

Backend

src-tauri/src/lib.rs

use std::sync::Mutex;
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .manage(Mutex::new(User {
            id : 0, 
            username : "".to_string(), 
            password : "".to_string()
        }))
        .plugin(tauri_plugin_opener::init())
        .invoke_handler(tauri::generate_handler![get_user, do_login])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

#[tauri::command]
fn get_user(state : tauri::State<Mutex<User>>) -> User{
    let user = &*state.lock().unwrap();

    user.clone()
}

#[tauri::command]
fn do_login(state : tauri::State<Mutex<User>>,username : String, password : String) -> bool{

    *state.lock().unwrap() = User { username, password, id : 1};
    true
}

#[derive(serde::Serialize, Clone)]
struct User {
    id : u32,
    username : String,
    password : String
}

코드 설명

우선 User structure부터 보자.

#[derive(serde::Serialize, Clone)]
struct User {
    id : u32,
    username : String,
    password : String
}

User 라는 이름의 structure를 정의했다.
내부 파라미터는 id, username, password 이다.
#[derive()]는 Rust의 attribute이다. 인터넷에서 rust attribute 혹은 rust macro를 공부해보자.

=> Serialize, Clone 생성이 가능한 User structure 정의

메인 함수를 살펴보자.

pub fn run() {
    tauri::Builder::default()
        .manage(Mutex::new(User {
            id: 0, 
            username: "".to_string(), 
            password: "".to_string()
        }))
        .plugin(tauri_plugin_opener::init())
        .invoke_handler(tauri::generate_handler![get_user, do_login])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

메인 함수는 기본적으로 쓰여진 것이 있을 것이다.
추가한 것은 .manage, .invoke_handler 정도

.manage() 매서드를 좀 더 살펴보자.

.manage(Mutex::new(User {
            id: 0, 
            username: "".to_string(), 
            password: "".to_string()
        }))

.manage() 매서드는 전역 상태를 등록하는 역할을 한다.
앱 전체에서 접근 가능한 상태를 관리한다고 볼 수 있다.

Mutex::new 는 Mutual Exclusion의 약자이다.
한 번에 하나의 스레드만 데이터에 접근 가능하게 하는 lock 매커니즘이다.
이를 통해 스레드를 안전한 동시성 제어를 할 수 있다.

이를 사용하기 위해 맨 윗 줄에
use std::sync::Mutex;를 헤더로 불러왔다.

=> User를 Mutex 매커니즘으로 초기화하여 전역 상태 등록 및 관리

.invoke_handler(tauri::generate_handler![get_user, do_login])

딱 감이 오지 않는가.
[ ] 안의 함수를 invoke할 수 있게 하는 매서드이다.

이제 get_user 함수를 보자

#[tauri::command]
fn get_user(state : tauri::State<Mutex<User>>) -> User{
    let user = &*state.lock().unwrap();

    user.clone()
}

#[tauri::command]는 Rust 함수를 JS에서 호출 가능하게 하는 attribute macro

state : tauri::State<Mutex<User>>

Tauri State로 User를 안전하게 받는다.

함수 내용은 입력 state를 클론 복제하여 user.clone() 반환값을 가진다.

do_login 함수도 비슷하다.
do_login 함수를 보면 무조건 true를 반환하게 되어있다.

결과물

cargo tauri dev를 통해 빌드 및 실행하자.

Login 버튼을 누르면 true 값이, Get User 버튼을 누르면 User structure가 반환된다.