Rust全栈Web开发工具cargo-leptos的使用,快速构建高性能Leptos框架应用

crates.io Discord

Leptos的构建工具:

Leptos Logo

特性

  • 在监视模式下并行构建服务器和客户端,以获得快速的开发者反馈
  • CSS热重载(无需页面重载,仅更新CSS)
  • 构建服务器和客户端以进行水合(不支持客户端渲染模式)
  • 支持工作区和单包设置
  • 使用dart-sass进行SCSS编译
  • 使用Lightning CSS进行CSS转换和压缩
  • 使用Cargo构建服务器和客户端(wasm)二进制文件
  • 使用wasm-bindgen生成JS-Wasm绑定
    • 包括对JS代码片段的支持,以便从WASM调用某些JS代码
  • 使用Binaryen中的wasm-opt优化wasm
  • watch命令用于自动重建和浏览器实时重载
  • test命令用于运行组成Leptos项目的lib和bin包的测试
  • build构建服务器和客户端
  • end-to-end命令用于构建、运行服务器并调用bash shell钩子。钩子通常会启动Playwright或类似工具
  • new命令用于基于模板创建新项目,使用cargo-generate。当前模板包括
    • 一个Actix启动器
    • 一个Axum启动器
    • 一个Axum启动器,将客户端和服务器代码保存在工作区中的单独crate中
  • 'no_downloads’特性允许用户管理可选依赖项

开始使用

安装:

cargo install --locked cargo-leptos

如果您出于任何原因需要最新的超级新鲜版本:

cargo install --git https://github.com/leptos-rs/cargo-leptos --locked cargo-leptos

帮助:

cargo leptos --help

要设置您的项目,请查看示例

依赖项

sass的依赖项在首次使用时如果尚未安装且未被which找到,则会自动安装在缓存目录中。 不同版本的依赖项可能会在此目录中累积,因此请随时删除它。

操作系统 示例
Linux /home/alice/.cache/cargo-leptos
macOS /Users/Alice/Library/Caches/cargo-leptos
Windows C:\Users\Alice\AppData\Local\cargo-leptos

如果您希望强制安装依赖项,或者正在使用Nix或NixOs,可以启用no_downloads特性来安装,以防止cargo-leptos尝试下载和安装它们。

cargo install --features no_downloads --locked cargo-leptos

单包设置

单包设置是指前端和服务器的代码都在同一个包中定义。

配置参数在包的Cargo.toml部分的[package.metadata.leptos]中定义。有关可以使用的参数的完整列表,请参阅参数参考。所有路径都相对于包根目录(即相对于Cargo.toml文件)

工作区设置

使用工作区设置时,支持单包和多包项目。后者是指前端和服务器位于不同的包中。

所有在其Cargo.toml中定义了[package.metadata.leptos]部分的工作区成员都会自动包含为Leptos单包项目。多包项目在工作区级别的Cargo.toml[[workspace.metadata.leptos]]部分中定义,该部分接受三个强制参数:

[[workspace.metadata.leptos]]
# 项目名称
name = "leptos-project"
bin-package = "server"
lib-package = "front"

# 更多配置参数...

注意双方括号:可以定义多个项目,并且一个包可以在多个项目中使用。

构建特性

使用cargo-leptos构建时,前端(库包)使用目标wasm-unknown-unknown和特性--no-default-features --features=hydrate编译为wasm。 服务器二进制文件使用特性--no-default-features --features=ssr编译。

参数参考

这些参数在工作区部分[[workspace.metadata.leptos]]或包(用于单包设置)部分[package.metadata.leptos]中使用。

请注意,Cargo Manifest使用单词target有两种不同的含义。 作为包的配置[[bin]]目标和作为编译输出的目标三元组。 在这里,后者被称为target-triple。

编译参数

# 设置使用的二进制目标的名称
#
# 可选,仅在bin-package定义了多个目标时才需要。也可以使用LEPTOS_BIN_TARGET=name环境变量设置
bin-target = "my-bin-name"

# 对输出的css、js和wasm文件启用额外的文件哈希
#
# 可选:默认为false。也可以使用LEPTOS_HASH_FILES=false环境变量设置(必须在运行时也设置)
hash-files = false

# 设置cargo-leptos用于跟踪最新哈希的文件名
#
# 可选:默认为"hash.txt"。也可以使用LEPTOS_HASH_FILE_NAME="hash.txt"环境变量设置
hash-file-name = "hash.txt"

# 编译所有目标时使用的特性
#
# 可选。可以使用命令行参数--features扩展
features = []

# 编译bin目标时使用的特性
#
# 可选。可以使用命令行参数--bin-features覆盖
bin-features = ["ssr"]

# 编译bin目标时是否使用--no-default-features标志
#
# 可选。默认为false
bin-default-features = false

# 为发布编译时bin目标使用的配置文件
#
# 可选。默认为"release"
bin-profile-release = "my-release-profile"

# 为调试编译时bin目标使用的配置文件
#
# 可选。默认为"debug"
bin-profile-dev = "my-debug-profile"

# 编译bin目标时使用的目标三元组
#
# 可选。环境变量:LEPTOS_BIN_TARGET_TRIPLE
bin-target-triple = "x86_64-unknown-linux-gnu"

# 编译lib目标时使用的特性
#
# 可选。可以使用命令行参数--lib-features覆盖
lib-features = ["hydrate"]

# 编译lib目标时是否使用--no-default-features标志
#
# 可选。默认为false
lib-default-features = false

# 为发布编译时lib目标使用的配置文件
#
# 可选。默认为"release"
lib-profile-release = "my-release-profile"

# 为调试编译时lib目标使用的配置文件
#
# 可选。默认为"debug"
lib-profile-dev = "my-debug-profile"

# 修复阻止增量编译的cargo错误(参见#203)
#
# 可选。在0.2.3之前默认为false,自0.2.3和#216起无条件启用(此设置已弃用)
separate-front-target-dir = true

# 将附加参数传递给编译到WASM的cargo进程
#
# 可选。无默认值
lib-cargo-args = ["--timings"]

# 将附加参数传递给构建服务器的cargo进程
#
# 可选。无默认值
bin-cargo-args = ["--timings"]

# 构建服务器时运行的命令,而不是"cargo"
#
# 可选。无默认值。环境变量:LEPTOS_BIN_CARGO_COMMAND
bin-cargo-command = "cross"

# 是否为所有cargo-leptos构建启用擦除组件模式。这优化了编译速度,
# 但代价是每个组件的运行时/二进制大小开销
#
# 可选。默认情况下,调试构建使用擦除组件,发布构建不使用
always-erase-components = false

# 是否为所有cargo-leptos构建禁用擦除组件模式
#
# 可选。默认情况下,调试构建使用擦除组件,发布构建不使用
disable-erase-components = false

# 启用wasm-opt特性
#
# 可选。默认情况下,使用"-Oz"、"--enable-bulk-memory"和"--enable-nontrapping-float-to-int"。有关所有特性,请咨询`wasm-opt --help`
# 通过提供特性,您将覆盖默认启用的特性
wasm-opt-features = ["-Oz","--enable-bulk-memory","--enable-nontrapping-float-to-int"]

站点参数

这些参数可以通过设置相应的环境变量来覆盖。它们也可以在.env文件中设置,因为cargo-leptos会读取在包或工作区目录及其任何父目录中找到的第一个文件。

# 设置输出的js、wasm和css文件的名称
#
# 可选,默认为lib包名称,或在工作区中为项目名称。环境变量:LEPTOS_OUTPUT_NAME
output-name = "myproj"

# 站点根文件夹是cargo-leptos生成所有输出的位置
# 注意:在工作区中运行时,它相对于工作区根目录
# 警告:此文件夹的所有内容将在重建时被擦除!
#
# 可选,默认为Cargo目标目录中的"/site"。环境变量:LEPTOS_SITE_ROOT
site-root = "target/site"

# 站点根相对文件夹,所有编译输出(JS、WASM和CSS)写入的位置
#
# 可选,默认为"pkg"。环境变量:LEPTOS_SITE_PKG_DIR
site-pkg-dir = "pkg"

# 源样式文件。如果它以_.sass_或_.scss_结尾,则将被`dart-sass`编译
# 为CSS并由lightning css处理。当设置为发布时,它还将被压缩
#
# 可选。环境变量:LEPTOS_STYLE_FILE
style-file = "style/main.scss"

# tailwind输入文件
#
# 可选,激活tailwind构建
tailwind-input-file = "style/tailwind.css"

# tailwind配置文件
#
# 可选,默认为"tailwind.config.js",如果不存在
# 则会为您生成
tailwind-config-file = "tailwind.config.js"

# 用于优化CSS的browserlist查询
#
# 可选,默认为"defaults"。环境变量:LEPTOS_BROWSERQUERY
browserquery = "defaults"

# 资源源目录。在此找到的所有文件将被复制并同步到site-root
# assets-dir不能有一个与site-pkg-dir同名的子目录/路径
#
# 可选。环境变量:LEPTOS_ASSETS_DIR
assets-dir = "assets"

# JS源目录。`wasm-bindgen`具有从JS文件包含JS代码片段的选项
# 使用`#[wasm_bindgen(module = "/js/foo.js")]`。此目录中任何JS文件的更改
# 将触发重建
#
# 可选。默认为"src"
js-dir = "src"

# 启用Leptos工作所需的JS胶水的最小化
# 使用SWC(Speed Web Compiler)来混淆和压缩JS,将其视为模块
#
# 仅适用于发布构建
#
# 可选:默认为false。也可以使用LEPTOS_JS_MINIFY=false环境变量设置(必须在运行时也设置)
js-minify = false

# 您的应用程序可能依赖的其他文件
# 对这些目录中任何文件的更改将触发重建
#
# 可选
watch-additional-files = ["additional_files", "custom_config.json"]

# 服务器提供内容的IP和端口。在您的服务器设置中使用它
#
# 可选,默认为127.0.0.1:3000。环境变量:LEPTOS_SITE_ADDR
site-addr = "127.0.0.1:3000"

# 重载服务器使用的端口号(仅在监视模式下使用)
#
# 可选,默认为3001。环境变量:LEPTOS_RELOAD_PORT
reload-port = 3001

# 用于运行端到端测试的命令。有关端到端测试的部分
#
# 可选。环境变量:LEPTOS_END2END_CMD
end2end-cmd = "npx playwright test"

# 运行端到端测试的目录
#
# 可选。环境变量:LEPTOS_END2END_DIR
end2end-dir = "integration"

# 生成API路由时用于服务器功能的默认前缀。可以
# 使用`#[server(prefix = "...")]`为单个函数覆盖
#
# 这对于为所有服务器功能覆盖默认前缀(`/api`)很有用,而无需
# 需要通过`#[server(prefix = "...")]`手动指定每个服务器功能
#
# 可选。默认为"/api"。环境变量:SERVER_FN_PREFIX
server-fn-prefix = "/api"

# 是否禁用将服务器功能的哈希附加到其API名称的末尾
#
# 当应用程序的客户端需要稳定的服务器API时,这很有用。例如,在
# Tauri应用程序中发布CSR WASM二进制文件。Tauri应用程序发布依赖于每个平台的
# 分发方法(例如,Apple App Store或Google Play Store),这些方法通常
# 比网站更新的频率慢得多。此外,用户通常
# 没有安装最新的应用程序版本。在这些情况下,CSR WASM
# 应用程序需要能够继续调用后端服务器功能API,因此API
# 路径需要一致且不能附加哈希
#
# 可选:默认为false。环境变量:DISABLE_SERVER_FN_HASH
disable-server-fn-hash = false

# 在API路由中包含服务器功能的模块路径。这是一种替代
# 策略来防止重复的服务器功能API路由(默认策略是添加
# 哈希到路由的末尾)。模块路径的每个元素将由`/`分隔
# 例如,完全限定名称为`parent::child::server_fn`的服务器功能
# 将具有`/api/parent/child/server_fn`的API路由(可能具有
# 不同的前缀和哈希后缀,取决于其他服务器功能配置的值)
#
# 可选,默认为false。环境变量:SERVER_FN_MOD_PATH
server-fn-mod-path = false

环境变量

编译lib(前端)或bin(服务器)以及运行服务器时设置以下环境变量。

从Leptos配置回显:

  • LEPTOS_OUTPUT_NAME
  • LEPTOS_SITE_ROOT
  • LEPTOS_SITE_PKG_DIR
  • LEPTOS_SITE_ADDR
  • LEPTOS_RELOAD_PORT

构建时使用的目录:

  • LEPTOS_LIB_DIR:库包相对于工作目录的路径
  • LEPTOS_BIN_DIR:二进制包相对于工作目录的路径

有关目录的注意事项:

  • cargo-leptos在构建和运行之前将工作目录更改为项目根目录,或者如果在工作区中,则为工作区根目录
  • 在单包配置中,这两个值设置为相同的值
  • 除非您可以保证整个项目结构在运行时也可用,否则避免在运行时使用它们

内部调用cargo-leptos的外部工具的版本是硬编码的。使用这些环境变量来 覆盖cargo-leptos应使用的版本(例如LEPTOS_SASS_VERSION=1.69.5):

  • LEPTOS_TAILWIND_VERSION
  • LEPTOS_SASS_VERSION

端到端测试

cargo-leptos为方便起见提供端到端测试支持。它是一个简单的 围绕在特定目录end2end-dir中执行的shell命令end2end-cmd的包装器。

end2end-cmd可以是任何shell命令。对于运行Playwright,它 将是npx playwright test

它的作用等同于手动运行:

  • 在一个终端中,运行cargo leptos watch
  • 在另一个终端中,切换到end2end-dir并运行end2end-cmd

测试设置时,请先尝试上述方法。如果那有效但cargo leptos end-to-end 无效,请创建GitHub工单

完整示例代码

以下是一个基于cargo-leptos的简单Leptos应用示例:

// Cargo.toml
[package]
name = "leptos-app"
version = "0.1.0"
edition = "2021"

[package.metadata.leptos]
output-name = "leptos-app"
site-root = "target/site"
site-pkg-dir = "pkg"
site-addr = "127.0.0.1:3000"

[dependencies]
leptos = { version = "0.5", features = ["serde"] }
leptos_meta = "0.5"
leptos_router = "0.5"
serde = { version = "1.0", features = ["derive"] }

[lib]
crate-type = ["cdylib", "rlib"]

[[bin]]
name = "leptos-app"
path = "src/main.rs"
// src/lib.rs
use leptos::*;
use leptos_meta::*;
use leptos_router::*;

#[component]
pub fn App() -> impl IntoView {
    provide_meta_context();
    
    view! {
        <Stylesheet id="leptos" href="/pkg/leptos-app.css"/>
        <Title text="Leptos App"/>
        <Router>
            <main>
                <Routes>
                    <Route path="" view=HomePage/>
                </Routes>
            </main>
        </Router>
    }
}

#[component]
fn HomePage() -> impl IntoView {
    let (count, set_count) = create_signal(0);
    
    view! {
        <h1>"Welcome to Leptos!"</h1>
        <button on:click=move |_| set_count.update(|n| *n += 1)>
            "Click me: " {count}
        </button>
    }
}
// src/main.rs
use leptos::*;
use leptos_app::App;

#[cfg(feature = "ssr")]
#[tokio::main]
async fn main() {
    use axum::Router;
    use leptos_axum::{generate_route_list, LeptosRoutes};
    use leptos_app::app::*;
    
    let conf = get_configuration(None).await.unwrap();
    let leptos_options = conf.leptos_options;
    let addr = leptos_options.site_addr;
    let routes = generate_route_list(App);

    let app = Router::new()
        .leptos_routes(&leptos_options, routes, App)

1 回复

cargo-leptos:Rust全栈Web开发工具

工具介绍

cargo-leptos是一个专为Leptos框架设计的Cargo子命令工具,用于简化和加速全栈Web应用的开发流程。它提供了项目脚手架、开发服务器、构建优化和部署支持等功能,让开发者能够快速构建高性能的Leptos应用。

主要特性

  • 一体化开发环境设置
  • 热重载开发服务器
  • 自动CSS处理和优化
  • SSR(服务端渲染)和CSR(客户端渲染)配置
  • 简单的部署流程

安装方法

cargo install cargo-leptos

使用方法

1. 创建新项目

cargo leptos new my-leptos-app
cd my-leptos-app

2. 运行开发服务器

cargo leptos watch

这将启动开发服务器,默认在localhost:3000,支持热重载。

3. 构建生产版本

cargo leptos build --release

4. 运行生产服务器

cargo leptos serve --release

配置示例

在Cargo.toml中添加leptos配置:

[package.metadata.leptos]
# 应用名称
name = "My Leptos App"
# 开发服务器地址
site-addr = "127.0.0.1:3000"
# 输出目录
site-root = "target/site"
# 资源目录
site-pkg-dir = "pkg"
# 是否启用热重载
reload-ws-port = 3001

项目结构示例

典型的cargo-leptos项目结构:

my-leptos-app/
├── src/
│   ├── main.rs          # 服务器入口
│   └── app/             # 前端组件
├── style/               # 样式文件
├── assets/              # 静态资源
└── Cargo.toml          # 项目配置

快速开始示例

创建一个简单的计数器应用:

// src/app.rs
use leptos::*;

#[component]
pub fn App() -> impl IntoView {
    let (count, set_count) = create_signal(0);
    
    view! {
        <button
            on:click=move |_| set_count.update(|n| *n += 1)
        >
            "点击次数: " {count}
        </button>
    }
}

完整示例demo

以下是一个完整的Leptos计数器应用示例,包含服务器端和客户端代码:

Cargo.toml配置:

[package]
name = "my-leptos-app"
version = "0.1.0"
edition = "2021"

[dependencies]
leptos = { version = "0.5", features = ["csr"] }
leptos_meta = "0.5"
leptos_router = "0.5"

[package.metadata.leptos]
name = "My Leptos App"
site-addr = "127.0.0.1:3000"
site-root = "target/site"
site-pkg-dir = "pkg"
reload-ws-port = 3001

src/main.rs(服务器入口):

use leptos::*;
use my_leptos_app::App;

fn main() {
    // 初始化Leptos应用
    leptos::mount_to_body(App);
}

src/app.rs(前端组件):

use leptos::*;

// 定义计数器组件
#[component]
pub fn Counter() -> impl IntoView {
    // 创建响应式信号
    let (count, set_count) = create_signal(0);
    
    // 增加计数函数
    let increment = move |_| set_count.update(|n| *n += 1);
    
    // 减少计数函数
    let decrement = move |_| set_count.update(|n| *n -= 1);
    
    // 重置计数函数
    let reset = move |_| set_count.set(0);

    view! {
        <div class="counter-container">
            <h1>"Leptos计数器应用"</h1>
            <div class="counter-display">
                <span class="count-value">{count}</span>
            </div>
            <div class="counter-buttons">
                <button class="btn btn-decrement" on:click=decrement>
                    "-"
                </button>
                <button class="btn btn-reset" on:click=reset>
                    "重置"
                </button>
                <button class="btn btn-increment" on:click=increment>
                    "+"
                </button>
            </div>
        </div>
    }
}

// 主应用组件
#[component]
pub fn App() -> impl IntoView {
    view! {
        <!DOCTYPE html>
        <html lang="zh-CN">
            <head>
                <meta charset="UTF-8"/>
                <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
                <title>"Leptos计数器"</title>
                <style>
                    "
                    body {
                        font-family: Arial, sans-serif;
                        display: flex;
                        justify-content: center;
                        align-items: center;
                        min-height: 100vh;
                        margin: 0;
                        background-color: #f5f5f5;
                    }
                    
                    .counter-container {
                        text-align: center;
                        padding: 2rem;
                        background: white;
                        border-radius: 10px;
                        box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
                    }
                    
                    .counter-display {
                        margin: 2rem 0;
                    }
                    
                    .count-value {
                        font-size: 3rem;
                        font-weight: bold;
                        color: #333;
                    }
                    
                    .counter-buttons {
                        display: flex;
                        gap: 1rem;
                        justify-content: center;
                    }
                    
                    .btn {
                        padding: 0.5rem 1rem;
                        font-size: 1.2rem;
                        border: none;
                        border-radius: 5px;
                        cursor: pointer;
                        transition: background-color 0.3s;
                    }
                    
                    .btn-increment {
                        background-color: #4CAF50;
                        color: white;
                    }
                    
                    .btn-increment:hover {
                        background-color: #45a049;
                    }
                    
                    .btn-decrement {
                        background-color: #f44336;
                        color: white;
                    }
                    
                    .btn-decrement:hover {
                        background-color: #da190b;
                    }
                    
                    .btn-reset {
                        background-color: #008CBA;
                        color: white;
                    }
                    
                    .btn-reset:hover {
                        background-color: #007B9A;
                    }
                    "
                </style>
            </head>
            <body>
                <Counter/>
            </body>
        </html>
    }
}

运行步骤:

  1. 创建新项目:
cargo leptos new my-leptos-app
cd my-leptos-app
  1. 用上面的代码替换对应的文件内容

  2. 启动开发服务器:

cargo leptos watch
  1. 在浏览器中访问 http://localhost:3000 查看计数器应用

这个完整的示例展示了如何使用cargo-leptos创建一个功能完整的Leptos计数器应用,包含响应式状态管理、事件处理和样式设计。

回到顶部