Leptos 是一个全栈框架,这说明它不止可以用 Rust 开发纯前端应用,也可以开发一个 MVC 式的 Web 应用。

为了 SEO

前端框架打包的纯前端应用,集合了 HTML、JS、CSS 这种在浏览器上运行的条件,只会产生一系列静态文件,JS 文件、CSS 文件、图片等。用户访问的时候浏览器直接请求到一个 html 文件,浏览器解析到其中的 <script> 标签,会下载它的 JS 文件,这些文件里包含了前端框架打包进去的 runtime,页面渲染逻辑等,然后在到浏览器上执行和渲染。

这种方式叫做 CSR,(Client Side Render)。

它的好处是明显的,更少的打包文件,更紧凑的格式,纯静态文件可以方便的部署在任何服务器上。

file

只不过这种方式对 SEO 不是很友好。

CSR 这种方式让浏览器每次访问的时候都是请求到一个空荡荡的 html 文件,再由 JS 去执行其他的请求数据和渲染逻辑,搜索引擎对于这个空荡荡的 html 实在是解析不出什么内容出来。也许搜索引擎现在可以去执行更复杂的 JS 逻辑了,但总不如解析 HTML 来的方便。

为了让自己的页面能够在网络上更容易被找到,开发者会尽可能地丰富它的页面信息,除了使用更加语义化的标签(<article>, <header>, <nav> 等)外,还会往 <meta> 标签里添加更多的信息。这些信息想要在被搜索引擎获取的话,用 CSR 不是一个很好的选择。

所以为了应对这种情况,SSR(Server Side Render)是更好的选择。

SSR

其实 SSR 就是在服务器完成首次渲染,这些渲染不是完全的,但会携带一些基本的信息,比如 <meta>,博客的文章等方便搜索引擎解析的信息。其 SSR 的运行原理是运行了一个简易的服务器,从直接给客户端一个 HTML 文件变成了有一个应用来接收请求。

file

主流前端框架实现了 SSR 功能(Angular, Vue, React)。Leptos 也提供了 SSR 的功能,在它的官网上详细介绍了 SSR 的原理,挺有意思的。

Leptos 的 SSR

Leptos 选择了 Actix 和 Axum 作为 SSR 服务器,具体使用哪个取决于开发者。

总的来说,一个请求从到达 SSR 服务器,到浏览器渲染页面,大致可以分为三个步骤:"dehydrated","hydrated","rehydrate"。我没有找到什么好的翻译,就叫这三个步骤为:脱水、浸泡、滋润吧。(大概这个意思)

dehydrated 脱水!

在 SSR 过程中,浏览器会处理必要的数据访问,比如要插入到 <mate> 标签中的信息,文章的信息等要让搜索引擎知晓的东西,这些东西要在返回给浏览器前就完整出现在 html 中,除此之外,像事件监听,runtime 等就不必让服务器处理。这个处理必要信息,不处理其他东西的过程就是脱水(dehyddrated)。此时的 html 是一个干巴巴的页面,只有基本数据,没有事件监听,框架的 runtime 等。

hydrate 浸泡!

脱水状态下的页面有了搜索引擎需要的信息,但是需要的不只是搜索引擎,还有普通用户的浏览器,所以他们还是需要各种事件的。这些事件会在浏览器接收到脱水的 html 后开始加载,所以会以 <script> 标签的方式插入到脱水的 html 中,"hydrate" 浸泡就是用来做这些事的。

rehydrate 湿润!

当浏览器接收到脱水的 html,请求到 <script> 里的 JS,执行 JS 将页面变成一个现代功能齐全的页面的过程,就是 "rehydrate"。

file

Leptos 的实现

上面 SSR 的各个流程需要不同的代码去实现,像如果我用了 Actix-web 作为服务器,那么我只需要在脱水期间作为服务器,浸泡湿润 期间不需要这个 Actix-web。Leptos 里用了 Rust 的 features 在不同的环境运行不同代码。

使用命令:

cargo leptos new --git leptos-rs/start

拉下来 Actix-web 作为 SSR 服务器的代码后,能够看到 src 下有 main.rslib.rs 两个文件:

file

main.rs 是作为服务器运行的代码,你能够看到里面启动了一个 Actix-web 服务器。

lib.rs 里有分别被标记为 feature="hydrate"feature="csr" 的代码块:

file

Cargo.toml 里也能看到大量的依赖被 不同的 features 瓜分:

file

所以当我们需要添加新的 crate 的时候要特别注意这个 crate 是使用在 server 下还是 client 下,还是两者都需要。

组件里的服务器代码

Leptos 里的组件无疑是在 feature="csr" 下的,运行在服务器上的代码,比如访问数据库,是在 feature="ssr" 下的。Leptos 提供了 Server Functions 功能,可以在组件里使用服务器的代码:

file

Server Functions 会生成一个 api,由组件调用 api 去执行。

这里有一点要注意,当我们使用到 Server Functions 时候会引用 ssr 下的代码,必须在 #[server] 标记下 Server Functions 里引入:

file

如果代码太多想要抽出来,这些服务器代码必须在 lib.rs 下用 feature = "ssr" 引入:

file

Conclusion

Leptos 挺有意思的,但它的 SSR 环境有时候会遇到一些奇怪的问题。 还是 React 好用。