Dioxus 0.5: 러스트로 개발하는 웹, 데스크톱, 모바일 앱
(dioxuslabs.com)- Rust GUI 프레임워크 Dioxus 0.5는
dioxus-core재작성과 unsafe 제거를 중심으로, 웹·데스크톱·모바일·Fullstack 개발 흐름을 크게 단순화함 - 0.4.3에서 0.5.0 사이에 100,000줄 이상의 코드와 1,400개 이상 커밋이 들어갔고, 새 코어는 수명과
Scope의존을 없애는 방향으로 바뀜 - 기존
use_state·use_ref중심 상태 관리는 Copy 가능한SignalAPI로 대체되어, 이벤트 핸들러와 future에서 반복적인Clone부담이 줄어듦 - 하나의
dioxus::launch와dx serve --platform흐름으로 웹, 데스크톱, Fullstack 앱을 실행하며, CLI가 대상 플랫폼에 맞는 빌드 feature를 자동 전달함 - 자산 핫 리로드, 이벤트 재작성, 데스크톱 렌더링 개선, 서버 함수 스트리밍까지 함께 바뀌어 단일 Rust 코드베이스의 적용 범위가 넓어짐
Dioxus 0.5의 릴리스 방향
- Dioxus는 Rust로 GUI를 만드는 라이브러리이며, 웹 앱·데스크톱 앱·모바일 앱 배포에 사용되고 있음
- 0.5 릴리스는 커뮤니티가 요구한 단순화, 견고함, 완성도 향상을 목표로 설계됨
- 주요 변화는 다음과 같음
dioxus-core완전 재작성 및 unsafe 코드 제거use_state,use_ref대신Signal기반 API 도입- 모든 수명과
cx: Scope상태 제거 - 모든 플랫폼에서 앱을 시작하는 단일
launch함수 - Tailwind와 Vanilla CSS를 지원하는 자산 핫 리로드
- 네이티브
WebSys이벤트 타입 접근을 허용하는 이벤트 재작성 - Error Boundary, Server Future, Suspense 통합
- 데스크톱 reconciliation 5배 개선
- 서버 함수 스트리밍과 Fullstack 핫 리로드
- Dioxus 0.4에서 업데이트하는 사용자를 위한 migration guide가 제공됨
수명과 Scope 제거
- Dioxus 0.1부터 0.4까지는 컴포넌트 내부 값이
'bump수명을 가졌고, 이를 통해 이벤트 리스너에서 훅, props, scope를 복제 없이 사용할 수 있었음 - 이벤트 핸들러에서는 대체로 잘 동작했지만, Dioxus의 future는
'static이어야 해서 값을 future 안으로 옮기기 전에clone이 필요했음 - 수명 오류가 발생하면 hook 자체가 아니라
cx가'static보다 오래 살아야 한다는 식의 메시지가 나와 혼란을 만들 수 있었음 - Dioxus 0.5는
Scope와'bump수명을 제거하고,Element를 수명 없는 형태로 바꿈 - 컴포넌트는 이제 scope 매개변수 없이 props를 직접 받을 수 있음
- 예:
fn MyComponent(name: String) -> Element
- 예:
- 런타임 함수는 컴포넌트 내부뿐 아니라 future와 이벤트 핸들러 내부에서도 직접 사용할 수 있음
Element가'static이 되면서 hook 안에서 사용하거나 context API를 통해 제공하는 것도 가능해짐- 이 변화는 가상 리스트나 오프스크린 렌더링 같은 API를 구현하기 쉬운 기반이 됨
dioxus-core의 unsafe 제거
'bump수명과 scope 제거는 Dioxus 내부의 unsafe 코드를 줄일 기회를 만들었음dioxus-core 0.5에는 unsafe 코드가 없음- 일부 의존성에는 소량의 unsafe가 남아 있으며, Dioxus 팀은 0.5 릴리스 사이클 동안 이를 제거할 계획임
- 남은 unsafe는 단순히 제거 가능한 것들이거나 FFI 때문에 필요한 것들로 분류됨
Signal 기반 상태 관리
- Dioxus 0.5는 컴포넌트의 핵심 상태 원시 타입으로 Signal을 도입함
- Signal은 기존
use_state,use_ref대비 두 가지 장점을 가짐- 항상
Copy가능함 - 수동 구독이 필요 없음
- 항상
-
Copy 상태
Signal<T>는 내부의T값이Copy가 아니어도Copy임- 이 동작은 unsafe 없이 구현된 generational-box 크레이트로 가능해짐
- 필요하면 Signal을
Send+Sync로 만들 수 있어 스레드 사이로 옮길 수 있음 - Copy 상태,
Send+SyncSignal, static 컴포넌트 조합으로 상태를 future, 이벤트 핸들러, 스레드 등 필요한 위치로 쉽게 이동할 수 있음 - 메모리 사용 방식은 0.4와 거의 같지만, 명시적
Clone이 필요하지 않음
-
스마트 구독
- Signal은 값이 바뀌었을 때 어떤 컴포넌트를 다시 실행할지 더 세밀하게 판단함
- 컴포넌트가 Signal 값을 읽은 경우에만 해당 컴포넌트가 다시 실행됨
- async 작업이나 이벤트 핸들러에서 읽은 경우는 컴포넌트 재실행 구독으로 취급되지 않음
- 부모가 버튼 클릭으로 Signal을 변경하지만 값을 직접 읽지 않고, 자식만 값을 읽으면 자식만 다시 렌더링됨
- 이 구조 덕분에 별도 상태 관리 크레이트였던 Fermi가 필요 없어짐
- Fermi는 static을 키로 쓰는
use_state유사 API를 제공했음 - Dioxus 0.5에서는
GlobalSignal을 static에 두고 일반 Signal처럼 사용할 수 있음 - Signal은 context API와도 동작해 별도의
use_shared_state훅 없이 컴포넌트 간 상태 공유가 가능함 use_future,use_memo같은 hook 안에서 Signal을 읽으면 해당 Signal이 hook 의존성에 자동 추가됨
CSS와 자산 핫 리로드
- Dioxus 0.5는 자산 시스템 개편의 일부로 자산 디렉터리의 CSS 파일 핫 리로드를 구현함
- CSS 파일이 RSX 안에 나타나면
dxCLI가 해당 파일을 감시하고 실행 중인 앱으로 업데이트를 즉시 스트리밍함 - 지원 대상은 Web, Desktop, Fullstack이며, 모바일 지원은 향후 모바일 중심 업데이트에서 제공될 예정임
- Tailwind watcher와 함께 사용하면 Tailwind CSS 핫 리로드도 지원됨
- VSCode에서는 custom regex extension을 통해 Tailwind class 힌팅도 받을 수 있음
- 여러 기기에 변경 사항을 동시에 스트리밍해 대상 기기 전체에서 핫 리로드할 수 있음
이벤트 시스템 재작성
- Dioxus는 출시 이후 크로스플랫폼 이벤트 API를 만들기 위해 synthetic event 시스템을 사용해 왔음
- Synthetic event는 플랫폼 간 이벤트 동작과 네트워크 직렬화에 유용하지만 한계도 있었음
- Dioxus 0.5는 각 플랫폼의 기반 이벤트 타입을 노출하고, 크로스플랫폼 API를 위한 trait도 함께 제공함
- 이 변화의 장점은 두 가지임
- 플랫폼 이벤트 타입에서 필요한 정보를 직접 얻거나 다른 라이브러리에 전달할 수 있음
- 앱이 사용하지 않는 이벤트 코드를 bundle splitting할 수 있음
- hello world 예시에서 gzipped 크기가 약 25% 감소함
- 작은 번들을 만드는 팁은 Dioxus optimization guide에 포함됨
크로스플랫폼 실행 API
- Dioxus 0.5는 앱 실행을 위한 새 크로스플랫폼 API를 도입함
- 별도 renderer 패키지를 가져오는 대신
dioxuscrate에서 feature를 활성화하고 prelude의launch함수를 호출하면 됨 - 하나의 앱에서 다음 플랫폼을 대상으로 실행할 수 있음
- Desktop:
dx serve --platform desktop - SPA Web:
dx serve --platform web - Fullstack:
dx serve --platform fullstack
- Desktop:
- CLI는 대상 플랫폼에 따라 적절한 빌드 feature를 자동으로 전달함
자산 시스템 베타와 Manganis
- Dioxus와 웹 앱에서 자산 경로는 오래되기 쉽고, 데스크톱과 웹에서 링크가 다를 수 있으며, 번들에 포함할 자산을 수동으로 추가해야 하는 문제가 있음
- 자산은 성능 병목이 될 수도 있음
- Dioxus Mobile 가이드 예시에서 0.4 버전은 로딩에 7초가 걸리고 9MB 리소스를 전송했음
- 0.5 모바일 가이드는 같은 이미지를 사용하면서도 1초 미만에 로드되고 필요한 리소스가 1/3로 줄어듦
- Dioxus 0.5는 새 자산 시스템 manganis 를 도입함
- CLI와 통합되어 앱 자산을 확인, 번들링, 최적화함
- API가 아직 불안정해 별도 crate로 배포됨
mg!매크로로 자산을 감싸면 CLI가 자동으로 감지함- 자세한 내용은 manganis docs에 있음
- 0.5 릴리스가 진행되는 동안 manganis 자산에도 핫 리로드를 추가할 계획임
데스크톱 렌더링 5배 개선
- Dioxus는 렌더링 diff를 빠르게 만들기 위해 여러 최적화를 사용함
- Templates는
rsx!매크로의 정적 부분 diff를 건너뛰게 함 - Dioxus Web에서는 sledgehammer를 통해 Rust에서 DOM 변경을 빠르게 적용함
- Dioxus 0.5는 같은 방식을 네트워크를 통한 변경 적용에도 사용함
- Desktop과 LiveView renderer가 변경 사항을 JSON 대신 바이너리 프로토콜로 통신함
- 렌더링 부하가 큰 작업에서 새 renderer는 브라우저에 변경을 적용하는 시간이 1/5로 줄고 지연 시간은 1/2로 줄어듦
- Dioxus 0.4에서 renderer가 계속 멈추던 벤치마크가 Dioxus 0.5에서는 부드럽게 실행됨
컴포넌트 작성 편의 기능
- Dioxus 0.5는 특정 element를 확장하고 속성을 element에 펼치는 기능을 지원함
- 예:
imgelement 속성을 확장한ImgPlus컴포넌트에서width,height,src같은 일반img속성을 그대로 받을 수 있음
- 예:
- 속성과 컴포넌트에 값을 전달할 때 구조체 초기화 축약 문법을 사용할 수 있음
class: class대신class처럼 쓸 수 있음
- 축약 속성은
IntoAttribute를 구현하는 모든 항목에 동작하며 Signal도 이 혜택을 받음 - Signal 속성이 아직 diffing을 건너뛰지는 않지만, 0.5 릴리스 사이클 동안 성능 최적화로 추가될 계획임
- 여러 줄에 나뉜 속성은 병합될 수 있음
- 같은
class속성에 조건부 값을 추가하면 공백을 구분자로 병합됨 - Tailwind처럼 컴파일 타임 파싱이 필요하면서 런타임 동적 처리도 필요한 라이브러리에 중요함
- 이 문법은 Tailwind compiler와 통합되어
tailwind-merge같은 라이브러리의 런타임 오버헤드를 제거함
- 같은
서버 함수 스트리밍과 Fullstack
- Dioxus 0.5는 스트리밍 데이터를 지원하는 최신 server functions crate를 지원함
- 서버 함수는 클라이언트로 데이터를 스트리밍하거나 클라이언트에서 서버로 데이터를 스트리밍할 수 있음
- 스트리밍 서버 함수는 출력 타입을 정의하고 서버 함수에서
TextStream을 반환하는 방식으로 만들 수 있음 - 오래 걸리는 작업 중 클라이언트를 업데이트하는 데 적합함
- Kalosm과 로컬 LLM을 사용해 일반 하드웨어에서 OpenAI ChatGPT endpoint와 유사한 기능을 제공하는 예제가 있음
- CLI는 이제
fullstack플랫폼을 지원하고, 클라이언트와 서버의 핫 리로드 및 병렬 빌드를 제공함dx servedx serve --platform fullstack
LiveView, 자산 핸들러, 파일 처리
- Dioxus 0.5에서는 router가 LiveView 앱에서 기본 동작함
- Dioxus Desktop은 custom asset handler를 지원함
- Custom asset handler는 Rust 코드에서 JavaScript를 거치지 않고 브라우저로 데이터를 효율적으로 스트리밍할 수 있게 함
- 비디오 스트리밍처럼 대역폭이 큰 통신에 적합함
- gstreamer나 webrtc 데이터를 직접 webview로 전달할 수 있어 프레임을 직접 인코딩·디코딩할 필요를 줄임
- 데스크톱의 파일 드롭도 이벤트 시스템에 네이티브로 통합됨
에러 처리
- Dioxus는 Error Boundary와
throwtrait를 통해 상위 컴포넌트에서 에러를 쉽게 처리할 수 있게 함 throw방식은 에러 상태와 조기 반환의 장점을 결합함Debug를 구현하는Result타입에서throw를 호출해 에러 상태로 바꾸고,?로 조기 반환할 수 있음ErrorBoundary컴포넌트는 자식에서 던져진 에러가 있을 때 다른 컴포넌트를 렌더링함ErrorBoundary는 중첩할 수 있어 앱의 여러 수준에서 에러를 잡을 수 있음- 이 패턴은 복구 불가능한 에러가 생겼을 때 panic하거나 에러마다 상태를 직접 관리하지 않고 전역 에러 상태를 처리하는 데 유용함
개발 경험과 템플릿
- Dioxus는 0.3에서 핫 리로드를 도입했고, 0.4에서 Desktop에 추가했으며, 0.5에서는 기본 활성화함
dx serve로 앱을 실행하면 개발 모드에서 기본적으로 핫 리로드가 켜짐- Desktop 앱에서 핫 리로드가 불가능해 전체 재컴파일이 필요할 때도 열린 창의 상태를 보존하고 복원함
- 앱 창 크기와 위치가 유지됨
- 편집할 때마다 앱이 전체 화면을 막는 상황을 줄임
- 새 템플릿은 Web, Desktop, Mobile, TUI, Fullstack 앱을 하나의 명령으로 만들 수 있게 정리됨
dx new의 기본 앱은 create-react-app에 가까운 형태로 바뀜- assets, CSS, 기본 배포 설정을 포함함
- dioxus-std, VSCode Extension, 문서, 튜토리얼 등 유용한 리소스 링크를 포함함
Dioxus Community와 생태계
- Dioxus Community는 0.5 릴리스를 위해 중요한 생태계 crate를 업데이트함
- icons, charts, Dioxus 전용 표준 라이브러리 같은 crate가 0.5 출시 시점에 바로 사용할 수 있도록 준비됨
Dioxus Community프로젝트는 원래 maintainer가 물러나도 중요한 crate를 최신 상태로 유지하기 위한 새 GitHub 조직임- Dioxus용 라이브러리를 만드는 경우, Dioxus 측은 이를 유지보수하는 데 도움을 줄 수 있으며 사실상 “Tier 2” 지원으로 유지하는 것을 목표로 함
앞으로 계획된 기능
- 0.5 이후 계획에는 다음 항목이 포함됨
- 자산 시스템 안정화와 더 깊은 통합
- lazy component와 함께 출력
.wasm직접 bundle splitting - Islands와 resumable interactivity, Signal 직렬화
- Server component와 LiveView를 Fullstack으로 병합
- 향상된 Devtools와 테스트 프레임워크
- 전체 Mobile 개편
- WebSocket, SSE, progressive form 등을 포함한 Fullstack 개편
Servo 기반 Dioxus-Blitz 미리보기
- Dioxus-Blitz의 “Blitz 2.0”에서는 Servo를 통합해 Firefox를 구동하는 것과 같은 CSS 엔진으로 WGPU 네이티브 렌더링을 목표로 함
- Taffy layout library를 만든 Nico Burns가 이 작업을 추진하기 위해 풀타임으로 합류함
- 데모에서는
google.com을 GPU에서 900 FPS로 렌더링함 - 현재 구현은 아직 완전하지 않고
google.com렌더링도 다소 어색하지만, 사용 가능한 수준에 빠르게 접근 중임 - 저장소는 https://github.com/jkelleyrtp/stylo-dioxus에서 확인할 수 있음
기여 방법
- Dioxus 프로젝트는 다음 기여를 원함
- 문서 번역
- “Good First Issues” 시도
- 문서 개선
- CLI 기여
- Discord 커뮤니티 질문 답변
- Dioxus 팀은 2024년 남은 기간 동안 커뮤니티 지원에 감사하며 앱 개발을 바꾸는 데 도움을 요청함
댓글과 토론
Hacker News 의견들
- 작년에 Dioxus로 Mastodon 클라이언트 Ebou를 만들었는데 전반적으로 좋은 경험이었지만 빠진 것도 많았음
작업을 시작했을 때 0.2 버전이었고, 이번 0.5 변경으로 당시 겪었던 복잡성이 거의 사라진 듯함. 아직 직접 써보진 않았지만 수명(lifetime) 제거와 계속 복제해야 하는 부담이 줄어 훨씬 쾌적해질 것 같음- Dioxus를 어떻게 선택했는지 궁금함
데스크톱, 웹/wasm, 모바일 등에 배포 가능한 네이티브 반응형 UI를 하려는 Rust 프레임워크가 꽤 많아서 https://github.com/flosse/rust-web-framework-comparison, 잘못 고르면 방치된 프레임워크를 유지하거나 고통스러운 마이그레이션을 해야 할까 걱정됨
Rust HTTP 서버 프레임워크도 비슷하게 많다가 지금은 Axum, Actix, Rocket이 앞서는 것처럼 보이고, 커뮤니티 흐름이 Axum으로 옮겨가는 듯해 Actix 선택이 잘못이었나 싶기도 함. Dioxus가 이길 신호가 있는지, 큰 커뮤니티와 YC 지원, 모멘텀 외에 지금 선택해도 되는 지표가 있는지 궁금함
Leptos와 Yew도 주요 경쟁자인지, Dioxus보다 낫거나 나쁜 이유가 무엇인지 알고 싶음. 회사는 Rust, Actix, Bevy에 많이 투자했고, 앞으로 Bevy와 Dioxus 같은 프레임워크를 묶어 네이티브 데스크톱·모바일 클라이언트를 만들려 함
그리고 Dioxus 이름이 Pokémon의 Deoxys에서 온 건지도 궁금함. 로고는 그런 느낌인데 코드베이스에는 Pokémon 참조가 없음
- Dioxus를 어떻게 선택했는지 궁금함
- “전반적으로 좋았지만 빠진 게 많았다”는 말에 동의함
9개월쯤 전에 Dioxus로 sshfs용 GUI 프런트엔드를 만들었는데, 개발자가 아직 어떤 기능을 끝내지 않은 벽에 부딪히기 전까지는 정말 훌륭한 GUI 프레임워크라는 인상이었음
서로 다른 컨텍스트 간 상태 공유도 가끔 고통스럽지만, 언어나 기반 기술과 상관없이 써본 모든 GUI 프레임워크가 그랬음. Dioxus 0.5는 이 부분에서 큰 진전처럼 보임. 내 블로그는 HTML의 상당 부분을 Dioxus로 렌더링하는데, 한계까지 밀어붙이는 용도가 아니라서 아주 잘 작동함 - Dioxus를 관심 있게 지켜보고 있지만 아직 써볼 기회는 없었음
다만 수명 제거 해법이 좀 의아함. generational-box가 일종의 가난한 사람의 가비지 컬렉터 아닌가 싶은데, 성능 영향이 어땠는지 궁금함
덧붙여[generational-box]([https://crates.io/crates/generational-box](<https://crates.io/crates/generational-box>))링크는 깨져 있음- 가난한 사람의 가비지 컬렉터가 맞지만, 메모리 의미론은 이전 버전과 정확히 같음
use_hook이 컴포넌트 수명 동안 값을 소유하므로 컴포넌트가 사라질 때 그 값도 드롭됨. 모든 signal은 여전히use_hook을 쓰므로 수명도 동일함.use_hook밖에서GenerationalBox::new()를 호출하는 건 보통 권장하지 않기 때문에 성능 영향은 없음
루프 안에서GenerationalBox::new()를 남발하면 그 쓰레기는 컴포넌트가 드롭될 때까지 남겠지만, 대부분은 Map이나 Vec에 push/pop을 할 테고 그때는 일반적인 메모리 의미론이 적용됨 - 이건 본질적으로 자동 참조 카운팅임: https://en.wikipedia.org/wiki/Automatic_Reference_Counting
- 가난한 사람의 가비지 컬렉터가 맞지만, 메모리 의미론은 이전 버전과 정확히 같음
- Rust 프로그래머는 아니지만 generational-box 크레이트가 어떻게 동작하는지 궁금함
일종의 아레나 할당이라는 건 알겠지만, “복사 없이 복사”를 어떻게 지원하는지, 그리고 내부적으로 세대가 있는RefCell아레나를 만들고GenerationalBox가Copy라는 설명이 왜 안전한지 이해가 안 됨
정적 데이터에 대한 포인터를 만들 수 있다는 건 알겠지만, 정적 수명이 없는 값이면 어떻게 되는지 궁금함- 데이터를 복사하는 게 아니라 데이터에 대한 참조를 복사하는 것임
데이터 참조는 프로그램 수명 동안 유지됨. generational box는 프로그램 수명보다 짧게 사는 데이터를 넣을 수 있게 해주지만, 그 데이터는 참조를 포함하면 안 됨. 넣은 데이터를 드롭하면 그 박스를 다른 할당에 재사용함
중앙화된 아레나 대신 박스를 쓰는 점만 빼면 세대별 아레나와 매우 비슷한 접근이고, 잠금 문제를 피하기 위한 선택임. 드롭된 뒤Copy참조로 데이터에 접근하려 하면 좋은 오류 메시지와 함께 실패함 - 이 크레이트는 잘 모르지만 Rust 기준으로 보면,
Copy는 특정한 의미가 있음
어떤 타입이Copy트레이트를 구현하면memcpy로 복사될 수 있다는 뜻이고, 깊은 복사가 아니라 얕은 복사에 가까움
그래서 “복사 없이 복사”가 아니라,Copy가 아닌 타입을Copy타입처럼 다룰 수 있게 하는 것으로 이해함. README에는 정적 콘텐츠가 필요하다고 되어 있으니, 정적 수명이 없는 값은 “그렇게 할 수 없다”가 답임
- 데이터를 복사하는 게 아니라 데이터에 대한 참조를 복사하는 것임
- 한동안 지켜봤고 출시돼서 매우 반가움
Dioxus는 React가 성공했던 요소를 많이 가져오면서도 그 위에서 빠르게 혁신하고 배포하는 점이 좋음. 이번 릴리스의 signals를 써보는 게 기대됨 - RSX 대신 React/JSX보다 SwiftUI에 더 가까운 무언가였으면 좋겠음
React가 JS와 웹에 해준 좋은 일과 이름값은 인정하지만, 2024년에 언어나 DSL을 처음부터 설계할 수 있다면 “반응형 UI” 코드가 꼭 React처럼 보여야 한다고 생각하진 않음
SwiftUI가 완벽하다는 뜻은 아니지만, SwiftUI로 쓰는 코드는 React로 비슷한 코드를 쓸 때보다 훨씬 더 깔끔하게 정리되고 구획화된 느낌임
크로스 플랫폼 GUI에 JSX를 쓰는 진짜 장점은 웹용 기존 라이브러리를 재사용하는 것 정도인데, RSX는 개발자가 JSX 개념 지식을 RSX로 옮길 수 있다는 것 말고는 “이식 가능한 가치”가 작아 보임. 차라리 React/JSX 패러다임보다 객관적으로 더 낫다고 보는 새 패러다임을 배우는 편이 나은 절충임
요약하면 “SwiftUI지만 크로스 플랫폼”인 프로젝트가 있으면 좋겠는데 아직 없음. @Tokamak/TokamakUI는 알고 있지만 아직 많이 미완성이고 활동도 줄어든 듯함- https://ribir.org/가 있음
현재는 Linux/mac/windows의 네이티브 데스크톱 앱만 지원하지만 WASM, 웹, 모바일 지원 계획이 있음
- https://ribir.org/가 있음
- Freenet의 탈중앙 홈페이지를 만들려고 Dioxus를 골랐음
Freenet을 설정한 사람들이 처음 보게 될 탈중앙 웹사이트가 될 예정임. 몇 년 동안 띄엄띄엄 작업해온 Kotlin 웹 프레임워크 Kweb과도 조금 비슷한데, 특히 상태 처리와 코드에서 HTML로 매핑되는 DSL 방식이 닮았음. 지금까지는 마음에 듦
https://freenet.org/
https://kweb.io/- 멋짐. 처음 DSL을 설계할 때 kweb을 봤던 것 같고 둘이 정말 비슷함
사실 Kotlin의 팬이고, Kotlin DSL과 동시성 모델을 좋아함
- 멋짐. 처음 DSL을 설계할 때 kweb을 봤던 것 같고 둘이 정말 비슷함
- Tauri와 비교하면 어떤지 궁금함
- README에 그 내용을 적어두었음: https://github.com/dioxusLabs/dioxus/?tab=readme-ov-file#dioxus-vs-tauri
Tauri는 프런트엔드를 웹뷰에 넣고, 네이티브 Rust 함수와는 Electron처럼 IPC 경계를 통해 통신해야 함
Dioxus에서는 Rust 코드가 네이티브 쪽에 있으므로 파일 시스템 읽기, 웹소켓 같은 작업에 IPC가 필요 없음. Tauri는 프런트엔드를 WASM으로 컴파일하도록 강제하고, 흥미로운 Rust 크레이트 중에는 wasm으로 컴파일되지 않는 것도 많음
IPC 경계가 없을 때 개발이 얼마나 단순해지는지는 말로 표현하기 어렵다. Dioxus 도구는 Rust만을 대상으로 하므로 0에서 번들된.app까지 1분 이내에 갈 수 있음. 새 빌드 12초, 새 번들 20초 정도임
그래도 Tauri가 주는 유연성, 즉 웹 호환 UI라면 무엇이든 프런트엔드로 쓸 수 있다는 점을 크게 좋아하고, Tauri 앱 안에서 Dioxus를 쓸 수도 있음 - 나도 이 질문을 하려고 들어왔음
Dioxus가 README에서 직접 다룬 건 좋았지만, 둘 다 써본 사람들의 실제 경험도 궁금함
Tauri로 장난감 데스크톱 앱을 만들어 봤는데, 웹 프런트엔드가 키 입력마다 갱신하고 작업해도 지연이 없을 만큼 IPC가 빠른지는 확인했고 답은 “그렇다”였음. 큰 파일을 키 입력마다 프런트엔드에서 Rust 계층으로 보내고 다시 프런트엔드로 돌려받을 수 있는지는, 적어도 내 순진한 구현에서는 “아니다”였음
Tauri와 Dioxus 모두 괜찮은 사례가 많고, 어떤 사례에서는 Dioxus가 더 나을 듯함. “우리 프로젝트에서는 X와 Y 때문에 Dioxus 또는 Tauri를 골랐다” 같은 비교 경험담을 듣고 싶음. Dioxus는 정말 멋져 보여서 써보는 게 기대됨
- README에 그 내용을 적어두었음: https://github.com/dioxusLabs/dioxus/?tab=readme-ov-file#dioxus-vs-tauri
- 네이티브 앱은 어떻게 렌더링하는지 궁금함. 여전히 어떤 종류의 브라우저 인스턴스 안에서 도는 건가?
- 렌더러로 시스템 웹뷰를 쓰거나, stylo를 가져온 실험적인 WGPU 기반 엔진을 선택할 수 있음
stylo는 Servo에서 Firefox와 공유되는 부분임. 장기적으로는 사람들을 WGPU 렌더러로 옮기고 싶지만 아직 꽤 초기 상태이고, Dioxus를 쓰는 많은 회사는 웹뷰가 앱의 90% 정도에는 충분히 좋은 해법이라는 걸 현실적으로 알고 있음
- 렌더러로 시스템 웹뷰를 쓰거나, stylo를 가져온 실험적인 WGPU 기반 엔진을 선택할 수 있음
- “0.5 릴리스 주기 동안 여러 의존성에 남아 있는 아주 작은 unsafe를 제거할 계획”이라는 부분에서, 그 사용처가 무엇이고 동기가 무엇인지 보고 싶음
사람들이 때때로unsafe를 너무 쉽게 쓰는 건 이해하지만, 표준 라이브러리도unsafe로 가득하고 그 선을 거기에 긋는 건 가끔 모래 위에 선을 긋는 것처럼 보임- 대부분 FFI와 상호작용하거나 일부 타입을 Send/Sync로 선언하는 데 필요함
세 곳에서 사용 중임. iOS의 일부 FFI 수정, signal에 함수 호출 문법을 가능하게 하기 위한 구현, 포인터를 해시로 쓰는 ID에 Send/Sync를 구현하는 부분임
마지막 것은 지금 보니usize로 대체하면 제거할 수도 있을 것 같음 - 사람들이
unsafe를 조금 과하게 두려워할 수 있다는 데 동의함
그래도 크레이트 작성자가 자기 크레이트에서unsafe제거를 목표로 삼는 게 반드시 나쁜 판단은 아님
모든unsafe를 제거하려는 크레이트 작성자는 사용자가 져야 할 신뢰 부담을 줄이려는 경우가 많음. 이것이unsafe키워드의 힘이라고 봄. 사실trust_me블록과check_yourself함수로 나뉘었어야 했을지도 모름
unsafe는 메모리 안전성 대화를 코드의 매우 좁고 감사 가능한 위치로 제한하고, 동시에 신뢰에 대한 새롭고 관리 가능한 대화를 만들어 줌
- 대부분 FFI와 상호작용하거나 일부 타입을 Send/Sync로 선언하는 데 필요함
- React가 훅 API에
use*명명 규칙을 만든 이유는 이해하지만, Dioxus에서 새 signal을 만드는 함수가 왜use_signal인지 궁금함
let mut count = use_signal(|| 0);는 새 signal을 만드는 호출 아닌가? signal은 렌더링마다 다시 만들어지지 않고, 그게 signal의 핵심임
SolidJS에서는const [count, setCount] = createSignal(0)처럼 createSignal로 signal을 만들고, 이쪽이 훨씬 이해하기 쉬움
API 이름은 중요함. 상태 훅은 다르게 동작하고useMemo같은 보완 요구도 생길 수 있기 때문임. Dioxus가 React에 가깝게 보이려는 것 말고use_signal이라는 이름을 고른 이유가 있는지 궁금함- Dioxus는 여전히 컴포넌트를 다시 렌더링하지만, 컴포넌트가 생성하는 rsx에 많은 최적화를 적용해서 Solid에 가까운 성능을 냄
Solid보다는 Preact에 더 가까움
최적화에는 UI의 동적 조각을 별도 “diff bin”으로 분리하는 것, 기본 메모이제이션, signal이 속성을 암묵적으로 dirty/managed로 표시하는 것이 포함됨
- Dioxus는 여전히 컴포넌트를 다시 렌더링하지만, 컴포넌트가 생성하는 rsx에 많은 최적화를 적용해서 Solid에 가까운 성능을 냄