Leptos를 활용한 풀스택 웹 애플리케이션 개발
1. 서론: Rust 웹 개발의 새로운 패러다임, Leptos
본 보고서는 Rust 기반의 현대적 풀스택 웹 프레임워크인 Leptos를 활용한 애플리케이션 개발에 대한 심층적인 기술 분석을 제공하는 것을 목적으로 한다. Leptos는 단순한 사용자 인터페이스(UI) 라이브러리를 넘어, Rust 언어의 고유한 장점인 성능, 메모리 안전성, 강력한 타입 시스템을 웹 개발의 전 영역—프론트엔드와 백엔드를 아우르는—에 적용하고자 하는 시도의 결정체이다. 이는 동일한 코드가 서버와 클라이언트 양쪽에서 실행될 수 있는 동형(isomorphic) 아키텍처를 통해 구현되며, 개발자에게 통합된 개발 경험을 제공한다.1
본 보고서는 Rust 언어의 기본 문법과 최신 웹 프레임워크(예: React, Vue, Svelte)의 핵심 개념에 대한 사전 지식을 갖춘 개발자를 대상으로 한다. 보고서의 목표는 Leptos의 철학적 배경과 핵심 아키텍처에 대한 깊이 있는 이해를 바탕으로, 실제 프로덕션 수준의 애플리케이션을 구축하는 데 필요한 구체적이고 실용적인 기술 지식을 전달하는 것이다.3
보고서의 구성은 다음과 같다. 첫째, Leptos의 설계 철학과 가상 DOM을 배제한 미세-입자 반응성(Fine-Grained Reactivity) 아키텍처를 분석한다. 둘째, 시그널(Signal), 컴포넌트(Component), 서버 함수(Server Function) 등 프레임워크를 구성하는 핵심 요소들의 내부 작동 원리를 심도 있게 탐구한다. 셋째, 렌더링 전략에 따른 개발 환경 구축 방법을 안내하고, cargo-leptos를 활용한 표준 프로젝트 구조를 분석한다. 넷째, 라우팅, 비동기 데이터 처리, 데이터베이스 연동 및 스타일링을 포함한 실전 풀스택 애플리케이션 구현 과정을 상세히 다룬다. 마지막으로, 인증, 오류 처리, 프로덕션 배포 전략과 같은 고급 주제를 논의하고, Leptos 생태계의 현재와 미래를 조망하며 결론을 맺는다.
2. Leptos 프레임워크의 철학과 핵심 아키텍처
이 장에서는 Leptos를 구성하는 근본적인 설계 원칙과 기술적 구조를 분석한다. 가상 DOM(Virtual DOM)을 사용하지 않고 미세-입자 반응성 모델을 채택한 아키텍처적 결정이 성능과 개발자 경험에 어떠한 영향을 미치는지 심도 있게 탐구한다.
2.1 Leptos의 어원과 철학: ‘가볍고, 정제된’
Leptos(λεπτός)는 고대 그리스어에서 유래한 단어로, ’가늘고, 가볍고, 정제된, 미세-입자의’라는 의미를 내포한다. 이 이름은 프레임워크의 핵심 아키텍처인 미세-입자 반응성 모델을 직접적으로 상징하며, 최소한의 오버헤드로 UI를 정밀하게 제어하려는 설계 목표를 반영한다.2
Leptos의 또 다른 중요한 철학은 웹 표준을 존중하고 이를 기반으로 기능을 확장하는 점진적 향상(Progressive Enhancement)에 있다. HTML의 기본 요소인 <a> 태그와 <form> 태그는 JavaScript나 WebAssembly(WASM)가 로드되지 않은 환경에서도 본연의 기능대로 동작한다. Leptos는 이러한 표준 동작을 기반으로, 클라이언트 측 라우팅이나 비동기 폼 제출과 같은 향상된 기능을 ‘덧입히는’ 방식으로 작동한다. 이는 초기 페이지 로딩 성능을 극대화하고, JavaScript를 사용할 수 없는 환경에서도 기본적인 기능성을 보장하는 견고한 애플리케이션을 구축할 수 있게 한다. 이러한 접근 방식은 모든 것을 JavaScript 런타임에 의존하는 다수의 SPA(Single-Page Application) 프레임워크와 Leptos를 구분 짓는 중요한 철학적 차이점이다.2
2.2 핵심 아키텍처: 가상 DOM(Virtual DOM)의 부재와 미세-입자 반응성(Fine-Grained Reactivity)
Leptos 아키텍처의 가장 큰 특징은 가상 DOM(Virtual DOM)을 사용하지 않고, 미세-입자 반응성 모델을 채택했다는 점이다. 이는 UI 업데이트 방식에 대한 근본적인 패러다임의 차이를 의미하며, 성능에 지대한 영향을 미친다.
React, Yew, Dioxus와 같은 프레임워크는 가상 DOM 모델을 기반으로 동작한다. 이 모델에서 상태가 변경되면, 프레임워크는 해당 상태에 의존하는 컴포넌트 함수를 재실행하여 새로운 가상 DOM 트리를 생성한다. 이후, 이전 가상 DOM 트리와 새로운 트리를 비교(diffing)하여 변경된 부분을 찾아내고, 이 변경 사항만을 실제 DOM에 적용(patch)한다. 이 방식은 개발자가 직접 DOM을 조작하는 복잡함에서 벗어나 ’UI는 상태의 함수’라는 선언적 모델에 집중할 수 있게 해주었으나, 상태 변경 시마다 컴포넌트 재실행과 트리 비교에 따른 계산 오버헤드를 필연적으로 수반한다.5
반면, Leptos와 SolidJS가 채택한 미세-입자 반응성 모델은 전혀 다른 방식으로 UI를 업데이트한다. 이 모델에서 컴포넌트 함수는 초기 렌더링 시 단 한 번만 실행되어 실제 DOM 노드를 생성하고 UI 구조를 설정한다. 이 과정에서 ’시그널(Signal)’이라는 반응성 기본 단위(primitive)가 상태와 UI 요소를 연결한다. 시그널의 값이 변경되면, 프레임워크는 가상 DOM 비교와 같은 중간 과정 없이 해당 시그널을 구독하고 있는 특정 DOM 노드(예: 텍스트 노드, 클래스 속성)를 직접, 그리고 즉시 업데이트한다. 이는 UI 업데이트가 필요한 최소한의 작업만을 수행하도록 보장하여 극도로 높은 성능을 달성하게 한다.1
이러한 아키텍처 차이는 벤치마크 결과에서도 명확히 드러난다. 가상 DOM 비교 과정의 오버헤드가 제거됨으로써, Leptos는 UI 생성 및 업데이트 속도에서 대부분의 가상 DOM 기반 프레임워크보다 월등한 성능을 보인다.7
Leptos의 아키텍처 선택은 단순히 성능 향상만을 목표로 하지 않는다. 이는 웹 개발 패러다임에 대한 근본적인 재고를 반영한다. 가상 DOM은 ’UI는 상태의 함수’라는 선언적 모델을 구현하기 위한 효과적인 추상화 계층이었지만, 그 자체로 성능적 비용을 내포하고 있었다. 미세-입자 반응성 모델은 이 선언적 패러다임을 유지하면서도, 반응성 그래프 추적과 같은 작업을 프레임워크(또는 컴파일러) 수준에서 처리하여 런타임의 부담을 최소화하는 방향으로의 진화를 의미한다. 따라서 Leptos를 채택하는 것은 단순히 개발 언어를 JavaScript에서 Rust로 바꾸는 것을 넘어, UI 렌더링에 대한 보다 현대적이고 성능 중심적인 아키텍처를 수용하는 것을 의미한다. 이는 개발자에게 시그널, 이펙트 등 반응성 시스템의 원리에 대한 더 깊은 이해를 요구하지만, 궁극적으로는 고도로 최적화된 애플리케이션을 구축할 수 있는 기반을 제공한다.
2.2.1 핵심 테이블 1: Leptos와 주요 웹 프레임워크 비교
Leptos의 기술적 위상을 명확히 하기 위해, 다른 주요 웹 프레임워크와의 핵심적인 차이점을 아래 표로 정리하였다. 이 비교는 개발자가 각 프레임워크의 특성을 이해하고 프로젝트 요구사항에 맞는 기술 스택을 선택하는 데 도움을 줄 것이다.3
| 특징 (Feature) | Leptos | SolidJS | React | Yew/Dioxus |
|---|---|---|---|---|
| 언어 (Language) | Rust | JavaScript/TypeScript | JavaScript/TypeScript | Rust |
| 반응성 모델 | 미세-입자 (시그널) | 미세-입자 (시그널) | 가상 DOM (Hooks) | 가상 DOM (Hooks-like) |
| 주요 장점 | 성능, 타입/메모리 안전성, 풀스택 통합 | 성능, 성숙한 JS 생태계 | 거대한 생태계, 풍부한 자료 | Rust로 React-like 개발 |
| 풀스택 지원 | 내장 (서버 함수) | SolidStart (메타 프레임워크) | Next.js (메타 프레임워크) | 제한적/프레임워크별 지원 |
| 생태계 성숙도 | 성장 중 | 중간 | 매우 성숙 | 성장 중 |
이 표에서 볼 수 있듯, Leptos는 ’Rust 언어의 안정성과 성능’이라는 장점과 ’SolidJS의 현대적인 미세-입자 반응성 아키텍처’를 결합한 독특한 위치를 점하고 있다.
2.3 동형(Isomorphic) 프레임워크로서의 Leptos
Leptos는 동형(isomorphic) 프레임워크로 설계되었다. 이는 동일한 Rust 코드가 서버와 클라이언트(브라우저) 환경 모두에서 실행될 수 있음을 의미한다. 이러한 특성 덕분에 Leptos는 애플리케이션의 요구사항에 따라 다양한 렌더링 전략을 유연하게 선택하고 조합할 수 있는 강력한 기능을 제공한다.2
Leptos가 지원하는 주요 렌더링 전략은 다음과 같다.
- CSR (Client-Side Rendering): 브라우저에서 WebAssembly(WASM)를 다운로드하여 실행하고, 클라이언트 측에서 모든 UI를 렌더링하는 전통적인 SPA(Single-Page Application) 방식이다.
trunk와 같은 도구를 사용하여 비교적 간단하게 구축할 수 있다.15 - SSR (Server-Side Rendering): 사용자가 페이지를 요청할 때마다 서버에서 완전한 HTML을 생성하여 응답하는 방식이다. 이는 초기 페이지 로딩 속도를 크게 향상시키고 검색 엔진 최적화(SEO)에 유리하다. 사용자는 상호작용이 없는 정적인 페이지를 즉시 보게 된다.15
- SSR with Hydration: SSR의 장점과 CSR의 장점을 결합한 가장 강력한 모델이다. 서버는 초기 요청에 대해 완전한 HTML을 렌더링하여 전송하고, 브라우저는 이 HTML을 즉시 사용자에게 보여준다. 그 후 백그라운드에서 WASM 번들을 다운로드하여 실행하고, 서버에서 렌더링된 정적 HTML 위에 이벤트 리스너와 반응성 상태를 ‘덧입히는(hydrate)’ 과정을 거친다. 이 과정을 통해 페이지는 완전한 상호작용이 가능한 SPA로 전환된다.15
- Islands Architecture: 이는 실험적인 기능으로, 페이지의 대부분은 정적인 HTML로 유지하면서 상호작용이 필요한 특정 컴포넌트(섬, Island)만을 선택적으로 Hydration하는 방식이다.
#[island]매크로를 사용하여 지정된 컴포넌트만 WASM 번들에 포함되므로, 전체 WASM 페이로드 크기를 획기적으로 줄여 초기 로딩 성능을 극대화할 수 있다.13
이처럼 다양한 렌더링 전략을 단일 코드베이스 내에서 선택적으로 적용할 수 있다는 점은 Leptos가 복잡한 요구사항을 가진 현대적인 웹 애플리케이션을 구축하는 데 매우 적합한 프레임워크임을 보여준다.
2.4 Rust 언어의 특성과 시너지
Leptos는 Rust 언어의 핵심적인 가치를 웹 개발에 그대로 이식하여 다른 언어로 작성된 프레임워크와 차별화되는 강력한 이점을 제공한다.
- 성능: Rust는 C/C++에 필적하는 네이티브 수준의 성능을 제공한다. 이는 서버 측 렌더링 및 비즈니스 로직 처리에서 높은 처리량을 보장하며, 클라이언트 측에서는 WASM으로 컴파일되어 복잡한 계산을 JavaScript보다 효율적으로 수행할 수 있다.1
- 메모리 안전성: Rust의 가장 독보적인 특징인 소유권(Ownership) 시스템과 빌림 검사기(Borrow Checker)는 컴파일 시점에 데이터 경합(data races), 널 포인터 역참조(null pointer dereferences)와 같은 메모리 관련 버그를 원천적으로 방지한다. 이는 런타임에 발생할 수 있는 예측 불가능한 오류를 크게 줄여 애플리케이션의 안정성과 보안성을 극대화한다.8
- 동시성: Rust는 두려움 없는 동시성(fearless concurrency)을 모토로, 멀티스레드 환경에서 안전하게 코드를 작성할 수 있는 강력한 도구를 제공한다. 이는 높은 트래픽을 처리해야 하는 웹 서버 백엔드를 구축할 때 특히 유용하다.1
- 강력한 타입 시스템: 정적 타입 언어인 Rust는 컴파일 시점에 타입 오류를 잡아내어 런타임 오류의 가능성을 줄인다. 또한,
Option<T>과Result<T, E>와 같은 내장 타입을 통해 데이터의 존재 유무나 연산의 성공/실패 여부를 명시적으로 처리하도록 강제하여 더욱 견고한 코드를 작성하게 한다.8
Leptos는 이러한 Rust의 특성을 적극적으로 활용한다. 특히, 상태 관리를 위한 시그널(Signal)은 Copy 트레이트를 구현하도록 설계되어, Rust의 까다로운 소유권 규칙을 개발자가 크게 신경 쓰지 않고도 반응형 코드를 쉽게 작성할 수 있도록 돕는다. 이는 Rust의 안정성은 유지하면서도 다른 프론트엔드 프레임워크와 유사한 수준의 개발 편의성을 제공하려는 영리한 설계 결정이다.1
3. Leptos의 구성 요소: 심층 탐구
이 장에서는 Leptos 애플리케이션을 구성하는 핵심 요소들을 개별적으로 분석하여 그 내부 작동 원리와 효과적인 사용법을 상세히 기술한다. 반응성 시스템의 근간을 이루는 ’시그널’부터 UI의 구조를 정의하는 ’컴포넌트’와 ‘뷰 매크로’, 그리고 풀스택 개발의 핵심인 ’서버 함수’에 이르기까지 각 요소의 기술적 특성을 깊이 있게 탐구한다.
3.1 반응성 시스템의 심장: 시그널(Signals)과 이펙트(Effects)
Leptos의 반응성 시스템은 ’시그널(Signals)’과 ’이펙트(Effects)’라는 두 가지 핵심 프리미티브를 기반으로 구축된다. 시그널은 변화를 추적할 수 있는 상태 값을 의미하며, 이펙트는 시그널의 변화에 반응하여 특정 코드를 실행하는 역할을 한다.
create_signal: 반응성 상태를 생성하는 가장 기본적인 함수이다. 이 함수는 상태 값을 읽을 수 있는 ’게터(getter)’와 값을 수정할 수 있는 ’세터(setter)’로 구성된 튜플을 반환한다. 게터는ReadSignal<T>타입, 세터는WriteSignal<T>타입이며, 두 기능을 합친RwSignal<T>타입도 제공된다. 이 시그널들은Copy트레이트를 구현하고 있어, 소유권 문제 없이 클로저나 자식 컴포넌트로 쉽게 전달할 수 있다.1- 파생 시그널(Derived Signals)과 메모(Memos): 다른 시그널의 값에 의존하여 새로운 값을 계산하는 기능이다. 단순한 클로저를 사용하면 해당 값이 필요할 때마다 계산이 다시 수행된다. 반면,
create_memo를 사용하면 의존하는 시그널이 변경되었을 때만 계산을 다시 수행하고 그 결과를 캐싱하여 불필요한 연산을 방지한다. 이는 복잡한 계산을 최적화하는 데 필수적이다.15 create_effect: 하나 이상의 시그널을 구독하고, 그 시그널들의 값이 변경될 때마다 주어진 클로저(부수 효과)를 실행한다. 이펙트는 반응성 시스템 내부의 상태 변화를 외부 세계(예: DOM 업데이트, 콘솔 로그, 로컬 스토리지 쓰기)와 동기화하는 역할을 한다. Leptos의 뷰 렌더러는 내부적으로create_effect를 사용하여 시그널의 변화를 감지하고 DOM을 자동으로 업데이트하므로, 개발자가 직접 DOM 조작을 위한 이펙트를 작성할 필요는 거의 없다.15- 반응성 그래프(Reactive Graph): 내부적으로 Leptos는 시그널, 메모, 이펙트를 노드로 하는 방향성 비순환 그래프(DAG)를 구축한다. 시그널은 소스 노드, 이펙트는 터미널 노드, 메모는 중간 노드 역할을 한다. 상태 변경이 발생하면, 이 그래프를 따라 변경 사항이 효율적으로 전파되어 꼭 필요한 이펙트만 최소한으로 실행된다. 이 메커니즘이 미세-입자 반응성의 핵심이며, 높은 성능을 보장하는 기반이 된다.19
Leptos의 시그널 디자인은 Rust의 가장 큰 진입 장벽 중 하나인 소유권 및 생명주기 문제를 웹 프론트엔드 개발이라는 특수한 맥락에서 영리하게 해결한 사례이다. Copy 트레이트를 구현한 ReadSignal과 WriteSignal은 내부적으로 상태 저장소에 대한 ID나 포인터를 가지는 가벼운 구조체이다. 따라서 이들을 클로저로 전달할 때 move 키워드를 사용하더라도 실제 상태 데이터가 이동하는 것이 아니라, 이 가벼운 핸들만 복사된다. 이로 인해 여러 이벤트 핸들러나 컴포넌트가 동일한 상태에 대한 소유권 충돌 없이 안전하고 쉽게 접근하고 수정할 수 있게 된다. 이는 React의 useState 훅이 반환하는 상태 값과 세터 함수를 의존성 배열의 복잡한 관리 없이 클로저 내에서 자유롭게 사용하는 것과 유사한 수준의 인체공학적 개발 경험을 제공한다. 이 설계는 Rust의 컴파일 타임 안정성은 그대로 유지하면서도, 프론트엔드 개발에서 빈번하게 발생하는 상태 공유 문제에 대한 실용적인 해결책을 제시하며, ’Rust는 UI 개발에 너무 복잡하다’는 통념을 극복하는 데 핵심적인 역할을 한다.
3.2 UI 구성의 빌딩 블록: 컴포넌트(Components)와 Props
Leptos에서 UI는 재사용 가능한 컴포넌트의 조합으로 구성된다. 컴포넌트는 UI의 특정 부분에 대한 구조와 동작을 캡슐화하는 단위이다.
#[component]매크로: 이 매크로는 일반 Rust 함수를 Leptos 컴포넌트로 변환하는 역할을 한다. 매크로가 적용된 함수는view!매크로 내에서 JSX의 커스텀 태그처럼 사용될 수 있다. 컴포넌트의 이름은 다른 HTML 요소와 구분하기 위해 항상 파스칼 케이스(PascalCase) 규칙을 따라야 한다.1- 컴포넌트 생명주기: Leptos 컴포넌트 함수의 가장 중요한 특징은, 상태가 변경될 때마다 재실행되는 ’렌더링 함수’가 아니라, 컴포넌트가 처음 마운트될 때 단 한 번만 실행되는 ’설정 함수(setup function)’라는 점이다. 이 함수 내에서 반응성 상태(시그널)를 초기화하고, 이벤트 핸들러를 정의하며, UI의 정적인 구조를 생성한다. 이후의 모든 UI 업데이트는 이 설정 단계에서 구축된 반응성 시스템을 통해 이루어진다.7
- Props 전달: 컴포넌트에 데이터를 전달하기 위해 함수 인자를 사용하며, 이를 ’props’라고 부른다.
view!매크로에서 컴포넌트를 사용할 때 HTML 속성과 유사한 구문으로 props를 전달할 수 있다. 만약 prop으로 전달되는 값이 시간에 따라 변해야 한다면, 반드시 일반 값이 아닌 시그널 타입(예:ReadSignal<T>)으로 전달해야 반응성을 유지할 수 있다.8 - Prop 커스터마이징: 개별 prop에
#[prop(...)]속성을 추가하여 동작을 변경할 수 있다. 예를 들어,#[prop(into)]는 전달된 값에 자동으로.into()를 호출하여 타입을 변환해주고,#[prop(optional)]이나#[prop(default =...)]는 해당 prop을 선택적으로 만들거나 기본값을 지정할 수 있게 해준다.22 - 자식(Children) 컴포넌트 전달: 컴포넌트 태그 사이에 위치하는 내용은
children이라는 특별한 prop으로 전달된다. 이childrenprop은 여러 타입을 가질 수 있다.Children은 한 번만 렌더링할 수 있는 자식들을,ChildrenFn은 여러 번 렌더링할 수 있는 자식들을 나타낸다.ChildrenFragment는 자식들을Vec으로 받아 반복 처리와 같은 조작을 가능하게 한다. 또한,#[slot]매크로를 사용하면 여러 개의 명명된 자식 그룹(슬롯)을 정의하여 복잡한 레이아웃 컴포넌트를 만들 수 있다.25
3.3 선언적 UI 작성을 위한 view! 매크로
view! 매크로는 Leptos에서 UI를 선언적으로 작성하기 위한 핵심 도구이다. 이는 JSX(JavaScript XML)와 유사한 RSX(Rust Syntax Extension)라는 도메인 특화 언어(DSL)를 사용하여, Rust 코드 내에서 HTML과 유사한 구문으로 UI 구조를 기술할 수 있게 한다.7
- 동적 속성(Dynamic Attributes):
view!매크로는 정적인 HTML 구조뿐만 아니라 동적인 UI 변경을 위한 특별한 구문을 제공한다.class:[class-name]=구문은 불리언 값을 반환하는 클로저를 받아, 그 결과가true일 때만 해당 CSS 클래스를 요소에 추가하거나 제거한다. 마찬가지로style:[property-name]=구문을 사용하여 개별 CSS 속성을 동적으로 변경할 수 있다. 이러한 동적 속성에 시그널을 사용하는 클로저를 전달하면, 시그널 값이 변경될 때마다 속성이 자동으로 업데이트된다.28 - 이벤트 핸들링:
on:[event-name]구문을 사용하여 DOM 이벤트를 처리하는 콜백 함수(클로저)를 등록할 수 있다. 예를 들어,on:click=move |_| {... }는 클릭 이벤트가 발생했을 때 주어진 클로저를 실행한다. 클로저 내에서 시그널의 세터를 호출하여 상태를 변경하면, 해당 시그널에 의존하는 UI 부분이 자동으로 업데이트된다.1
3.4 풀스택 통합의 열쇠: 서버 함수(Server Functions)
서버 함수는 Leptos의 풀스택, 동형(isomorphic) 아키텍처를 구현하는 핵심 기능이다. #[server] 매크로를 사용하여 정의된 함수는 클라이언트와 서버의 경계를 매끄럽게 넘나들 수 있게 해준다.1
-
개념 및 작동 원리:
#[server]가 붙은 함수는 컴파일 타겟에 따라 다르게 변환된다. -
서버 빌드(
ssr피처 활성화 시): 함수 본문이 그대로 포함되어, 데이터베이스 조회나 파일 시스템 접근과 같은 서버 측 로직을 수행하는 일반적인 비동기 Rust 함수로 컴파일된다. 또한, 이 함수를 호출할 수 있는 고유한 API 엔드포인트가 자동으로 생성된다.14 -
클라이언트 빌드(hydrate 또는 csr 피처 활성화 시): 함수 본문은 제거되고, 대신 서버에 생성된 API 엔드포인트로 네트워크 요청(fetch)을 보내는 스텁(stub) 코드로 대체된다. 이 스텁은 함수의 인자를 직렬화하여 요청 본문에 담고, 서버로부터 받은 응답을 역직렬화하여 반환한다.14
이러한 변환 덕분에 개발자는 클라이언트 측 코드에서 마치 일반 비동기 함수를 호출하는 것처럼 서버 함수를 사용할 수 있으며, 복잡한 API 클라이언트 코드를 작성할 필요가 없어진다.
-
REST API와의 비교: 전통적인 REST API 개발 방식에서는 클라이언트의 데이터 요청 로직, 서버의 API 엔드포인트 로직, 그리고 둘 사이의 데이터 형식(API 명세)을 별도로 정의하고 관리해야 한다. 반면, 서버 함수는 이러한 것들을 단일 Rust 함수 정의로 통합한다. 함수의 시그너처 자체가 API 명세가 되며, 타입 시스템을 통해 클라이언트와 서버 간의 데이터 형식이 컴파일 시점에 보장된다. 이는 개발 생산성을 크게 향상시키고, API 불일치로 인한 런타임 오류를 줄여준다.14
-
기술적 제약사항: 서버 함수는 몇 가지 중요한 제약사항을 가진다. 첫째, 클라이언트에서의 호출은 네트워크 요청을 수반하므로 항상
async함수여야 한다. 둘째, 네트워크 통신과 직렬화/역직렬화 과정에서 오류가 발생할 수 있으므로, 반환 타입은 반드시Result<T, ServerFnError>형태여야 한다. 셋째, 함수의 인자와 반환 타입은 네트워크를 통해 전송될 수 있도록serde를 통해 직렬화 및 역직렬화가 가능해야 한다. 마지막으로, 현재 버전에서는 제네릭 함수를 서버 함수로 직접 정의할 수 없다.14
4. 개발 환경 구축 및 프로젝트 설정
이 장에서는 Leptos 애플리케이션 개발을 시작하기 위한 구체적인 환경 설정 과정을 안내한다. 애플리케이션의 렌더링 전략에 따라 적합한 빌드 도구를 선택하는 방법부터, cargo-leptos를 이용한 표준 프로젝트의 구조화, 그리고 개발 생산성을 극대화하기 위한 다양한 설정 팁까지 실용적인 내용을 다룬다.
4.1 렌더링 전략과 도구 선택: trunk vs. cargo-leptos
Leptos 프로젝트는 주로 채택하는 렌더링 전략에 따라 trunk 또는 cargo-leptos라는 두 가지 주요 빌드 도구를 사용한다.
- CSR (Client-Side Rendering) with trunk:
trunk는 Rust로 작성된 WebAssembly 애플리케이션을 위한 제로-설정(zero-configuration) 웹 앱 번들러이다. CSR 방식의 Leptos 앱을 개발할 때 주로 사용된다.16
- 설정 과정:
cargo install trunk명령어로trunk를 설치한다.rustup target add wasm32-unknown-unknown명령어로 WASM 컴파일 타겟을 추가한다.- 프로젝트 루트에
index.html파일을 생성하고,<body>태그를 포함한 기본 HTML 구조를 작성한다. main.rs파일에서leptos::mount_to_body함수를 사용하여 루트 컴포넌트를<body>에 마운트한다.trunk serve --open명령어를 실행하여 개발 서버를 시작하고 브라우저에서 앱을 확인한다.9
-
장단점:
trunk를 사용한 CSR 방식은 빌드 속도가 빠르고 개발 반복 주기가 짧으며, 결과물이 정적 파일(HTML, JS, WASM)이므로 GitHub Pages나 Vercel과 같은 정적 호스팅 서비스에 쉽게 배포할 수 있다. 그러나 초기 로딩 시 전체 WASM 번들을 다운로드해야 하므로 초기 페이지 로딩 속도가 느릴 수 있으며, 일반적인 SPA와 마찬가지로 검색 엔진 최적화(SEO)에 어려움이 있을 수 있다.16 -
SSR (Server-Side Rendering) with cargo-leptos:
cargo-leptos는 SSR 및 Hydration을 사용하는 풀스택 Leptos 애플리케이션을 위해 특별히 설계된 빌드 도구이다. 이는 서버용 네이티브 바이너리와 클라이언트용 WASM 바이너리의 분리된 빌드, 에셋 번들링, 그리고 개발 서버 실행 과정을 통합하여 관리한다.2
- 설정 과정:
cargo install cargo-leptos명령어로cargo-leptos를 설치한다.cargo leptos new --git <template-url>명령어를 사용하여 Axum 또는 Actix 기반의 스타터 템플릿으로 새 프로젝트를 생성한다.- 생성된 프로젝트 디렉토리에서
cargo leptos watch명령어를 실행하면, 서버와 클라이언트 코드의 변경 사항을 감지하여 자동으로 재빌드하고 브라우저를 새로고침하는 개발 서버가 실행된다.7
- 장단점: SSR 방식은 서버에서 HTML을 미리 렌더링하여 전송하므로 초기 로딩 성능이 우수하고 SEO에 매우 유리하다. 또한 서버 함수를 통해 백엔드 로직과 완벽하게 통합된다. 반면, 코드 변경 시 서버와 클라이언트를 모두 재컴파일해야 하므로 개발 반복 속도가 CSR에 비해 느릴 수 있으며, Hydration 과정의 추가적인 복잡성을 고려해야 한다.16
4.2 cargo-leptos 프로젝트 구조 분석 (Axum 템플릿 기준)
cargo leptos new --git https://github.com/leptos-rs/start-axum 명령어로 생성된 프로젝트는 풀스택 개발을 위한 표준화된 구조를 제공한다.7
-
Cargo.toml의 피처 플래그:Cargo.toml파일 내에는[features]섹션이 정의되어 있다.csr,hydrate,ssr이라는 세 가지 주요 피처 플래그가 있으며, 이들은 조건부 컴파일(#[cfg(feature = "...")])에 사용된다. 예를 들어,ssr피처는 서버 빌드 시에만 활성화되어 데이터베이스 연결이나 파일 시스템 접근과 같은 서버 전용 코드를 포함시키고,hydrate또는csr피처는 클라이언트 빌드 시에만 활성화되어 브라우저 API를 사용하는 코드를 포함시킨다. 이 메커니즘을 통해 단일 코드베이스에서 서버와 클라이언트 코드를 효과적으로 분리하고 관리할 수 있다.15 -
main.rs(서버 진입점): 이 파일은 Axum 웹 서버를 설정하고 실행하는 역할을 한다. 주요 로직은 다음과 같다.
- Leptos 설정(
LeptosOptions)을 파일이나 환경 변수로부터 로드한다. leptos_axum::leptos_routes함수를 사용하여 Leptos 애플리케이션의 라우팅을 Axum 라우터에 통합한다. 이 함수는 앱의 루트 컴포넌트를 렌더링하는 핸들러와 서버 함수를 처리하는 API 엔드포인트를 자동으로 등록한다.target/site디렉토리에 생성된 정적 에셋(WASM, JS, CSS)을 서빙하기 위한 라우트를 설정한다.- 설정된 Axum 서버를 지정된 주소와 포트에서 실행한다.37
-
app.rs/lib.rs(공유 코드): 애플리케이션의 루트 컴포넌트(<App />)와 페이지 컴포넌트 등 서버와 클라이언트 양쪽에서 모두 사용되는 공유 코드가 이 파일에 위치한다. -
[package.metadata.leptos]:Cargo.toml파일 내 이 섹션은cargo-leptos의 동작을 제어하는 설정을 담고 있다. -
output-name: 생성될 JS 및 WASM 파일의 기본 이름을 지정한다. -
site-root: 빌드 결과물(서버 바이너리 제외)이 생성될 디렉토리를 지정한다 (기본값:target/site). -
site-pkg-dir: site-root 내에서 JS, WASM, CSS 파일이 위치할 하위 디렉토리를 지정한다 (기본값: pkg).
이 외에도 스타일 파일 경로, 브라우저 지원 범위 등 다양한 옵션을 설정할 수 있다.34
Leptos의 풀스택 모델은 Rust의 강력한 기능인 피처 플래그와 조건부 컴파일에 깊이 의존한다. 이는 단일 코드베이스 내에서 서버 전용 로직(예: #[cfg(feature = "ssr")] 블록 안의 데이터베이스 접근 코드)과 클라이언트 전용 로직을 명확하게 분리하여, 최종 바이너리의 크기를 최적화하고 각 환경에 불필요한 코드가 포함되지 않도록 보장하는 강력한 메커니즘이다. 하지만 이 방식은 JavaScript/TypeScript 생태계에서 런타임에 isServer와 같은 불리언 플래그로 분기하거나, *.server.ts와 같이 파일 이름 규칙으로 서버 코드를 분리하는 방식에 익숙한 개발자에게는 초기 학습 곡선을 높이는 요인이 될 수 있다. Cargo.toml에서의 피처 관리, 코드 전반에 걸친 #[cfg] 어트리뷰트 사용 등은 추가적인 인지적 부담을 야기할 수 있다.38 cargo-leptos와 스타터 템플릿은 이러한 설정의 복잡성을 상당 부분 추상화하고 표준화하여 개발자가 비즈니스 로직에 더 집중할 수 있도록 돕는 중요한 역할을 수행한다.
4.3 개발 경험(DX) 향상을 위한 설정
Leptos 개발 생산성을 높이기 위해 다음과 같은 도구와 설정을 활용할 수 있다.
console_error_panic_hook: WASM 애플리케이션에서 패닉이 발생하면 브라우저 개발자 콘솔에는 해독하기 어려운 오류가 출력되는 경우가 많다.console_error_panic_hook크레이트를 사용하면, 패닉 발생 시 Rust 소스코드의 파일명과 줄 번호를 포함한 상세한 스택 트레이스를 콘솔에 출력해주어 디버깅을 훨씬 용이하게 만든다.39leptosfmt: Rust의 기본 포맷터인rustfmt는view!매크로 내의 RSX 구문을 제대로 포맷하지 못한다.leptosfmt는view!매크로 전용 포맷터로, RSX 코드의 들여쓰기와 줄 바꿈을 일관되게 유지하여 가독성을 높여준다.cargo install leptosfmt로 설치하고, VS Code와 같은 에디터의 저장 시 자동 포맷 기능과 연동하여 사용할 수 있다.39rust-analyzer설정:rust-analyzer는 Rust를 위한 강력한 언어 서버이다. 프로젝트의.vscode/settings.json파일(VS Code 기준)에"rust-analyzer.cargo.features": ["ssr"]또는"hydrate"를 추가하면,rust-analyzer가 해당 피처를 활성화한 상태로 코드를 분석한다. 이를 통해#[cfg(feature =...)]블록 내의 코드에 대해서도 정확한 타입 추론, 자동 완성, 오류 검사 기능을 제공받을 수 있어 개발 경험이 크게 향상된다.39
5. 실전 풀스택 애플리케이션 구현
이 장에서는 실제 풀스택 애플리케이션을 구축하는 과정을 통해 Leptos의 핵심 기능들을 통합적으로 활용하는 방법을 구체적인 예제와 함께 단계별로 설명한다. 클라이언트 측 라우팅부터 비동기 데이터 처리, 데이터베이스 연동을 통한 CRUD 구현, 그리고 Tailwind CSS를 이용한 스타일링까지, 현대적인 웹 애플리케이션 개발에 필요한 전 과정을 다룬다.
5.1 페이지 네비게이션: leptos_router 활용
leptos_router는 Leptos 애플리케이션에 클라이언트 사이드 라우팅 및 상태 관리 기능을 제공하는 공식 라이브러리이다.
- 기본 설정: 라우팅 기능은
<Router>,<Routes>,<Route>라는 세 가지 핵심 컴포넌트를 조합하여 설정한다. 최상위 컴포넌트를<Router>로 감싸 라우팅 컨텍스트를 활성화하고, 페이지 콘텐츠가 변경될 위치에<Routes>를 배치한다.<Routes>내부에는 개별 경로를 정의하는<Route>컴포넌트들을 위치시킨다.41 - 경로 정의:
<Route>컴포넌트의pathprop은 URL 경로를 정의한다. 이 경로는 정적 경로(예:/about), 콜론으로 시작하는 동적 파라미터(예:/users/:id), 그리고 별표로 시작하는 와일드카드(예:/posts/*any)를 포함할 수 있다.viewprop에는 해당 경로와 일치할 때 렌더링될 컴포넌트를 지정한다.41 - 네비게이션: 페이지 간 이동에는
<A>컴포넌트를 사용한다. 이 컴포넌트는 내부적으로 HTML<a>태그를 렌더링하지만, 클릭 이벤트를 가로채 서버에 새로운 페이지를 요청하는 대신 브라우저의 History API를 사용하여 클라이언트 내에서 페이지를 전환한다. 이는 SPA의 부드러운 사용자 경험을 제공한다. 일반<a>태그와 달리 중첩된 상대 경로를 정확하게 해석하는 장점도 있다. 함수 호출을 통해 프로그래밍 방식으로 페이지를 이동해야 할 경우,use_navigate훅을 사용할 수 있다.43 - 중첩 라우팅(Nested Routing): 복잡한 UI 레이아웃을 구현할 때 중첩 라우팅을 사용할 수 있다.
<ParentRoute>컴포넌트로 공통 레이아웃을 정의하고, 그 내부에<Outlet>컴포넌트를 배치하면, 자식 라우트의 내용이<Outlet>위치에 렌더링된다. 이를 통해 상위 레이아웃을 재렌더링하지 않고 하위 페이지만 교체할 수 있어 효율적이다.42
5.2 비동기 데이터 로딩: create_resource와 <Suspense>
Leptos는 비동기 데이터 로딩을 선언적으로 처리하기 위한 강력한 프리미티브를 제공한다.
create_resource: 서버 함수나 외부 API 호출과 같은 비동기 작업을 수행하고 그 결과를 반응형으로 관리하는 핵심 기능이다.create_resource는 두 개의 클로저를 인자로 받는다:
-
소스(source) 시그널: 리소스가 의존하는 반응성 값을 정의한다. 이 소스 시그널의 값이 변경되면, 리소스는 자동으로 데이터를 다시 가져온다.
-
패처(fetcher) 함수: 소스 시그널의 값을 인자로 받아 실제 비동기 작업(Future)을 반환한다.
리소스는 로딩 중일 때는 None, 데이터 로딩이 완료되면 Some(T) 값을 가지는 시그널처럼 동작한다.15
-
<Suspense>: 비동기 리소스의 로딩 상태를 처리하는 선언적인 방법을 제공한다.<Suspense>컴포넌트로 UI의 일부를 감싸고fallbackprop에 로딩 중에 보여줄 UI(예: 스피너)를 지정하면, 감싸진 내부에서 사용되는 모든 리소스가 로딩을 완료할 때까지fallbackUI가 표시된다. 모든 리소스의 로딩이 완료되면,<Suspense>는 자동으로 실제 자식 컨텐츠를 렌더링한다. 이는 여러 비동기 요청에 대한 로딩 상태를 수동으로 관리하는 복잡함을 제거해준다.44 -
<Transition>:<Suspense>와 유사하게 동작하지만, 데이터가 다시 로드될 때(예: 소스 시그널 변경 시)fallbackUI를 즉시 보여주는 대신, 새로운 데이터가 로딩될 때까지 이전 컨텐츠를 계속 표시한다. 이는 사용자에게 데이터가 업데이트되는 동안에도 끊김 없는 경험을 제공하여 UI의 깜빡임을 방지한다.48 -
Resourcevs.LocalResource:create_resource는 SSR 환경에서 서버에서 데이터를 미리 로드하고, 그 결과를 직렬화하여 HTML과 함께 클라이언트로 전송한다. 클라이언트에서는 Hydration 과정에서 이 직렬화된 데이터를 사용하므로, 초기 로딩 시 클라이언트 측에서 다시 데이터를 요청할 필요가 없다. 반면,create_local_resource는 클라이언트 측에서만 실행되며, 서버 렌더링에는 관여하지 않는다. 브라우저 전용 API를 사용해야 하는 비동기 작업에 적합하다.44
5.3 서버 데이터 변경: create_action과 <ActionForm>
데이터 조회와 달리, 서버의 상태를 변경하는 작업(Create, Update, Delete)은 ’액션(Action)’을 통해 처리된다.
create_action: 사용자의 특정 행동(예: 폼 제출, 버튼 클릭)에 의해 촉발되는 비동기 함수를 캡슐화한다.create_resource가 선언적으로 데이터를 ‘읽는’ 데 사용된다면,create_action은 명령형으로 데이터를 ‘쓰는’ 데 사용된다.15Actionvs.Resource: 이 둘의 근본적인 차이는 실행 시점에 있다.Resource는 의존하는 소스 시그널이 변경될 때 ‘자동으로’ 실행되지만,Action은.dispatch()메서드가 명시적으로 호출될 때만 ‘수동으로’ 실행된다. 이 차이로 인해 두 프리미티브는 각각 데이터 로딩과 데이터 변경이라는 명확히 구분된 역할을 수행한다.49<ActionForm>: 서버 함수로 생성된 액션과 HTML<form>을 손쉽게 연결해주는 컴포넌트이다.actionprop에create_action으로 생성한 서버 액션을 전달하기만 하면, 폼 제출 시 해당 액션이 자동으로 디스패치된다. 이 컴포넌트의 가장 큰 장점은 점진적 향상을 완벽하게 지원한다는 것이다. JavaScript/WASM이 활성화된 환경에서는 페이지 새로고침 없이 비동기적으로 폼이 제출되지만, 비활성화된 환경에서는 일반적인 HTML 폼처럼 동작하여 서버로POST요청을 보낸다.51- 클라이언트 사이드 유효성 검사:
<ActionForm>은 일반<form>처럼submit이벤트를 발생시킨다.on:submit:capture이벤트 핸들러를 사용하여 폼 제출 이전에 클라이언트 측 유효성 검사를 수행할 수 있다.FromFormData::from_event트레이트를 사용하면submit이벤트로부터 서버 함수의 입력 타입에 맞는 데이터를 파싱하고 검증할 수 있다. 만약 유효성 검사에 실패하면, 이벤트 객체의prevent_default()메서드를 호출하여 실제 폼 제출(즉, 액션 디스패치)을 막을 수 있다.52
5.3.1 핵심 테이블 2: Leptos 비동기 프리미티브: Resource vs. Action
데이터 로딩과 데이터 변경이라는 두 가지 핵심 비동기 작업을 처리하는 Resource와 Action의 차이점을 명확하게 구분하여 개발자가 올바른 도구를 선택하도록 돕기 위해 아래 표를 제시한다.15
| 구분 | create_resource | create_action |
|---|---|---|
| 주요 목적 | 데이터 로딩 (읽기, Fetching) | 데이터 변경 (쓰기, Mutation) |
| 실행 시점 | 소스 시그널 변경 시 자동으로 실행 | .dispatch() 호출 시 수동으로 실행 |
| 주요 사용 사례 | 페이지 진입 시 데이터 로드, 검색어 변경 시 결과 업데이트 | 폼 제출, 버튼 클릭으로 항목 삭제/추가 |
| 상태 표현 | Option<T> (로딩 중 None, 완료 후 Some(T)) | input, value, pending 등 여러 시그널로 세분화 |
| 컴포넌트 연동 | <Suspense>, <Transition> | <ActionForm>, <Form> |
Resource와 Action은 분리된 개념처럼 보이지만, 서버 함수와 결합될 때 비로소 완전한 풀스택 데이터 흐름을 형성한다. 사용자가 <ActionForm>을 통해 데이터를 제출하여 Action이 실행되면, 서버 함수가 데이터베이스를 업데이트한다. 이 업데이트된 상태를 다시 화면에 반영하기 위해서는, Action의 성공적인 완료를 트리거로 삼아 관련된 Resource를 무효화(invalidate)하거나 데이터를 다시 불러오는(refetch) 패턴이 필요하다. Leptos에서는 action.version()과 같이 액션이 실행될 때마다 값이 변하는 시그널을 create_resource의 소스 시그널로 사용하여 이 패턴을 선언적으로 구현할 수 있다. 즉, Action의 성공적인 실행이 자동으로 Resource의 데이터 리프레시를 유발하게 된다. 이처럼 Resource와 Action을 연계하는 패턴을 이해하는 것이 Leptos로 복잡한 데이터 중심 애플리케이션을 구축하는 핵심이다.
5.4 데이터베이스 연동: SQLx를 이용한 CRUD 구현
Leptos 서버 함수 내에서 비동기 SQL 라이브러리인 SQLx를 사용하여 데이터베이스와 상호작용할 수 있다.
- 설정:
Cargo.toml파일에sqlx와 해당 데이터베이스 드라이버(예:postgres) 의존성을 추가한다. 이때,ssr피처 블록 내에 의존성을 명시하여, 이 코드가 클라이언트 측 WASM 번들에 포함되지 않도록 하는 것이 매우 중요하다.34 - 연결 풀(Connection Pool) 관리: 애플리케이션 시작 시 데이터베이스 연결 풀(
sqlx::PgPool등)을 생성하고, 이를 애플리케이션 상태로 관리해야 한다. Axum을 사용하는 경우,State확장이나 Leptos의provide_contextAPI를 사용하여 연결 풀을 각 요청 핸들러와 서버 함수에서 접근할 수 있도록 주입하는 것이 일반적인 패턴이다.14 - 마이그레이션:
sqlx-cli는 데이터베이스 스키마의 버전을 관리하기 위한 강력한 명령줄 도구이다.sqlx migrate add <migration_name>명령어로 새로운 마이그레이션 파일을 생성하고, SQL을 작성한 뒤,sqlx migrate run명령어로 데이터베이스에 변경 사항을 적용할 수 있다.revert명령어를 통해 이전 상태로 롤백하는 것도 가능하다.54 - CRUD 구현: 서버 함수는 일반적인 비동기 Rust 함수이므로, 그 안에서 SQLx를 사용하여 데이터베이스 작업을 수행할 수 있다.
sqlx::query!또는sqlx::query_as!매크로를 사용하면 컴파일 시점에 SQL 쿼리의 유효성을 검사하여 타입 안전성을 높일 수 있다.INSERT,SELECT,UPDATE,DELETE등의 CRUD 작업을 수행하는 서버 함수를 각각 정의하고, 이를 프론트엔드에서는create_resource나create_action을 통해 호출하여 사용한다.1
5.5 스타일링 전략: Tailwind CSS 통합 가이드
Leptos 자체는 특정 스타일링 방식에 대한 의견을 가지고 있지 않으며, 개발자가 다양한 전략을 선택할 수 있도록 유연성을 제공한다.61
- 다양한 스타일링 옵션: 일반 CSS 파일을
index.html에 링크하는 방식,stylers나styled와 같은 CSS-in-Rust 라이브러리를 사용하는 방식, 그리고 현재 가장 널리 사용되는 유틸리티-우선(utility-first) 방식인 Tailwind CSS를 통합하는 방법 등이 있다.61 - Tailwind CSS 설정:
cargo-leptos는 Tailwind CSS 통합을 위한 빌드 파이프라인을 내장하고 있어 설정이 비교적 간단하다.
npm을 통해tailwindcss를 설치하고tailwind.config.js파일을 생성한다.content설정에 Rust 소스 파일(*.rs)과index.html을 포함시켜 Tailwind가 클래스 이름을 스캔할 수 있도록 한다.style/input.css와 같은 소스 CSS 파일을 만들고@tailwind지시문을 추가한다.Cargo.toml의[package.metadata.leptos]섹션에tailwind-input-file옵션을 설정하여cargo-leptos가 빌드 시 Tailwind CLI를 실행하도록 지시한다.- 마지막으로, 애플리케이션의 루트 컴포넌트에서
<Stylesheet />컴포넌트를 사용하여cargo-leptos가 생성한 최종 CSS 파일(/pkg/output-name.css)을 페이지에 주입한다.62
- 동적 클래스 적용:
view!매크로의class:구문을 사용하면 시그널의 값에 따라 Tailwind 클래스를 조건부로 적용할 수 있다. 예를 들어,class:bg-red-500=is_error는is_error시그널이true일 때만bg-red-500클래스를 적용한다.28
6. 고급 주제 및 배포 전략
이 장에서는 프로덕션 수준의 애플리케이션을 개발하고 운영하는 데 필수적인 인증, 오류 처리, 최적화 및 다양한 배포 전략과 같은 고급 주제들을 심도 있게 다룬다.
6.1 인증 및 세션 관리
Leptos 애플리케이션에서 인증을 구현하는 것은 서버 함수와 컨텍스트 API를 중심으로 이루어진다.
- 구현 패턴: 일반적인 흐름은 다음과 같다.
- 로그인: 사용자가 아이디와 비밀번호를 제출하면,
<ActionForm>이 이를 받아 로그인 처리를 담당하는 서버 함수를 호출한다. - 세션 생성: 서버 함수는 데이터베이스에서 사용자 정보를 확인하고, 인증에 성공하면 세션 ID를 생성한다. 이 세션 ID는 데이터베이스의 세션 테이블에 사용자 정보와 함께 저장되고, 클라이언트에게는 암호화된 보안 쿠키(HttpOnly, Secure) 형태로 전송된다.
- 인증 상태 전파: 이후 모든 요청에 대해, 서버는 요청에 포함된 세션 쿠키를 확인한다. 유효한 세션이 존재하면, 해당 사용자 정보를 조회하여 Leptos의
provide_contextAPI를 통해Option<User>와 같은 형태로 렌더링 컨텍스트에 주입한다. - 로그아웃: 로그아웃을 위한 서버 함수는 데이터베이스에서 해당 세션 정보를 삭제하고 클라이언트의 세션 쿠키를 만료시킨다.14
- 보호된 라우트(Protected Routes): 특정 경로나 컴포넌트에 인증된 사용자만 접근할 수 있도록 제한하는 기능은 컨텍스트를 통해 구현할 수 있다. 상위 라우트나 레이아웃 컴포넌트에서
use_context::<Option<User>>()를 호출하여 현재 사용자의 인증 상태를 확인한다. 만약 사용자가 인증되지 않았다면(None),leptos_router::use_navigate훅을 사용하여 로그인 페이지로 리디렉션하거나,<Show>컴포넌트를 사용하여 로그인 컴포넌트를 조건부로 렌더링한다.67 - 외부 라이브러리: 직접 세션 관리를 구현하는 대신,
leptos-keycloak-auth와 같이 Keycloak과 같은 외부 OAuth2/OIDC 제공자와 통합해주는 라이브러리를 사용하면 보다 표준적이고 안전한 인증 시스템을 구축할 수 있다.67 JWT(JSON Web Token) 기반 인증을 구현할 경우,jsonwebtoken크레이트를 서버 함수 내에서 사용하여 토큰을 검증하고 클레임을 추출할 수 있다.69
6.2 선언적 오류 처리: <ErrorBoundary>
Leptos는 React의 Error Boundary와 유사한 선언적 오류 처리 메커니즘을 제공하여, 렌더링 과정에서 발생하는 오류가 애플리케이션 전체를 중단시키는 것을 방지한다.71
- 작동 원리:
view!매크로 내에서Result<T, E>타입의 값을 렌더링할 때, 만약 그 값이Err(E)상태라면 Leptos는 렌더링을 중단하고 컴포넌트 트리 상위로 전파하며<ErrorBoundary>컴포넌트를 찾는다. 가장 가까운<ErrorBoundary>는 이 오류를 포착하여 자식 컴포넌트 대신fallbackprop으로 지정된 UI를 렌더링한다. 이 메커니즘이 작동하기 위해서는 오류 타입E가std::error::Error트레이트를 구현해야 한다.71 - 구현 예제:
<ErrorBoundary>의fallbackprop은 현재 발생한 오류들의 맵을 담고 있는 시그널(errors)을 인자로 받는 클로저를 받는다. 개발자는 이errors시그널을 사용하여 사용자에게 “숫자를 입력해주세요“와 같은 일반적인 메시지뿐만 아니라,.to_string()을 통해 “cannot parse integer from empty string“과 같은 구체적인 오류 내용을 목록 형태로 보여줄 수 있다. 오류 상태가 해결되면(예: 사용자가 입력을 수정하여Result가Ok상태가 되면),<ErrorBoundary>는 자동으로fallbackUI를 숨기고 다시 정상적인 자식 컨텐츠를 렌더링한다.71
6.3 프로덕션 빌드 및 배포
Leptos 애플리케이션을 프로덕션 환경에 배포할 때는 성능과 안정성을 위해 몇 가지 중요한 사항을 고려해야 한다.
- 릴리스 빌드: Rust 애플리케이션은 항상
--release플래그를 사용하여 컴파일해야 한다. 릴리스 모드는 디버그 모드에 비해 LLVM 최적화를 최대한 활용하여 실행 파일의 크기를 줄이고 성능을 크게 향상시킨다. 배포 전,cargo leptos build --release또는trunk build --release를 사용하여 로컬 환경에서 릴리스 모드로 애플리케이션을 테스트하여 디버그 모드에서는 나타나지 않던 잠재적인 문제를 미리 확인하는 것이 중요하다.75 - 환경 변수 관리: 프로덕션 환경에서는 데이터베이스 URL, 외부 API 키 등 환경에 따라 달라지는 설정 값들을 환경 변수로 관리해야 한다.
- 서버 측(SSR): 서버 바이너리는 실행 시점에
std::env::var를 통해 환경 변수를 읽을 수 있다.LEPTOS_ENV=PROD와 같은 환경 변수를 설정하면,cargo-leptos의watch모드를 위한 웹소켓 코드가 빌드에서 제외되는 등 프로덕션에 최적화된 동작을 하도록 할 수 있다.76 - 클라이언트 측(CSR/Hydration): 브라우저에서 실행되는 WASM 코드는 서버의 런타임 환경 변수에 직접 접근할 수 없다. 따라서 클라이언트 측에서 필요한 환경 변수는 두 가지 방법으로 전달해야 한다. (1)
env!()매크로를 사용하여 컴파일 시점에 값을 바이너리에 직접 포함시키는 방법. 이 방법은 환경별로 바이너리를 다시 빌드해야 하며, 민감한 정보를 포함해서는 안 된다. (2) 서버가 초기 HTML을 렌더링할 때, 환경 변수 값을<script>태그 내의 전역 JavaScript 변수로 주입하는 방법. 이 방식은 단일 빌드 아티팩트를 여러 환경에 배포할 수 있게 해주는 유연한 방법이다.78 - Docker 컨테이너화: SSR 애플리케이션을 배포하는 가장 안정적이고 이식성 높은 방법은 Docker를 사용하는 것이다. 멀티-스테이지 빌드(multi-stage build)를 활용한
Dockerfile을 작성하면 최종 이미지의 크기를 크게 줄일 수 있다. 첫 번째 ‘빌드’ 스테이지에서는 Rust 컴파일러와cargo-leptos등 모든 빌드 도구를 포함한 환경에서 애플리케이션을--release모드로 컴파일한다. 두 번째 ‘런타임’ 스테이지에서는 가벼운 베이스 이미지(예:debian:bookworm-slim) 위에, 첫 번째 스테이지에서 생성된 서버 바이너리와target/site디렉토리의 정적 에셋만을 복사한다. 이렇게 하면 최종 배포 이미지에는 불필요한 빌드 도구나 소스 코드가 포함되지 않아 보안성이 향상되고 크기가 최적화된다.81 - 클라우드 배포:
- CSR 앱:
trunk build --release로 생성된 정적 파일들(dist디렉토리)은 Vercel, Netlify, GitHub Pages와 같은 정적 호스팅 플랫폼에 매우 쉽게 배포할 수 있다.84 - SSR 앱: Docker 컨테이너화된 SSR 앱은 Fly.io, Railway, Google Cloud Platform(App Engine, Cloud Run), AWS(ECS, App Runner) 등 대부분의 클라우드 플랫폼에 배포할 수 있다. 각 플랫폼의 CLI나 CI/CD 파이프라인을 통해 Docker 이미지 배포를 자동화할 수 있다.81
- 서버리스: Shuttle, AWS Lambda, Cloudflare Workers와 같은 서버리스 플랫폼에도 배포가 가능하다. 이는 특정 플랫폼에 맞는 어댑터나 설정이 필요할 수 있으며, ’콜드 스타트’와 같은 서버리스 환경의 특성을 고려해야 한다.81
Leptos의 배포 전략은 선택한 렌더링 모드에 따라 명확하게 구분된다. CSR은 정적 호스팅의 단순함을 따르는 반면, SSR은 Rust 서버 바이너리와 WASM/JS 에셋을 함께 관리하고 배포해야 하는 복잡성을 내포한다. 이 복잡성을 해결하는 가장 효과적이고 표준적인 솔루션이 바로 Docker이다. 멀티-스테이지 Dockerfile은 Rust의 무거운 컴파일 환경과 실제 서비스에 필요한 가벼운 런타임 환경을 완벽하게 분리하여, ’빌드’와 ’실행’이라는 두 가지 다른 관심사를 격리한다. 이 방식은 최종 배포 이미지의 크기를 최소화하고 보안을 강화하며, 개발 환경부터 프로덕션 환경까지 일관된 실행 환경을 보장한다. 즉, Docker는 Leptos의 동형(isomorphic) 철학을 개발 단계를 넘어 프로덕션 배포 단계까지 확장하여 완성시키는 핵심적인 도구로서 기능한다.
7. 결론: Leptos 생태계의 현재와 미래
7.1 Leptos 채택의 기술적 장단점 종합
Leptos는 Rust를 웹 개발의 풀스택 영역으로 확장하는 강력하고 현대적인 프레임워크로서, 뚜렷한 기술적 장점과 함께 고려해야 할 현실적인 단점을 가지고 있다.
장점:
- 압도적인 성능: 가상 DOM을 배제하고 미세-입자 반응성 모델을 채택하여 UI 업데이트 시 최소한의 연산만을 수행한다. 이는 특히 동적인 데이터가 많은 애플리케이션에서 매우 빠른 사용자 경험을 제공한다.8
- 안정성과 신뢰성: Rust의 강력한 타입 시스템과 컴파일 타임 메모리 안전성 보장은 런타임 오류의 가능성을 크게 줄여, 견고하고 안정적인 애플리케이션을 구축하는 데 기여한다.8
- 통합된 개발 경험: 서버 함수를 통해 프론트엔드와 백엔드 로직을 동일한 언어, 동일한 타입 시스템, 심지어 동일한 파일 내에서 작성할 수 있다. 이는 컨텍스트 전환 비용을 줄이고 개발 생산성을 향상시킨다.1
- 점진적 향상: 웹 표준을 존중하는 설계 덕분에 JavaScript/WASM 없이도 기본적인 기능이 동작하며, 이는 접근성과 초기 로딩 성능에 긍정적인 영향을 미친다.13
단점:
- 생태계 및 라이브러리: React나 Vue와 같은 주류 JavaScript 프레임워크에 비해 생태계의 크기가 작고, 즉시 사용할 수 있는 UI 컴포넌트 라이브러리나 서드파티 유틸리티가 상대적으로 부족하다.13
- 학습 곡선: Rust 언어 자체의 학습 곡선이 가파르며, Leptos의 반응성 시스템(시그널, 이펙트)과 풀스택 아키텍처(피처 플래그, 조건부 컴파일)에 대한 이해가 추가로 요구된다.8
- 개발 반복 속도: Rust의 컴파일 시간은 인터프리터 언어에 비해 길다.
cargo-leptos watch와 같은 도구가 증분 컴파일과 핫 리로딩을 지원하지만, 프로젝트 규모가 커질수록 코드 변경 후 결과를 확인하기까지의 시간이 길어질 수 있다.38
7.2 다른 Rust 웹 프레임워크와의 관계 (Yew, Dioxus, Sycamore)
Leptos는 Rust 웹 프레임워크 생태계 내에서 독자적인 위치를 차지하고 있다.
- Yew와 Dioxus: 이 두 프레임워크는 React의 영향을 받아 가상 DOM과 컴포넌트 기반 아키텍처를 채택했다. React 개발 경험이 있는 개발자에게는 상대적으로 친숙할 수 있다. 반면, Leptos는 아키텍처적으로 SolidJS에 더 가까우며, 성능을 최우선으로 하는 미세-입자 반응성 모델을 채택했다는 점에서 근본적인 차이가 있다.5
- Sycamore: Sycamore 역시 Leptos와 마찬가지로 미세-입자 반응성을 기반으로 하는 프레임워크이다. 두 프레임워크는 유사한 철학을 공유하지만, 템플릿 DSL(Sycamore는 함수형, Leptos는 JSX-like)과 서버 통합 방식 등에서 차이를 보인다. 현재 커뮤니티의 활성도나 기능 완성도 측면에서는 Leptos가 다소 앞서 있는 것으로 평가된다.7
결론적으로, Leptos는 Rust 웹 생태계 내에서 가장 현대적인 프론트엔드 패러다임을 채택하고, 이를 풀스택 개발 모델과 가장 긴밀하게 통합한 프레임워크 중 하나로 자리매김하고 있다.
7.3 향후 발전 방향 및 전망
Leptos는 활발한 커뮤니티를 중심으로 빠르게 발전하고 있다. 현재 실험적으로 제공되는 Islands Architecture가 안정화되면, 대규모 애플리케이션의 WASM 페이로드 문제를 해결하여 성능을 한 단계 더 끌어올릴 것으로 기대된다. 또한, 제네릭 컴포넌트 지원, 서버 함수 기능 확장, 그리고 개발자 경험(DX)을 개선하기 위한 도구 체인 강화 등이 지속적으로 논의되고 있다.
Rust와 WebAssembly 기술이 점차 성숙해지면서, 웹 개발에서 성능과 안정성에 대한 요구가 높아짐에 따라 Leptos와 같은 프레임워크의 중요성은 더욱 커질 것이다. Leptos는 Rust의 시스템 프로그래밍 역량을 웹의 동적인 사용자 인터페이스 영역으로 성공적으로 이식한 선구적인 사례로서, 향후 웹 기술의 다양성과 발전에 중요한 기여를 할 것으로 전망된다.2
8. Works cited
- Leptos: Home, accessed October 27, 2025, https://leptos.dev/
- Leptos Web Framework - Build fast web applications with Rust - Eric David Smith, accessed October 27, 2025, https://ericdavidsmith.com/blog/software/leptos-web-framework
- Introduction - Leptos, accessed October 27, 2025, https://book.leptos.dev/
- leptos_router - crates.io: Rust Package Registry, accessed October 27, 2025, https://crates.io/crates/leptos_router
- Leptos, a cutting-edge full-stack Rust framework - Hacker News, accessed October 27, 2025, https://news.ycombinator.com/item?id=36461660
- Ask HN: Real world Svelte speed difference compared to virtual DOM frameworks?, accessed October 27, 2025, https://news.ycombinator.com/item?id=36755999
- leptos-rs/leptos: Build fast web applications with Rust. - GitHub, accessed October 27, 2025, https://github.com/leptos-rs/leptos
- Migrating a JavaScript frontend to Leptos, a Rust framework …, accessed October 27, 2025, https://blog.logrocket.com/migrating-javascript-frontend-leptos-rust-framework/
- Using Rust and Leptos to build beautiful, declarative UIs - LogRocket Blog, accessed October 27, 2025, https://blog.logrocket.com/using-rust-leptos-build-beautiful-declarative-uis/
- Building High-Performance Web Frontends with Rust, Yew, and Leptos | Leapcell, accessed October 27, 2025, https://leapcell.io/blog/building-high-performance-web-frontends-with-rust-yew-and-leptos
- GitHub - gbj/leptos: A full-stack, isomorphic Rust web framework leveraging fine-grained reactivity to build declarative user interfaces. - Reddit, accessed October 27, 2025, https://www.reddit.com/r/rust/comments/y5scij/github_gbjleptos_a_fullstack_isomorphic_rust_web/
- What advantages have WebAssembly over the ‘traditional’ front-end (in React, Vue, Elm, Svelte,…)? : r/rust - Reddit, accessed October 27, 2025, https://www.reddit.com/r/rust/comments/16m0y7o/what_advantages_have_webassembly_over_the/
- Is leptos the right choice for the UI rewrite? · Issue #15 · LemmyNet …, accessed October 27, 2025, https://github.com/LemmyNet/lemmy-ui-leptos/issues/15
- Server Functions - Leptos Book, accessed October 27, 2025, https://book.leptos.dev/server/25_server_functions.html
- leptos - Rust - Docs.rs, accessed October 27, 2025, https://docs.rs/leptos/latest/leptos/
- Getting Started - Leptos Book, accessed October 27, 2025, https://book.leptos.dev/getting_started/index.html
- Generate Keypair using ECDH with Leptos - Keypair Generation, accessed October 27, 2025, https://mojoauth.com/keypair-generation/generate-keypair-using-ecdh-with-leptos
- leptos_reactive — server-side Rust // Lib.rs, accessed October 27, 2025, https://lib.rs/crates/leptos_reactive
- Appendix: How Does the Reactive System Work?, accessed October 27, 2025, https://leptos.shantou.university/en/appendix_reactive_graph.html
- leptos_reactive - Rust - Docs.rs, accessed October 27, 2025, https://docs.rs/leptos_reactive
- Responding to Changes with Effects - Leptos Book, accessed October 27, 2025, https://book.leptos.dev/reactivity/14_create_effect.html
- component in leptos - Rust - Docs.rs, accessed October 27, 2025, https://docs.rs/leptos/latest/leptos/attr.component.html
- A Basic Component - Leptos Book, accessed October 27, 2025, https://book.leptos.dev/view/01_basic_component.html
- Components and Props - Leptos Book, accessed October 27, 2025, https://book.leptos.dev/view/03_components.html
- Passing Children to Components - Leptos Book, accessed October 27, 2025, https://book.leptos.dev/view/09_component_children.html
- leptos::children - Rust - Docs.rs, accessed October 27, 2025, https://docs.rs/leptos/latest/leptos/children/index.html
- Leptos vs Dioxus vs Sycamore (vs Svelte?): Part 1 — Syntax comparison - Vedant Pandey, accessed October 27, 2025, https://blog.vedant.dev/leptos-vs-dioxus-vs-sycamore-vs-svelte-part-1-syntax-comparison-c58ed631896c
- Dynamic Classes, Styles and Attributes - Leptos Book, accessed October 27, 2025, https://book.leptos.dev/view/02_dynamic_attributes.html
- leptos_server - crates.io: Rust Package Registry, accessed October 27, 2025, https://crates.io/crates/leptos_server
- leptos::server_fn - Rust - Docs.rs, accessed October 27, 2025, https://docs.rs/leptos/latest/leptos/server_fn/index.html
- Full Stack Rust with Leptos - benwis, accessed October 27, 2025, https://benw.is/posts/full-stack-rust-with-leptos
- server in leptos - Rust - Docs.rs, accessed October 27, 2025, https://docs.rs/leptos/latest/leptos/attr.server.html
- Implement a Simple WASM Calculator in Rust Using Leptos, and With DumbCalculator, accessed October 27, 2025, https://www.instructables.com/Implement-a-Simple-WASM-Calculator-in-Rust-Using-L/
- Building WASM web UI with Rust and Leptos, accessed October 27, 2025, https://www.rustadventure.dev/building-wasm-web-ui-with-rust-and-leptos
- leptos-rs/cargo-leptos: Build tool for Leptos (Rust) - GitHub, accessed October 27, 2025, https://github.com/leptos-rs/cargo-leptos
- cargo-leptos - Leptos Book, accessed October 27, 2025, https://book.leptos.dev/ssr/21_cargo_leptos.html
- Extractors - Leptos Book, accessed October 27, 2025, https://book.leptos.dev/server/26_extractors.html
- Leptos VS js frameworks : r/rust - Reddit, accessed October 27, 2025, https://www.reddit.com/r/rust/comments/1k5vxdr/leptos_vs_js_frameworks/
- Leptos DX - Leptos Book, accessed October 27, 2025, https://book.leptos.dev/getting_started/leptos_dx.html
- Leptos Rust Suite VS Code Extension - Visual Studio Marketplace, accessed October 27, 2025, https://marketplace.visualstudio.com/items?itemName=MorshedulMunna.leptos-rust-suite
- Defining
- Defining
- The Component - Leptos Book, accessed October 27, 2025, https://book.leptos.dev/router/19_a.html
- Loading Data with Resources - Leptos Book, accessed October 27, 2025, https://book.leptos.dev/async/10_resources.html
- create_resource in leptos_reactive - Rust - Docs.rs, accessed October 27, 2025, https://docs.rs/leptos_reactive/latest/leptos_reactive/fn.create_resource.html
- Structuring Components dependent on resources · leptos-rs leptos · Discussion #2342 - GitHub, accessed October 27, 2025, https://github.com/leptos-rs/leptos/discussions/2342
- Suspense - Leptos Book, accessed October 27, 2025, https://book.leptos.dev/async/11_suspense.html
- Transition - Leptos Book, accessed October 27, 2025, https://book.leptos.dev/async/12_transition.html
- Actions - Leptos Book, accessed October 27, 2025, https://book.leptos.dev/async/13_actions.html
- create_action in leptos::reactive::actions - Rust - Docs.rs, accessed October 27, 2025, https://docs.rs/leptos/latest/leptos/reactive/actions/fn.create_action.html
- using
- ActionForm in leptos::form - Rust - Docs.rs, accessed October 27, 2025, https://docs.rs/leptos/latest/leptos/form/fn.ActionForm.html
- Module 6.1: Database Integration with SQLx + Postgres | by Simple …, accessed October 27, 2025, https://medium.com/@ed.wacc1995/module-6-1-database-integration-with-sqlx-postgres-rust-rest-api-96a81dbe28dc
- Pool in sqlx - Rust - Docs.rs, accessed October 27, 2025, https://docs.rs/sqlx/latest/sqlx/struct.Pool.html
- Efficient Database Connection Management with sqlx and bb8/deadpool in Rust | Leapcell, accessed October 27, 2025, https://leapcell.io/blog/efficient-database-connection-management-with-sqlx-and-bb8-deadpool-in-rust
- HTML forms, Databases, Integration tests | Luca Palmieri, accessed October 27, 2025, https://www.lpalmieri.com/posts/2020-08-31-zero-to-production-3-5-html-forms-databases-integration-tests/
- sqlx-cli - crates.io: Rust Package Registry, accessed October 27, 2025, https://crates.io/crates/sqlx-cli
- Rust SQLx CLI: database migration with MySQL and PostgreSQL. - DEV Community, accessed October 27, 2025, https://dev.to/behainguyen/rust-sqlx-cli-database-migration-with-mysql-and-postgresql-42gp
- Build CRUD REST API with Rust and MySQL using Axum & SQLx - Medium, accessed October 27, 2025, https://medium.com/@raditzlawliet/build-crud-rest-api-with-rust-and-mysql-using-axum-sqlx-d7e50b3cd130
- Interlude: Styling - Leptos Book, accessed October 27, 2025, https://book.leptos.dev/interlude_styling.html
- Full stack with Rust: axum + leptos + tailwind.css - 63 orders of magnitude, accessed October 27, 2025, https://8vi.cat/full-stack-with-rust-axum-leptos-tailwind-css/
- Integrating Tailwind and DaisyUI into a Leptos project - Kival Mahadew, accessed October 27, 2025, https://kivalm.com/blog/dev/rustle/tailwind-leptos
- An Example Template for Using Leptos & Tailwind for Full Stack Applications - GitHub, accessed October 27, 2025, https://github.com/KCaverly/leptos-tailwind
- Building a Modern Todo List Application with Rust, Leptos, and …, accessed October 27, 2025, https://autognosi.medium.com/building-a-modern-todo-list-application-with-rust-leptos-and-tailwind-css-4-0-28a859f4a17f
- Indrazar/auth-sessions-example: An Example of an HTTPS … - GitHub, accessed October 27, 2025, https://github.com/Indrazar/auth-sessions-example
- leptos_keycloak_auth - Rust - Docs.rs, accessed October 27, 2025, https://docs.rs/leptos-keycloak-auth
- lpotthast/leptos-keycloak-auth - GitHub, accessed October 27, 2025, https://github.com/lpotthast/leptos-keycloak-auth
- Validate JWT using RS256 in Leptos | SSOJet, accessed October 27, 2025, https://ssojet.com/jwt-validation/validate-jwt-using-rs256-in-leptos/
- Validate JWT using ES512 in Leptos - SSOJet, accessed October 27, 2025, https://ssojet.com/jwt-validation/validate-jwt-using-es512-in-leptos/
- Error Handling - Leptos Book, accessed October 27, 2025, https://book.leptos.dev/view/07_errors.html
- React Error Boundary - Medium, accessed October 27, 2025, https://medium.com/@bloodturtle/react-error-boundary-caaaf770c486
- ErrorBoundary in leptos::error - Rust - Docs.rs, accessed October 27, 2025, https://docs.rs/leptos/latest/leptos/error/fn.ErrorBoundary.html
- Error Handling - leptos-book-unofficial-japanese-translation - GitLab, accessed October 27, 2025, https://nogiro.gitlab.io/leptos-book-unofficial-japanese-translation/view/07_errors.html
- Deployment - Leptos Book, accessed October 27, 2025, https://book.leptos.dev/deployment/index.html
- leptos::config - Rust - Docs.rs, accessed October 27, 2025, https://docs.rs/leptos/latest/leptos/config/index.html
- leptos_config - Rust - Docs.rs, accessed October 27, 2025, https://docs.rs/leptos_config
- Access environment variables in CSR · leptos-rs leptos · Discussion …, accessed October 27, 2025, https://github.com/leptos-rs/leptos/discussions/2530
- Leptos, Sass and Trunk: Setting Up a React Like Project Development Environment in Leptos and Rust WASM | by Saeed Andalib | Medium, accessed October 27, 2025, https://medium.com/@SSeanin/leptos-turf-and-trunk-setting-up-a-react-like-project-development-environment-in-leptos-and-rust-1bd02a83ceb9
- How to pass environment variables to a Rust WASM application like Yew, Dioxus and Leptos as a TypeScript Developer - DEV Community, accessed October 27, 2025, https://dev.to/javiasilis/how-to-pass-environment-variables-to-a-rust-wasm-application-like-yew-dioxus-and-leptos-as-a-typescript-developer-ond
- Deploying SSR Apps - Leptos Book, accessed October 27, 2025, https://book.leptos.dev/deployment/ssr.html
- Building My Portfolio Website with Rust and Leptos: A Journey into WebAssembly | by Vasantha Kumar | Google Cloud - Medium, accessed October 27, 2025, https://medium.com/google-cloud/building-my-portfolio-website-with-rust-and-leptos-a-journey-into-webassembly-12709ee4ab10
- Can’t get leptos container to expose to host : r/rust - Reddit, accessed October 27, 2025, https://www.reddit.com/r/rust/comments/1aqjkaq/cant_get_leptos_container_to_expose_to_host/
- Deploying CSR Apps - Leptos Book, accessed October 27, 2025, https://book.leptos.dev/deployment/csr.html
- create-leptos-csr - crates.io: Rust Package Registry, accessed October 27, 2025, https://crates.io/crates/create-leptos-csr
- Leptos CSR Starter Template deployed to Vercel - GitHub, accessed October 27, 2025, https://github.com/leptos-community/deployment-csr-vercel
- Part 1: Building User Interfaces - Leptos Book, accessed October 27, 2025, https://book.leptos.dev/view/index.html
- Deploy Leptos - Railway, accessed October 27, 2025, https://railway.com/deploy/pduaM5
- leptos-community/deployment-ssr-shuttle - GitHub, accessed October 27, 2025, https://github.com/leptos-community/deployment-ssr-shuttle
- Does anybody actually use Leptos framework in production? : r/rust - Reddit, accessed October 27, 2025, https://www.reddit.com/r/rust/comments/191vxcb/does_anybody_actually_use_leptos_framework_in/