WSL-UI 구축: 타우리와 함께하는 크리스마스 프로젝트
Source: Dev.to
위 링크에 있는 전체 텍스트를 제공해 주시면, 해당 내용을 한국어로 번역해 드리겠습니다. (코드 블록, URL 및 기술 용어는 그대로 유지합니다.)
소개
크리스마스에 여유 시간이 생겨서 뭔가 새로운 것을 시도해보고 싶었습니다. 저는 평소에 DevOps—파이프라인, 인프라 등—를 담당하고 있지만, 제대로 된 데스크톱 앱, 즉 Windows에서 WSL2 배포판을 시각적으로 관리할 수 있는 툴을 만들고 싶었습니다.
WSL2를 어느 정도 사용해 본 사람이라면 여러 배포판(우분투, 데비안, 알파인 등)을 오가며 명령줄을 외우는 번거로움을 잘 알고 있을 겁니다:
wsl --list --verbose
wsl --terminate Ubuntu
wsl --export Ubuntu ./ubuntu-backup.tar
wsl --import NewDistro C:\WSL\NewDistro ./some-rootfs.tar
이렇게 명령어로도 할 수는 있지만, 실행 중인 상태, 메모리 사용량을 보여주고 클릭만으로 일반적인 작업을 수행할 수 있는 시각적인 도구가 있다면 훨씬 더 편리할 것입니다.
왜 Tauri?
웹 기술을 사용한 크로스‑플랫폼 데스크톱 앱을 생각하면 Electron이 가장 흔한 선택이지만, 각 앱이 자체 Chromium과 Node.js 런타임을 포함해 부피가 크다는 단점이 있습니다. 그래서 간단한 “Hello World”조차도 약 150 MB가 될 수 있습니다.
Tauri는 다른 접근 방식을 취합니다:
- Native WebView – 운영 체제의 WebView(Windows에서는 WebView2)를 사용하며, 앱 간에 공유됩니다.
- Rust backend – 작은 네이티브 바이너리로 컴파일됩니다.
- Size – Tauri 앱은 10 MB 이하가 될 수 있으며, 제가 만든 포터블 실행 파일은 약 4 MB입니다.
다른 이유들:
- Learning Rust – Rust 언어를 제대로 배우고 싶었습니다.
- Native Windows integration – Windows API와 셸 명령을 쉽게 호출할 수 있습니다.
- Security model – 프론트엔드는 명시적으로 허용된 백엔드 함수만 호출할 수 있습니다.
기술 스택
프론트엔드
| 기술 | 이유 |
|---|---|
| React 19 + TypeScript | 정적 타입을 제공하는 최신 UI 프레임워크 |
| Zustand | 간단한 상태 관리, Redux보다 추상화가 적음 |
| Tailwind CSS 4 | 유틸리티‑우선 스타일링, 빠른 반복 |
| Vite | 번개처럼 빠른 빌드 툴체인 |
백엔드
| 크레이트 / 라이브러리 | 목적 |
|---|---|
| Tauri 2.5 | 데스크톱 앱용 Rust 프레임워크 |
wsl-core (custom) | WSL 출력 파싱 |
winreg | Windows 레지스트리 접근(이름 변경에 필요) |
reqwest | OCI 레지스트리 풀을 위한 HTTP 클라이언트 |
테스트
- Vitest – 프론트엔드 단위 테스트.
- WebdriverIO with Tauri Driver – 엔드‑투‑엔드 테스트.
첫 번째 구현: 배포 목록 가져오기
초기 버전은 단순히 배포 목록을 나열하고 상태를 표시했습니다. Tauri의 명령 시스템 덕분에 이를 간단히 구현할 수 있었습니다.
Rust 측
#[tauri::command]
pub async fn list_distributions() -> Result, String> {
// Run `wsl --list --verbose` and parse the output
let output = std::process::Command::new("wsl")
.args(["--list", "--verbose"])
.output()
.map_err(|e| e.to_string())?;
// Parse and return
parse_wsl_list(&output.stdout)
}
React 측
import { invoke } from '@tauri-apps/api/core';
import { useState, useEffect } from 'react';
interface Distribution {
name: string;
state: string;
version: number;
// …other fields
}
export function useDistributions() {
const [distributions, setDistributions] = useState([]);
useEffect(() => {
async function loadDistributions() {
const distros = await invoke('list_distributions');
setDistributions(distros);
}
loadDistributions();
}, []);
return distributions;
}
복잡한 IPC 설정이나 직렬화 보일러플레이트가 필요하지 않았습니다—Tauri가 JavaScript와 Rust 사이의 다리를 처리합니다.
기능 성장
목록 보기 뒤에 다음을 추가했습니다:
- 리소스 모니터링 – 메모리 사용량, CPU 비율, 디스크 크기.
- 배포 관리 – 시작, 중지, 종료, 기본값 설정.
- 가져오기/내보내기 – 배포를 tar 파일로 백업 및 복원.
- 컨테이너 가져오기 – 레지스트리에서 OCI 이미지를 직접 풀링.
- 이름 바꾸기 – 배포 이름을 변경 (Windows 레지스트리 수정을 포함).
- 맞춤 작업 – 배포별 사용자 정의 셸 명령.
러스트 도전 과제
Rust의 빌림 검사기가 저를 반복해서 잡아냈지만, 코드가 컴파일되면 보통 제대로 동작했습니다. 다른 언어에서 흔히 발생하던 버그—널 포인터, 레이스 컨디션, 사용‑후‑해제—는 단순히 발생하지 않았습니다.
개발 중에 Tauri 2.0이 출시되어 1.x에서 2.x로 마이그레이션하게 되었습니다. 과정은 대부분 간단했지만, 몇몇 API가 변경되고 플러그인 시스템이 전면 개편되었습니다.
Frontend Reflections
React은 React이고, Tailwind는 스타일링을 빠르게 해줍니다. Zustand는 수년간 Redux를 사용한 뒤 신선한 공기 같은 느낌이었습니다—상태와 함수만으로 스토어를 만들고, 액션/리듀서/미들웨어 같은 절차가 필요 없습니다.
시리즈 개요
이 글은 WSL‑UI를 구축하는 시리즈의 첫 번째 게시물입니다. 다음 게시물에서는 다음 주제를 다룰 예정입니다:
- Mock Mode – 테스트 및 개발을 위한 가짜 WSL 환경 구축.
- Registry Surgery – 배포판 이름 변경이 내부적으로 어떻게 작동하는지.
- OCI Without Docker – 레지스트리에서 직접 컨테이너 이미지를 가져오기.
- Microsoft Store Publishing – Tauri에서 MSIX, 그리고 스토어 등록까지.
- E2E Testing – WebdriverIO를 사용한 스크린샷 생성 및 비디오 녹화.
- Polish and Analytics – 백엔드 관점에서 본 UI 개발 어려움과 프라이버시 우선 분석.
가용성
WSL‑UI는 오픈 소스이며 다음에서 이용할 수 있습니다:
- Microsoft Store – “WSL UI”를 검색하거나 스토어 목록을 확인하세요.
- Official Website – [Website Download]
- GitHub –
Tauri에 대해 궁금하거나 구성 요소들이 어떻게 맞물리는지 보고 싶다면, 코드는 모두 제공되어 있으며, 적절히 문서화되어 있어 탐색하기에 준비되어 있습니다.
Next Up
실제 WSL 배포판에 손대지 않고도 개발 및 테스트를 할 수 있는 완전한 모크 모드를 구축한 방법.