今天是周六,周末的事情感觉比平时都多,所以也没有写代码。所以打算结合这几天开发Yew应用的经历,聊聊Yew的Hydration。
首先Hydration这个单词是什么意思,我查了一下字典,意思是"水合"。而什么又是水合呢?我有查了一下字典,发现这是化学里面的一个词汇,意思是物质溶解在水里时,与水发生的化学作用。 一般指溶质分子(或离子)和水分子发生作用,形成水合分子(或水合离子)的过程。
即便我理解了上面这段话,那这里面的物质怎么和Yew的Hydration相关的元素对应起来呢?虽然现在项目能正常运行了,但是关于Hydration的底层逻辑,我感觉目前还是云里雾里的。
要运行Yew的SSR模式开发的应用,要运行下面两个命令行
rust
trunk build index.html
cargo run --features=ssr --bin=ssr_hydrate -- --dir dist
当第一个命令行运行时,会生成dist文件夹,里面包含的文件如下:
bash
zycao@ZydeiMac dist % ls -lah
total 4320
drwxr-xr-x 6 zycao staff 192B 9 16 22:33 .
drwxr-xr-x 11 zycao staff 352B 9 16 22:31 ..
-rw-r--r-- 1 zycao staff 2.1K 9 16 22:32 index-6acd6682c1b8241.css
-rw-r--r-- 1 zycao staff 602B 9 16 22:33 index.html
-rw-r--r-- 1 zycao staff 31K 9 16 22:33 ssr_hydrate-9655cd31dfbca4c8.js
-rw-r--r-- 1 zycao staff 2.1M 9 16 22:33 ssr_hydrate-9655cd31dfbca4c8_bg.wasm
我这里突发奇想,如果我直接在dist文件夹下启动http-server .从浏览器中打开index.html,会是什么结果?
结果是页面一片空白,控制台里报错如下:
bash
Failed to load resource: the server responded with a status of 404 (Not Found)
这个报错说明index.html文件加载完成后,还是要尝试去服务器端加载资源,具体是什么资源,目前我也不知道。
在运行第二个命令行时,会启动服务器,并且执行bin/ssr_server.rs
里面的代码。在ssr_server.rs
的文件中,我们可以看到,它是读取了index.html
的。代码如下:
rust
let index_html_s = tokio::fs::read_to_string(opts.dir.join("index.html"))
.await
.expect("failed to read index.html");
let (index_html_before, index_html_after) = index_html_s.split_once("<body>").unwrap();
从这里的代码可以推断出,它是要将服务端生成的代码添加到已经生成好了的index.html
中。难道这个过程即是hydration吗?
另外,这个项目中还有一个bin/ssr_hydrate.rs
,这个bin在哪里被调用呢?我怀疑是在trunk build index.html
中调用或者运行的。果然,将bin/ssr_hydrate.rs
删除后报错如下:
bash
zycao@ZydeiMac app % trunk build index.html
2023-09-16T15:17:33.507159Z INFO 📦 starting build
2023-09-16T15:17:33.510702Z INFO spawning asset pipelines
2023-09-16T15:17:33.825368Z INFO building app
2023-09-16T15:17:33.827025Z INFO compiling sass/scss path="index.scss"
2023-09-16T15:17:33.957026Z INFO finished compiling sass/scss path="index.scss"
error: no bin target named `ssr_hydrate`.
原来在app/index.html
的data-bin
属性上设置了ssr_hydrate
。
而ssr_hydrate.rs
的代码确很简单,就几行如下:
rust
use app::App;
fn main() {
#[cfg(target_arch = "wasm32")]
wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));
yew::Renderer::<App>::new().hydrate();
}
上面的代码中有一个方法调用叫.hydrate()
,难道trunk build index.html
的过程才是Hydration吗?
这里我想起来之前的一个发现,即页面展现出来了,但是点击页面上的按钮没有反应,最初我以为是代码的问题,后来才发现,当页面展现出来的时候,wasm文件还在加载中。那么这个现象是不是可以说明页面上展现出来的内容不是wasm文件本身生成的,而是服务器端渲染的。
等等,如果展现的页面是服务器端渲染的,那wasm文件又是如何知道当前页面的状态的呢?服务器端渲染的内容最终是要加载到浏览器端然后和wasm文件中的代码交互的啊。这是不是就是Hydration呢?
最后附上Yew官方关于SSR Hydration的阐述,如下
Hydration is the process that connects a Yew application to the server-side generated HTML file. By default, ServerRender prints hydratable html string which includes additional information to facilitate hydration. When the Renderer::hydrate method is called, instead of start rendering from scratch, Yew will reconcile the Virtual DOM generated by the application with the html string generated by the server renderer.
很抱歉留下了一个问题,我也希望能够尽快在后面的开发过程中找到这个问题的答案。