Rust真全栈开发快速入门

文章目录

虚假的全栈开发,前端后端分离然后分别使用不同的编程语言来开发前后端,真实的全栈开发,前后端全用Rust编程语言,无需打开两个项目分别维护,本文使用的技术栈是Leptos, tailwindcss, trunk

Cargo.toml的依赖如下:

[dependencies]
leptos = { version = "0.5.4", features = ["csr"] }

环境准备

增加编译目标

最终的前端代码会以wasm文件存在

rustup target add wasm32-unknown-unknown

首先需要安装构建项目的必要命令行工具

cargo install trunk wasm-bindgen-cli

安装wasm-bindgen-cli其实非必要,因为当trunk找不到这个命令行工具的时候会自动到github下载,但是, 因为众所周知的原因,可能访问失败,所以建议直接手动安装

安装tailwindcss命令行工具

安装tailwindcss命令行工具也是非必要,因为trunk也会尝试自己安装,之所以手动换安装和上面的原因一样。

这有两个办法,一个是通过npm安装,一个是直接使用tailwindcss提供的二进制执行文件。

如果你已经有node环境的话,那就直接使用npm安装吧,不过要保证能够直接在终端执行tailwindcss命令。

npm install -g tailwindcss

手动安装的话可以去这个地址https://github.com/tailwindlabs/tailwindcss/releases下载对应平台最新的二进制文件,然后放到PATH路径中的某个目录, 只有能在终端执行的时候找到tailwindcss命令即可。

快速入门

创建项目

cargo new leptos-demo
# 没错, leptos还支持ssr
cargo add leptos --features=csr

然后进入开发目录创建index.html

cat > index.html <<EOF
<!DOCTYPE html>
<html>
  <head></head>
  <body></body>
</html>
EOF

src/main.rs文件的内容替换如下

use leptos::*;

fn main() {
    mount_to_body(|| view! { <p>"Hello, world!"</p> })
}

现在目录结构如下

leptos-demo
├── src
│   └── main.rs
├── Cargo.toml
├── index.html

然后我们就可以在rust项目的根目录执行以下命令启动项目了。

trunk serve 

trunk提供了一个和当下前端开发差不多的开发体验,它包括打包,热加载等功能,所以当我们修改代码的时候,trunk会检测到并重新编译,前端的页面也会自动刷新。

Tailwindcss

上面虽然很快的构建了一个可以运行的页面,但是前端很重要的是用户体验,也就是有一些必要的CSS样式,所以需要一个CSS框架,大家可以根据自己的需要选择,而我选择的是TailwindCSS, 我很喜欢这个框架。

我们可以创建以下文件。

tailwind.config.js

module.exports = {
  content: {
    files: ["./src/**/*.rs", "index.html"],
  },
  darkMode: "media", // 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
};

src/tailwind.css

@tailwind base;
@tailwind components;
@tailwind utilities;

创建完上述两个文件之后,文件结构如下

.
├── Cargo.lock
├── Cargo.toml
├── index.html
├── src
│   ├── main.rs
│   └── tailwind.css
└── tailwind.config.js

第一个文件是为了使用编辑器的时候获得tailwindcss的提示, VSCode对应的插件名是: Tailwind CSS IntelliSense

在VSCode似乎光是tailwind.config.js文件不生效,所以我还设置了以下配置。

{
    "emmet.includeLanguages": {
        "rust": "html",
        "*.rs": "html"
    },
    "tailwindCSS.includeLanguages": {
        "rust": "html",
        "*.rs": "html"
    }
}

最后将index.html修改成如下内容。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
	
    <link data-trunk rel="tailwind-css" href="src/tailwind.css"/>
</head>
<body>
</body>
</html>

上面的重点主要是<link data-trunk rel="tailwind-css" href="src/tailwind.css"/>这一行,通过这一行的设置, trunk会在编译的时候也调用tailwindcss命令行工具生成对应的CSS, 所以可以实时的预览tailwindcss的显示效果。

至此,前端开发的主要问题解决了,可以愉快的开发,不过还有一些问题没有提,这主要是因为这是一篇单独的文章,以后有机会再写相关的系列文章吧。

一个更具体的例子

如果你对上面的例子不够满意,那么可以将main.rs替换成以下内容,下面的例子是创建了一个可以交互的页面,显示效果如下:

leptos-counter-preview

use leptos::*;

#[component]
pub fn SimpleCounter( initial_value: i32) -> impl IntoView {
    // 创建一个信号, 一个类似于其他前端框架的state
    let (value, set_value) = create_signal( initial_value);
    
    // 为三个按钮分别创建对应的事件函数
    // value和set_value都实现了Copy trait所以不需要额外的调用clone方法
    let clear = move |_| set_value.set(0);
    let decrement = move |_| set_value.update(|value| *value -= 1);
    let increment = move |_| set_value.update(|value| *value += 1);

    view! {
        <div class="container flex items-center mt-20 flex-col">
            <div class="">
                <span class="text-gray-500">"Value: " {move || value.get().to_string()} "!"</span>
            </div>

            <div class="flex gap-2 items-center mt-2">
                <button on:click=clear
                    class="hover:bg-red-400 rounded-md bg-blue-500 text-white text-sm font-medium pl-2 pr-3 py-2 shadow-sm">
                    "Clear"
                </button>
                <button on:click=decrement 
                    class="hover:bg-yellow-400 rounded-md bg-yellow-500 text-white text-sm font-medium pl-2 pr-3 py-2 shadow-sm">
                    "-1"
                </button>
                <button on:click=increment
                    class="hover:bg-green-400 rounded-md bg-green-500 text-white text-sm font-medium pl-2 pr-3 py-2 shadow-sm">
                    "+1"
                </button>
                
            </div>
        </div>
        
    }
}


pub fn main() {
    mount_to_body(|| view! { <SimpleCounter initial_value=3 /> })
}

SSR

就像本文标题所说的那样,我要的是全栈开发,而不是用某种技术来替代前端开发,leptos的设计之初就考虑到了SSR, 它可以跟其他web框架集成,然后前后端都是Rust编程语言开发,本文暂时不具体说明了。

Leptos的其他特性

Leptos非常接近其他的前端框架,几乎该有的都有了,比如路由,控制流,动态属性,组件传参和上下文等,有兴趣的可以查阅官方文档: https://book.leptos.dev/getting_started/index.html

不足

如果你真的准备跟我一样拥抱本文所说的全栈开发,在此之前, 请容许我先说说这个技术栈的一些不足。

  • 社区资源不够强大

    因为wasmleptos都比较新,所以相较于react, vue之类的前端框架社区, 肯定是不够后者强大的,所以开发可能会遇到很多新的问题,然后不知道怎么解决。

  • UI框架不多

    还是一样的问题,因为积累相较于JavaScript的前端框架还是太少,所以可能需要自己写很多东西,而没有现成的UI框架和组件, 不过也不是完全没有, 可以参考这个地址里的资源: https://github.com/leptos-rs/awesome-leptos

  • 入门门槛高

    Rust的学习是一道坎,而新的概念也是一道坎。

  • 稳定性

    由于leptos还没到1.0版本,所以在此之前可能会有破坏性升级,那么就可能需要在开发过程中维护这些差异,而且在学习过程中会发现很多教程里的内容过时了。

总结

这篇文章算是之前diss前端开发复杂性的文章的后续,我感觉终于找到了适合自己的全栈开发实践,以后还是有相关内容的文章,可能是leptos的系列文章,就像axum系列文章一样。

参考链接