Topcoat:Rust 的全栈开发框架
Topcoat: The full full-stack framework for Rust

原始链接: https://github.com/tokio-rs/topcoat

Topcoat 是一个模块化的、“内置电池”式全栈 Rust 框架,专为简洁性和开发者生产力而设计。它通过允许开发者无需独立的 API 层即可构建全栈应用程序,简化了 Web 开发。组件可以在服务器渲染标记语言的同时直接查询数据库。 主要功能包括: * **无缝响应性:** 使用独特的 `$(...)` 语法,在服务器端进行初始渲染时执行 Rust 代码,并自动将其转换为 JavaScript 以实现即时的浏览器交互,无需 WASM 包或复杂的构建步骤。 * **高效更新:** 使用 `#[shard]` 组件,在数据变化时智能地在服务器端重新渲染并替换 HTML 片段。 * **直观的模板:** `view!` 宏支持熟悉的 Rust 控制流,并包含自动格式化程序。 * **自动路由:** 路由可以直接从文件结构中推断出来。 * **内置生态系统:** 包含集成的资产管道(支持 Tailwind CSS 和 Fontsource)、强大的 Cookie/会话管理以及请求范围内的工具。 虽然目前处于实验性的早期阶段,且预计会有重大更改,但 Topcoat 提供了一种强大而统一的方法,能够以极少的样板代码构建现代 Rust Web 应用程序。

Tokio 团队意外地开源了 **Topcoat**,这是一个全新的 Rust “全栈” Web 框架。据首席维护者 Carl Lerche 表示,由于私有持续集成(CI)的限制,该代码库比原计划提前公开,正式的官方博客文章预计将于下周发布。 尽管社区的一些早期反馈因认为该框架缺乏数据库集成而对其“全栈”定位提出质疑,但 Lerche 澄清说,Topcoat 被设计为与即将推出的 Tokio 生态 ORM —— **Toasty** 紧密集成,以简化数据工作流。 目前,团队将早期反馈和使用体验置于功能完整性之上。Lerche 已积极邀请社区分享当前 Rust Web 生态中的痛点,以帮助规划该框架的发展。
相关文章

原文

The full full-stack framework for Rust

Topcoat is a modular, batteries-included Rust framework for building fullstack apps. It prioritizes simplicity and productivity. See the Getting started guide to set up a new project.

Early-stage and experimental. Expect breaking changes.

use topcoat::{
    Result,
    router::{Router, RouterBuilderDiscoverExt, page},
    view::{component, view},
};

#[tokio::main]
async fn main() {
    topcoat::start(Router::builder().discover().build()).await.unwrap();
}

#[page("/")]
async fn home() -> Result {
    view! {
        <!DOCTYPE html>
        <html>
            <body>
                hello(name: "World")
            </body>
        </html>
    }
}

#[component]
async fn hello(name: &str) -> Result {
    view! { <h1>"Hello, " (name) "!"</h1> }
}

What makes Topcoat different

Client reactivity without the boilerplate

Topcoat renders all markup on the server: components can be async and query the database directly, eliminating all the traditional boilerplate needed for a separate API layer. Interactivity does not have to cost a round-trip, though. A $(...) expression is ordinary type-checked Rust that Topcoat evaluates on the server for the initial render and also translates to JavaScript, so it re-runs instantly in the browser. No wasm bundle, no client build step:

view! {
    signal open = false;

    // Runs entirely in the browser; no server round-trip.
    <button @click=$(|_e| open.set(!open.get()))>"What is Topcoat?"</button>
    <p :hidden=$(!open.get())>"A fullstack Rust framework."</p>
}

When an update does need the server, like fresh search results, mark the component as a #[shard]. Topcoat re-renders it on the server whenever one of its $(...) arguments changes and swaps the new HTML in place:

#[component]
async fn search() -> Result {
    view! {
        signal query = String::new();

        <input @input=$(|e: Event| query.set(e.target.value))>

        // Updates as the user types.
        search_results(query: $(query.get()))
    }
}

#[shard]
async fn search_results(cx: &Cx, query: String) -> Result {
    view! {
        <ul>
            // Your own server-side code, like a database query:
            for product in search_products(cx, &query).await? {
                <li>(product.name)</li>
            }
        </ul>
    }
}

Powerful, unsurprising HTML templates

The view! macro stays true to HTML and Rust. Use familiar Rust control flow as part of your templates:

view! {
    <nav>
        for item in nav_items {
            <a
                href=(item.url)
                if item.url == current_path {
                    aria-current="page"
                    class="active"
                }
            >
                (item.label)
            </a>
        }
    </nav>
}

Use the topcoat fmt CLI command to automatically format view! snippets (and other macros) across your codebase.

Topcoat can optionally infer your route tree from your app's module structure (without a build step):

src/
|-- app.rs              -> /            (and the root <html> layout)
`-- app/
    |-- about.rs        -> /about
    |-- _marketing.rs                  (layout, no URL segment)
    |-- _marketing/
    |   `-- pricing.rs  -> /pricing
    |-- posts.rs        -> /posts
    |-- posts/
    |   `-- id.rs       -> /posts/{post_id}
    `-- api/
        `-- health.rs   -> GET /api/health

The bundler scans your compiled binary for asset! calls, copies (or even downloads) every file into a local asset directory, and allows Topcoat to serve them efficiently with aggressive browser caching.

const FERRIS: Asset = asset!("./ferris.png");

view! { <img src=(FERRIS)> }

Topcoat also ships with utilities for web fonts and icons, as well as easy integrations for Fontsource (Google Fonts) and Iconify.

Built-in Tailwind support

Enabled the tailwind feature to integrate Tailwind into your project effortlessly:

view! { <link rel="stylesheet" href=(topcoat::tailwind::stylesheet!())> }

Start here

Rendering

Routing

  • Router: pages, layouts, and API routes; manual and auto-discovered.
  • Module-based routing: derive the route table from your module tree.

Working with requests

  • Request context (Cx): the value pages, layouts, and components read from.
  • App context: share long-lived values across requests, keyed by type.
  • Memoization: #[memoize] for per-request caching and fan-out dedup.
  • Functions, not middlewares: the recommended way to model auth and other request-scoped concerns.
  • Cookies: read and write the request cookie jar, with signed, encrypted, and prefixed cookies.
  • Sessions: bring-your-own-storage session authentication: login/logout lifecycle, sliding expiration, and token rotation.

Asset system

  • Assets: declare assets in Rust, serve them with content-hashed URLs.
  • Fonts: bundle and serve web fonts.
  • Icons: download Iconify icon sets or declare your own.

Client reactivity

  • The runtime: signals, $(...) expressions, @ event handlers, and : bind attributes.
  • Expressions: the dual Rust/JavaScript expression language and its vocabulary.
  • Procedures: async server functions callable from the browser.
  • Shards: components that re-render on the server when their arguments change.

Third-party integrations

  • Tailwind: Tailwind CSS without Node, wired into the asset pipeline.
  • htmx: drive partial HTML swaps from the server with request/response header helpers.
联系我们 contact @ memedata.com