Dolt Workbench에 Electron 대신 Tauri를 적용해 보며 Next.js 연동, 웹뷰 구조, Node.js와 Rust의 차이, 사이드카 프로세스, 배포 한계 등을 비교한다.
Dolt Workbench는 MySQL, Postgres, Dolt, Doltgres 데이터베이스를 지원하는 오픈 소스 SQL 워크벤치입니다. 우리는 이 워크벤치를 Electron으로 만들었습니다. Electron은 HTML, CSS, JavaScript 같은 전통적인 웹 기술로 만든 웹 앱을 데스크톱 애플리케이션으로 변환할 수 있게 해 주는 인기 있는 프레임워크입니다. 워크벤치는 DoltHub나 Hosted Dolt와 공통점이 많기 때문에, 아키텍처도 이들과 매우 비슷합니다. 즉, 프론트엔드는 Next.js를 사용하고, 여기에 데이터베이스 상호작용을 처리하는 추가 GraphQL 레이어가 있습니다. 이런 이유로, 우리 애플리케이션의 데스크톱 버전을 빠르게 띄우기 위해 Electron을 사용하는 것은 매우 자연스러운 선택이었습니다.
하지만 Electron에는 꽤 큰 단점들이 있고, 워크벤치가 성숙해질수록 그 단점들이 점점 더 눈에 띄기 시작했습니다. 그래서 나는 같은 웹→데스크톱 유즈케이스를 지원하는 더 최근의 프레임워크인 Tauri를 살펴보는 데 시간을 들였습니다. 이 글에서는 Electron과 Tauri가 워크벤치와 얼마나 잘 통합되는지, 그리고 두 프레임워크 사이의 장단점을 비교해 보겠습니다.
Next.js는 데스크톱 애플리케이션 환경으로 깔끔하게 옮겨지지 않습니다. 주된 이유는 서버 사이드 렌더링과 API 라우팅 기능 중심의 프레임워크 아키텍처에 있습니다. 데스크톱 앱에서는 클라이언트와 상호작용하는 애플리케이션 서버가 존재하지 않고, 단지 HTML, CSS, JavaScript를 윈도우에 렌더링하기만 하면 됩니다. 이런 이유로 Electron은 Next.js 애플리케이션을 느슨하게만 지원합니다. Next.js로 Electron 앱을 만들 수 없다는 뜻은 아니지만, 제대로 동작하게 하려면 몇 가지 우회 방법이 필요합니다.
가장 잘 알려진 우회 방법 중 하나가 Nextron이라는 프로젝트입니다. Nextron은 Next.js 애플리케이션을 Electron 프레임워크에 연결하고 빌드 과정을 단순화하는 것을 목표로 합니다. 워크벤치는 이 프로젝트를 사용합니다. 문제는 이 글을 쓰는 시점에 Nextron이 더 이상 유지보수되고 있지 않은 것으로 보이고, 실제로 몇 가지 버그에 부딪히기 시작했다는 점입니다.
Tauri는 대체로 프론트엔드 프레임워크에 대해 무관(neutral)합니다. Next에 한정해서 말하자면, 여전히 서버 사이드 기능은 사용할 수 없지만, Tauri는 Next의 정적 사이트 생성 기능에 의존함으로써 통합 과정을 훨씬 단순하게 만듭니다. Next 앱을 Tauri와 함께 동작시키려면, Next 설정 파일에 output: 'export'만 지정해 주면 되고, 나머지는 Tauri가 알아서 처리합니다.
Electron과 Tauri의 가장 큰 차이점은 UI를 렌더링하는 방식에서 나옵니다. Electron 프레임워크는 애플리케이션에 전체 Chromium 브라우저 엔진을 함께 번들링합니다. Chromium은 Google Chrome이 사용하는 엔진입니다. 이는 브라우저 호환성 문제를 신경 쓰지 않아도 된다는 점에서 유용합니다. 최종 사용자의 머신이나 아키텍처와 상관없이 항상 동일한 Chromium 인스턴스가 애플리케이션 UI를 렌더링합니다. 그 결과 어디에서 실행하든 앱이 동일하게 보이도록 보장하는 매우 표준화된 경험을 제공합니다.
하지만 이는 상당한 **부피(bloat)**로 이어지기도 합니다. 대다수의 데스크톱 앱에 전체 Chromium 브라우저 엔진은 과한 수준입니다. 가장 단순한 “Hello World” 수준의 Electron 앱조차 디스크 공간을 150MB 정도 차지할 수 있습니다.
Tauri는 시스템의 네이티브 웹뷰를 활용함으로써 이 문제를 해결합니다. 전체 브라우저 엔진을 번들링하는 대신, Tauri는 WRY라는 라이브러리를 사용합니다. WRY는 운영체제에 맞는 웹뷰에 대한 크로스 플랫폼 인터페이스를 제공합니다. 예상할 수 있듯이, 이를 통해 Tauri 앱은 훨씬 더 가벼워집니다.
단점은 더 이상 호환성에 대한 강한 보장이 없다는 점입니다. 하지만 내가 보기에는, 이 부분은 대부분 실제로 큰 문제가 되지 않는 듯합니다. 시스템 웹뷰 간 호환성 문제는, 특히 주요 운영체제들에서는, 극히 드물게 발생합니다.
두 프레임워크의 또 다른 큰 차이점은 “메인(main) 프로세스”를 어떻게 처리하느냐에 있습니다. 메인 프로세스란 애플리케이션 윈도우, 메뉴, 시스템 API와 상호작용이 필요한 기타 데스크톱 앱 구성 요소들을 오케스트레이션하는 백엔드 프로세스를 말합니다.
Electron에서는 메인 프로세스가 Node.js 환경에서 실행됩니다. 이는 일반적인 Node API에 접근할 수 있고, 평소처럼 모듈을 import 할 수 있으며, 무엇보다도 Electron 전용 코드를 순수 JavaScript로 작성할 수 있다는 뜻입니다. 이는 Electron의 타깃 사용자층인 웹 개발자들에게 엄청난 장점입니다.
반면 Tauri는 Rust를 사용합니다. 프레임워크 코드 전체와 메인 프로세스 진입점은 Rust로 작성됩니다. 당연히, 이는 평균적인 웹 개발자에게 접근성을 다소 떨어뜨립니다. 그렇다고 해도 Tauri는 Rust 레이어와 상호작용할 수 있는 꽤 풍부한 JavaScript API를 제공합니다. 대부분의 애플리케이션에서는 이 API들로 필요한 일을 충분히 처리할 수 있습니다. 워크벤치의 경우, JavaScript API와 최소한의 Rust 코드만으로 Electron 버전과 동일한 기능을 완전히 재현할 수 있었습니다.
내 경험상, Tauri API는 우리 애플리케이션 코드에 더 자연스럽게 녹아들었습니다. Electron에서는 메인 프로세스가 무언가를 해야 할 때마다, 가장 단순한 작업이라도 항상 프로세스 간 통신(IPC)을 사용해야 합니다. 예를 들어, 호스트 머신의 파일에 쓰기를 하려면, 프론트엔드가 Electron 메인 프로세스에 신호를 보내고, 메인 프로세스가 새 프로세스를 생성한 뒤, 여러분이 작성한 쓰기 함수를 실행해야 합니다.
Tauri에서는 애플리케이션 코드 안에서 바로 Tauri의 파일 시스템 API를 사용할 수 있습니다. 내부적으로는 비슷한 IPC 패턴이 발생하지만, Tauri가 제공하는 추상화가 좀 더 깔끔하다고 느꼈습니다.
Electron은 Node.js 위에서 실행되기 때문에, 애플리케이션과 함께 전체 Node.js 런타임도 번들링합니다. 이는 장단점이 있습니다. 워크벤치 관점에서 보면, GraphQL 레이어 자체가 프론트엔드와 함께 실행되어야 하는 별도의 Node.js 애플리케이션이기 때문에, 이는 유리하게 작용합니다. Electron이 Node.js를 포함하고 있으므로, Node 런타임을 사용해 Electron 메인 프로세스에서 직접 GraphQL 서버를 띄울 수 있습니다.
이렇게 하면 일반적인 사이드카 프로세스를 번들링하고 실행할 때 발생하는 많은 골칫거리를 없앨 수 있습니다. 예를 들어, 우리 앱은 Dolt의 사본도 함께 포함해, 사용자가 워크벤치에서 직접 로컬 Dolt 서버를 시작할 수 있게 해 줍니다. 이를 위해서는, 각 워크벤치 릴리스에 해당 아키텍처에 맞는 Dolt 바이너리를 번들링해야 합니다. Node 런타임이 없었다면, GraphQL 레이어에 대해서도 비슷한 작업을 해야 했을 겁니다.
Tauri에서는 정확히 이 문제가 발생합니다. 이를 우회하기 위해, pkg 같은 도구를 사용해 GraphQL 서버를 바이너리로 컴파일한 다음, Dolt를 실행하는 방식과 동일하게 사이드카로 실행해야 합니다. 다행히도, 이는 Tauri 애플리케이션에서 꽤 흔한 유즈케이스인 듯하고, Tauri 측에서도 Node.js 앱을 사이드카로 실행하는 방법에 대한 유용한 가이드를 제공하고 있습니다.
또한 전체 Node.js 런타임 자체가 상당히 무겁기 때문에, 이것도 Electron 앱 용량이 커지는 데 한몫합니다. 워크벤치를 Electron과 Tauri 두 방식으로 모두 빌드해 본 뒤, 크기 차이는 상당했습니다. 왼쪽이 Electron 버전이고 오른쪽이 Tauri입니다:

Tauri에서 워크벤치의 기능을 재현해 본 뒤에도, 우리가 전체 마이그레이션을 미루고 있는 이유는 몇 가지가 있습니다.
이 둘 중 어느 것도 결정적인(하드) 차단 요인은 아니지만, 꽤 번거로운 문제여서, Nextron 관련 문제가 더 심각해지거나 위 이슈들이 해결될 때까지는 마이그레이션을 미루고 있습니다. 당분간은 마이그레이션 작업을 해 둔 내 브랜치를 열어 둔 상태로 두고, 곧 다시 살펴볼 수 있기를 바라고 있습니다. 혹시 Tauri 팀에 계신다면, 해결책이 있다면 알려 주세요!
전체적으로 Tauri에 깊은 인상을 받았습니다. Tauri는 고전적인 Electron식 부풀림(bloat)의 상당 부분을 제거하고, 기존 코드베이스와도 자연스럽게 통합됩니다. Tauri나 Dolt Workbench가 궁금하다면 Discord에서 알려 주세요.