最近一直学习Yew的使用,突然间觉得Yew这个到底是怎么运行的呢?Yew官方推荐Trunk来构建、打包成前端Web应用。那么Trunk到底干了些什么事呢?
研究Trunk的源码发现了一些蛛丝马迹,首先Trunk本身也是Rust写的。Trunk本身只是一个整合者,编译wasm文件也是执行外部程序,我们来看下编译rust成wasm的源文件pipelines/rust.rs
主要两个步骤:第一步先调用cargo进行编译,这一步生成target为wasm32-unknown-unknown的wasm文件。第二步,通过调用wasm-bindgen,把前一步生成的wasm文件作为输入,最后生成用于web的wasm文件以及js文件。第二步很关键,Trunk的配置说明要求一定要有main函数,以Yew为例。
实际上Trunk里面有好几个例子,这是一个官方的测试例子。
实际上Yew这类完全使用脚本来动态的操作Dom来达到页面的变化原理跟上面这个例子差不多,但我有一点疑惑的地方在于加载wasm后是如何执行这个main方法运行整个应用的呢?之前有看过基于库的形式,但那个一般是在rust中定义某个函数,加载完成wasm后再在JS中调用。但是Trunk这个生成的文件中似乎不太容易看出来,到底是怎么调用的呢?
Trunk构建后的index.html中会加入上面文件,再看下自动添加的这段。
可以看出会自动执行init方法,然后我们看下js文件内部。
发现默认会执行__wbg_init这个方法最后会调用__wbg_finalize_init的方法。
这个方法内部wasm会调用__wbindgen_start这个方法,我们通过chrome的调试工具来看下。
这个方法内部确实调用main方法,回到Trunk构建wasm的步骤,__wbindgen_start是在哪一步加入到wasm中的呢?第一步构建的wasm文件我们可以在target目录找到。
这里我们打断一下,wasm格式是二进制,我们需要把他转成可读的格式,这里我们使用wabt。以下是mac上的安装方式:
brew install wabt
转换成wat格式
wasm2wat ./yew-lab.wasm -o ./yew-lab.wat
发现第一步构建的wasm中并没有__wbindgen_start这个方法,那么可以肯定是在wasm-bindgen构建环节加入的。我们还是看下wasm-bindgen的源码wasm-conventions
我们发现了get_or_insert_start_builder这个方法,然后搜索下。
根据线索我们再进一步,再看下源码cli-support/src/wit/mod.rs
这个函数已经写的很明确了,发现main函数然后把加入到start里执行。
如果有兴趣可以看下wasm-bindgen中生成js的处理,源码crates/cli-support/src/js/mod.rs
最后我们再回到Trunk本身,再看源码pipelines/rust.rs
Trunk最后把生成的文件作了一个整合,生成index.html。