1P by GN⁺ | ★ favorite | 댓글 1개
  • 웹 앱과 TypeScript 코드로 만든 Deno 프로젝트를 플랫폼별 재배포 가능한 데스크톱 앱 바이너리로 묶을 수 있음
  • 출력물은 애플리케이션 코드, Deno 런타임, 웹 렌더링 엔진을 함께 포함하며, Deno v2.9.0에 들어갔지만 아직 안정 릴리스는 아님
  • 기본 WebView 백엔드는 운영체제 내장 webview를 사용해 작은 바이너리를 지향하고, 렌더링 일관성이 필요하면 Chromium(CEF) 백엔드를 선택할 수 있음
  • Next.js, Astro, Fresh, Remix, Nuxt, SvelteKit, SolidStart, TanStack Start, Vite SSR 프로젝트를 감지해 릴리스 모드와 --hmr 개발 모드에 맞게 서버를 실행함
  • Deno 코드와 webview 간 통신은 소켓 기반 IPC가 아닌 인프로세스 채널을 쓰며, 교차 컴파일과 bsdiff 기반 자동 업데이트까지 범위에 포함됨

deno desktop의 역할과 현재 상태

  • deno desktop은 Deno 프로젝트를 자체 포함형 데스크톱 애플리케이션으로 변환함
    • 입력은 단일 TypeScript 파일부터 Next.js 앱까지 가능함
    • 출력은 플랫폼별로 재배포 가능한 바이너리임
    • 바이너리에는 애플리케이션 코드, Deno 런타임, 웹 렌더링 엔진이 포함됨
  • 이 기능은 Deno v2.9.0에 포함되어 있지만 아직 안정 릴리스는 아님
    • 지금 시험하려면 deno upgrade canarycanary 빌드를 설치해야 함
    • 명령어, 설정 키, TypeScript API는 안정화 전까지 바뀔 수 있음

백엔드 선택과 웹 프로젝트 실행

  • 웹 기술을 데스크톱 UI 툴킷으로 쓰면서, 기존 웹 스택 기반 데스크톱 앱 도구의 트레이드오프를 줄이는 방향을 택함
    • Electron, Tauri, Electrobun 같은 도구는 큰 바이너리, 플랫폼 지원 누락, JavaScript 생태계 부재, 내장 업데이트 부재, 프레임워크 통합 부재 같은 트레이드오프가 있을 수 있음
  • 기본 WebView 백엔드는 운영체제의 webview를 사용해 작은 바이너리를 지향함
    • Deno의 Node 호환 계층을 통해 npm 생태계를 사용할 수 있음
    • macOS·Windows·Linux에서 같은 렌더링이 필요하면 번들된 Chromium인 CEF 백엔드를 선택할 수 있음
  • 프레임워크 자동 감지는 기존 웹 프로젝트를 코드 변경 없이 데스크톱으로 실행하는 방식임
    • 대상은 Next.js, Astro, Fresh, Remix, Nuxt, SvelteKit, SolidStart, TanStack Start, Vite SSR 등임
    • 릴리스 모드에서는 프로덕션 서버를 실행함
    • --hmr에서는 핫 리로드가 있는 개발 서버를 실행함

런타임 통신, 빌드, 업데이트

  • 백엔드와 UI 통신에는 인프로세스 채널을 사용함
    • 값은 호출 경계를 넘을 때 인코딩됨
    • Deno 코드와 webview 사이에 교차 프로세스 왕복이 없음
  • 한 머신에서 macOS, Windows, Linux용으로 교차 컴파일할 수 있음
    • 백엔드는 로컬에서 빌드하지 않고 필요할 때 다운로드됨
  • 자동 업데이트는 latest.json 매니페스트와 bsdiff 패치를 사용하는 내장 바이너리 차분 업데이트 방식임
    • 런타임이 폴링, 적용, 실패한 실행에 대한 롤백을 처리함

간단한 예제와 문서 구성

  • 한 파일짜리 데스크톱 앱은 Deno.serve()로 HTML 응답을 반환하는 main.ts를 만들고 deno desktop main.ts를 실행해 만들 수 있음
Deno.serve(() =>
  new Response("<h1>Hello, desktop</h1>", {
    headers: { "content-type": "text/html" },
  })
);
deno desktop main.ts
  • 컴파일된 바이너리는 Deno.serve() 핸들러에 바인딩된 로컬 HTTP 서버를 가리키는 창을 엶
    • macOS/Linux에서는 ./main으로 실행함
    • Windows에서는 .\main.exe로 실행함
  • Deno.serve()는 webview가 이동하는 주소에 자동 바인딩되므로 포트나 호스트 이름을 넘길 필요가 없음
  • 관련 문서는 설정, 백엔드, HTTP 서빙, 프레임워크, 창 관리, 바인딩, 메뉴, 트레이와 dock, 대화상자, 알림, HMR, DevTools, 자동 업데이트, 오류 보고, 배포, 비교, CLI 참조로 나뉨
    • Deno.BrowserWindow는 창 생명주기, 여러 창, 이벤트와 관련됨
    • Deno.autoUpdate()는 매니페스트, bsdiff, 롤백과 관련됨
    • bindings.<name>()은 webview에서 Deno 코드를 호출하는 바인딩 방식임

댓글과 토론

Hacker News 의견들
  • Deno Desktop이 그런 절충점을 꽤 의견 강하게 정한 듯함: “기본은 작게, Node 호환성은 완전하게”
    글의 5줄짜리 Hello World로 deno desktop index.ts를 해봤는데, Windows 10에서 결과가 442MB였음
    Electron 빌드보다 작을 줄 알았는데 훨씬 커서 놀랐고, libcef.dll이 247MB, Hello World가 들어간 deno-test.dll이 78MB였음
    뭔가 잘못한 건지 궁금함

    • Electron Hello World도 브라우저/Chromium 런타임을 포함해서 대략 100~150MB였던 걸로 기억함
      그래서 OS 웹뷰 같은 걸 재사용해서 20MB 이하 해법이 나올 수 있길 기대했는데, 400MB가 넘는 건 좀 기만적으로 느껴짐
      설정을 잘못한 걸 수도 있으니 deno desktop test.ts 말고 뭔가 더 해야 하는지 궁금함
  • “앱마다 CEF를 각자 번들링하는 대신 공유 CEF 런타임을 관리하면 앱당 바이너리 크기를 몇 MB로 줄일 수 있고, 로드맵에 있다”는 부분이 흥미로움
    CEF를 잘 몰라서 버전 관리는 어떻게 되는지 궁금함
    앱마다 요구하는 CEF 버전이 다르면 결국 Electron처럼 각 앱이 자기 브라우저를 들고 다니는 모델로 돌아가는 건지, 아니면 그런 경우에도 공유 런타임의 장점이 남는 건지 알고 싶음
    https://docs.deno.com/runtime/desktop/comparison/

    • CEF는 Chromium Embedded Framework
      https://github.com/chromiumembedded/cef
    • 참고로 CEF는 Riot과 League of Legends 클라이언트에도 쓰였음
      결과가 좋지는 않았지만, 그게 CEF 기술 자체 문제였는지 다른 구성 요소나 프로세스 탓인지는 모르겠음
      https://www.riotgames.com/en/news/architecture-league-client...
    • 장점이 클지 의심스러움
      데스크톱의 Electron 앱은 사실상 거의 다 서로 다른 Chromium 버전을 쓰고, 업그레이드 때 깨질 위험 때문에 오래된 버전을 유지하는 경우도 많음
    • 웹 개발자는 대상 환경이 계속 최신으로 갱신되는 데 익숙하니, “그냥 네가 가진 최신 걸 줘” 같은 모델에 참여하거나 빠지는 선택지가 가능할 것 같음
    • 내장 브라우저를 직접 내려받고 관리하기보다는 시스템 웹뷰를 쓰면 좋겠음
      Windows라면 WebView2 같은 방식임
  • Deno는 계속 인상적임
    새 프로젝트를 Deno 없이 시작한 지 꽤 오래됐고, Node.js보다 Deno 생태계를 완전히 지지하게 됐음
    이 기능을 얼마나 자주 쓸지는 모르겠지만, 선택지가 생긴 건 정말 좋음

  • 인상적인 작업임
    바이브 코딩으로 데스크톱 앱을 만들 때 꽤 흥미로울 것 같음
    Lovable, Bolt, v0 같은 도구는 웹 앱을 만들 때 기본적으로 TypeScript를 쓰니 여기에 잘 어울려 보임
    작은 데스크톱 앱에 Chromium과 Node를 번들링하는 대신 Go/Wails를 써왔고, Electron도 역할은 잘했지만 그 큰 번들은 나한테는 확실히 거부감이 컸음

  • Deno의 가장 큰 강점 중 하나인 권한 시스템과 어떻게 통합되는지가 궁금했음
    특히 에이전트가 내 기기에서 마음대로 돌아다니게 할 때 중요함
    CLI 참고 문서에는 “컴파일 시 부여한 권한이 컴파일된 바이너리에 구워진다”고 되어 있음
    사용자가 어떤 권한을 줄지 알 수 있고 결정할 수 있도록 표면화되면 좋겠음
    https://docs.deno.com/runtime/reference/cli/desktop/#runtime...

    • 개발자에게서 받은 바이너리를 실행하는 상황임
      거기서 Deno 권한 프롬프트를 보여주면, 그 권한의 무결성 보장이 없기 때문에 오히려 오해를 줄 수 있다고 봄
    • Deno Desktop에 아직 없는 것 중 하나가 데스크톱 앱용 런타임 권한
      파일시스템이나 네트워크 접근마다 권한 프롬프트를 띄우는, Deno 권한 시스템을 데스크톱 샌드박싱에 적용하는 방식임
  • 출시하기 똑똑한 기능임
    어떤 플랫폼을 쓸지 결정할 때 충분히 고려 대상이 될 것 같음

    • 동의함
      작은 설치 크기와 크로스플랫폼이면 Electron이나 Tauri의 괜찮은 대안처럼 보임
  • “웹 기술은 세계에서 가장 널리 알려진 UI 툴킷”이라는 표현은 별로 적절하지 않다고 봄
    Electron 앱이 많이 비판받는 이유는 UI 툴킷과는 정반대에 가깝기 때문임
    호스트 OS의 UI 패턴을 제대로 따르지 못하는 경우가 많음
    웹 기술은 그냥 웹 기술이고, 버튼을 렌더링할 수는 있지만 스타일을 입히지 않은 버튼조차 OS 네이티브처럼 보인다는 보장이 없고 브라우저마다 달라짐

    • 사람들이 Electron을 쓰는 이유는 그게 아님
      목표가 단순히 “UI 툴킷”이거나 “호스트 OS의 UI 패턴을 따르는 것”이었던 적은 없음
      Chromium에는 엄청나게 많은 기능이 들어 있고, Electron은 그 유틸리티를 그대로 가져오며 그건 장점임
      예를 들어 비디오 작업을 해봤다면, 데스크톱 앱 안에서 현대 브라우저의 전체 능력을 쓰는 게 판도를 바꾼다는 걸 알 수 있음
      비디오 재생은 물론이고 현대 웹과 WebCodecs로 가능한 트랜스코딩까지 직접 구현하려면 매우 큰 작업이며, Windows/macOS/Linux에서 동작해야 하는 데스크톱 앱이라면 더더욱 그렇음
      Electron으로 수십 시간 만에 만든 앱이 있는데, 다른 방식이면 수십 일이 걸렸을 것 같고 AI를 써도 비디오 전문가가 아니면 어려웠을 것임
    • 왜 표현이 나쁘다는 건지 모르겠음
      “네이티브” UI라고 주장한 적은 없음
      Linux의 네이티브 UI는 항상 굉장히 못생겨 보였고, 차라리 잘 꾸민 HTML+CSS 레이아웃을 쓰는 편이 훨씬 낫다고 느껴왔음
      내 경험상 Electron은 주로 비대하고 느리다는 이유로 욕을 먹고, 네이티브가 아니라는 건 사람들이 부가적으로 덧붙이는 정도임
      예전부터 HTML+CSS로 레이아웃은 쓰되 JavaScript 런타임은 필요 없는 직접 브라우저 통합을 만들고 싶었음
      Servo가 얼마나 가벼운지는 모르겠지만 언젠가 그런 아이디어가 현실화되면 좋겠음
    • Linux, macOS, Windows에서 Zed를 쓸 때마다 GPUI 프레임워크가 얼마나 안정적이고 빠른지 놀라움
      사용자로서는 매우 만족스럽고, 접근성 같은 기본 기능이 아직 부족하긴 하지만 곧 구현될 거라 봄
      개발자 입장에서는 Rust 말고 진입 장벽이 뭔지 잘 모르겠고, 동시에 Rust가 차별점이기도 함
    • UI가 네이티브처럼 보이는지는 이미 오래전에 반론거리로서 힘을 잃었음
      25년쯤 전 이야기고, Microsoft조차 신경 쓰지 않기 시작한 뒤로는 아무도 크게 신경 안 씀
    • 호스트 OS의 UI 패턴을 따르지 않는다는 걸 단점으로 보는 것 같지만, 나한테는 그게 Electron의 핵심 장점 중 하나임
      서로 다른 OS에서 내 앱이 다르게 보이길 원하지 않음
      모든 기기에서 테스트할 리소스가 없고, 한 시스템에서 테스트한 화면이 다른 시스템에서도 똑같이 보인다는 건 매우 큰 장점임
  • 이 영역에 경쟁자가 생겨서 반가움
    특히 Deno는 현재 Node 구현처럼 타입만 제거하는 게 아니라 진짜 TypeScript를 직접 실행할 수 있다는 점이 좋음
    다만 이건 Tauri 시장을 꽤 많이 가져갈 것 같음
    이제 왜 Tauri를 써야 하지?
    대부분 인터넷 연결에서 번들 크기 150MB 증가는 다운로드 시간 1~10초 차이에 불과하고, 대신 신뢰할 수 있는 렌더링 엔진을 얻을 수 있음

    • Deno도 TypeScript 코드를 실행할 때 기본적으로는 타입 주석을 제거할 뿐임
      타입 검사를 하려면 deno run --check로 실행하거나 별도 deno check 하위 명령을 써야 함
      개발 중에는 보통 IDE가 타입 검사와 린팅을 자동으로 해주니 큰 문제는 아님
    • Tauri는 특정 JavaScript 생태계에 가두지 않음
      사실 JavaScript를 쓸 필요도 없음
      그리고 Astro, Nuxt, UV, Bun, Vite처럼 개발자 프레임워크 스타트업들이 여럿 인수되는 걸 봐왔음
      수년간 유지되고 지원받아야 하는 소프트웨어라면 그런 흐름이 신뢰를 주지는 않음
    • “백엔드”가 JavaScript가 아닐 때 Tauri를 씀
    • “신뢰할 수 있는 렌더링 엔진”을 얻는다는 말이 잘 이해되지 않음
      Deno Desktop과 Tauri 둘 다 시스템 웹뷰를 쓰는 것 아닌가?
    • 그 논리라면 Electron을 쓰자는 말과도 같음
      왜 이걸 쓰고 Electron은 쓰지 않아야 하지?
  • Deno가 내놓은 자료 중에서는 비교 섹션이 제일 좋았음
    마지막 줄에 iOS/Android 지원이 Electron은 “no”, Deno는 “not yet”으로 되어 있는데, 이걸 실제로 해내면 훨씬 커질 것임

  • 웹 게임을 Steam 앱이나 온라인 구매용 앱으로 배포하는 데 정말 좋을 것 같음
    한번 써볼 생각임