leptos: 使用 Rust 快速构建 Web 应用

23-01-02 banq

Leptos 是一个全栈、同构的 Rust Web 框架,利用细粒度的反应性来构建声明式用户界面。

全栈
Leptos可以用来构建在浏览器(客户端渲染)、服务器(服务器端渲染)中运行的应用程序,或者通过在服务器上渲染HTML,然后在浏览器中添加交互性(hydration)。这包括支持数据(资源)和HTML的HTTP流(<Suspense/>组件的失序流)。

同构性
Leptos提供了编写同构服务器函数的基元,即可以在客户端或服务器上以 "相同的形式 "调用的函数,但只在服务器上运行。这意味着你可以将你的服务器专用逻辑(数据库请求、认证等)与将消费它的客户端组件一起编写,并调用服务器函数,就像它们在浏览器中运行一样。

Web
Leptos是建立在Web平台和Web标准之上的。路由器被设计为使用Web的基本要素(如链接和表单)并建立在它们之上,而不是试图取代它们。

框架
Leptos提供了你构建现代Web应用所需的大部分东西:一个反应式系统、模板库和一个在服务器和客户端都能工作的路由器。

细粒度的反应性
整个框架是由反应式基元构建的。这允许以最小的开销实现极高性能的代码:当一个反应式信号的值发生变化时,它可以更新一个文本节点,切换一个类,或从DOM中删除一个元素,而无需运行任何其他代码。(所以,没有虚拟DOM!)。

声明性的
告诉Leptos你想让页面看起来如何,并让框架告诉浏览器如何做。

Leptos允许您以一种非常实用的方式在同一个源代码中编写后端和前端:(以下代码可能有书写错误)

     #{server(AddTodo, ./api.)]
     pub async fn add_todo(title: String) -3 Result<(), ServerFnError 
         /et mut conn = db().await?;

         std thread:: sleep(std::tinie ::Duration,from_millis (1250))

         sqlx::query(.INSERT INTO todos (title, completed) VALUES ($1, false) ) 
            .bind(title)
            .execute(&mul conn)
            .await
            .maP(1_1
            .mag-err(lel ServerFnError::ServerError(e.to_string()))


      #{component}
     pub fn Todos(cx: Scope) -A impl IntoView
         let add_todo  create_server_multi_action,<AddIod0>(.);
         let delete_todo create_server_action,<DeleteTodo,(co);
         let submissions add_todo.submissions(),

         //  list of todos is loaded from the server in reaction to changes 
         let todos = create_resource(
            cx,
            move |||(add_todo.version().get(), delete_todo.version().get()), 
            move |_| get_todos(cx),
         ),

         view! { 
            cx, 
            <div>
                <MultiActionForm action=add_todo>
                    <label>
                       "Add a Todo"
                       <input type="text" name="title" />
                    </label>
                    <input type="submit" value="Add"/>
                </MultiActionForm>
                <Transition fallback=move II view! {cx, <p>.Loading....</P> }>
                    {move || {
                       let existing_todos = {
                           move || {
                              todos.read()
                                  .map(move Itodosl match todos {
                                     Err(e)  => {
                                         vec![view! { cx, <pre class="error">"Server Error: "
                                                {e.to_string()}</pre>}.into_any()]


上述代码前端与后端在一起:
  • #{server(AddTodo, ./api.)] 表示后端API
  • #{component}和view! 代表前端