(点击上方公众号,可快速关注)
作者:magicly
https://magicly.me/fe-hpc/asmjs-and-webassembly
前一篇我们探索了用Emscripten编译C代码到asm.js和WebAssembly,使前端代码执行速度大大提升,但是实际项目中由于C语言缺乏很多高级特性,不利于开发大型项目(说C可以开发操作系统kernel这种大型项目的同学不好意思,我没那么nb),而C++我又觉得太复杂,也没有用过C++做过大型项目,所以我最后选择了Rust。
一开始也纠结过要用Go还是Rust或者Swift的,后来发现Go目前还不支持编译到WebAssembly,Swift按理说应该可以支持的,因为都是用LLVM做的编译器,不过没有找到好的资料,好像说要自己编译LLVM去支持https://stackoverflow.com/questions/46572144/compile-swift-to-webassembly 。另外对Rust的一些特性很是喜欢,听说Rust很复杂,比较像Scala和Haskell,而偏偏我对Scala还算熟悉,也学过一下Haskell,所以决定尝试一下Rust。
https://github.com/ChristianMurphy/compile-to-web 这里可以查看目前能编译到WebAssembly的语言。
PS, 话说asm.js和Rust都是Mozilla搞的呢。
安装Rust的管理工具rustup
rustup用于安装管理Rust的相关工具,包括编译器rustc、包管理工具cargo等,支持安装不同版本比如stable, beta, nightly等以及在不同版本之间切换,类似于nvm。
curl https://sh.rustup.rs -sSf | sh
安装Emscripten Rust编译器
用rustup安装最新体验版(Nightly Version):
rustup toolchain add nightly
rustup target add wasm32-unknown-emscripten --toolchain nightly
安装cmake
根据平台自行选择:
brew install cmake # MacOS, brew
sudo port install cmake # MacOS, MacPorts
sudo apt-get install cmake # Debian Linux
安装 Emscripten
参考前一篇,或者直接执行下面命令:
wget https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz
tar -xvf emsdk-portable.tar.gz
cd emsdk-portable
./emsdk update
./emsdk install sdk-incoming-64bit
这一步花的时间比较久,据说要2个多小时,我是执行完命令就出去跟朋友吃饭了,所以具体时间不知道。
添加下列路径到PATH中:
~/emsdk-portable
~/emsdk-portable/clang/fastcomp/build_incoming_64/bin
~/emsdk-portable/emscripten/incoming
终端执行emcc -v检查是否安装成功。
用Webpack运行Rust
新建一个Rust/Javascript混合项目:
cargo new webasm --bin --vcs none
cd webasm
npm init
rustup override set nightly
安装Webpack, webpack-dev-server, rust-wasm-loader,
npm i -D webpack webpack-dev-server rust-wasm-loader
增加package.json脚本:
{
"name": "webasm",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"compile": "webpack --progress",
"serve": "http-server",
"start": "webpack-dev-server --content-base ./build"
},
"author": "magicly",
"license": "ISC",
"devDependencies": {
"http-server": "^0.10.0",
"rust-wasm-loader": "^0.1.2",
"webpack": "^3.6.0",
"webpack-dev-server": "^2.8.2"
}
}
在build目录下新建文件index.html:
<!DOCTYE html>
<html>
<head>
<title>Hello WebAssembly</title>
</head>
<body>
< div id="container"></div>
<script src="/bundle.js"></script>
</body>
</html>
配置webpack.config.js:
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: __dirname + '/build',
},
module: {
rules: [
{
test: /\.rs$/,
use: {
loader: 'rust-wasm-loader',
options: {
<span>// The path to the webpack output relative to the project root</span>
path: '',
release: true <span>// 没有的话性能巨差,差不多只有1/10</span>
}
}
}
]
},
<span>// The .wasm 'glue' code generated by Emscripten requires these node builtins,</span>
<span>// but won't actually use them in a web environment. We tell Webpack to not resolve those</span>
<span>// require statements since we know we won't need them.</span>
externals: {
'fs': true,
'path': true,
}
}
新建src/main.rs文件,添加我们要从js中调用的函数:
fn main() {
println!("Hello, world!");
}
<span>// Functions that you wish to access from Javascript</span>
<span>// must be marked as no_mangle</span>
#[no_mangle]
pub fn add(a: i32, b: i32) -> i32 {
return a + b
}
新建src/index.js,写代码加载WebAssembly模块:
const wasm = require('./main.rs')
wasm.initialize({ noExitRuntime: true }).then(module => {
<span>// Create a Javascript wrapper around our Rust function</span>
const add = module.cwrap('add', 'number', ['number', 'number'])
console.log('Calling rust functions from javascript!')
console.log(add(1, 2))
})
然后执行npm start,访问http://localhost:8080/就可以看到调用rust代码的效果了。并且还支持热更新哦,直接修改rust代码,保存,页面就能看到最新效果。
测试了一下前一篇里的代码,直接运行rust优化过的代码只需要300多ms,这个基本跟C代码一样,但是用wasm运行,居然要2.7s左右,不知道是哪里没有配置好,还是说现在Rust编译成wasm没有优化好。Rust支持WebAssembly应该还不是特别成熟,可以关注https://github.com/rust-lang/rust/issues/38804 跟进。
另外Rust有一个包https://crates.io/crates/webplatform, 可以用来操作DOM,不过我目前用不到(感觉没啥用)。
Refers
-
https://medium.com/@ianjsikes/get-started-with-rust-webassembly-and-webpack-58d28e219635
-
http://zcfy.cc/article/get-started-with-rust-webassembly-and-webpack-ian-j-sikes-medium-3345.html
-
Compiling to the web with Rust and emscripten
-
Rust ⇋ JavaScript
-
http://www.hellorust.com/emscripten/
-
http://asquera.de/blog/2017-04-10/the-path-to-rust-on-the-web/
-
https://github.com/mrdziuban/rust-emscripten-loader
-
https://github.com/ballercat/wasm-loader
-
https://hackernoon.com/compiling-rust-to-webassembly-guide-411066a69fde
-
https://github.com/mbasso/awesome-wasm
-
https://github.com/rust-lang/rust/issues/38805
-
https://davidmcneil.github.io/the-rusty-web/#benchmarks
-
http://asmjs.org/
-
http://webassembly.org/
-
https://kripken.github.io/emscripten-site/index.html
-
https://developer.mozilla.org/en-US/docs/WebAssembly
-
http://www.codepool.biz/emscripten-compile-cc-javascript.html
-
http://www.ruanyifeng.com/blog/2017/09/asmjs_emscripten.html
-
https://zhuanlan.zhihu.com/p/25865972
-
https://zhuanlan.zhihu.com/p/24632251
觉得本文对你有帮助?请分享给更多人
关注「前端大全」,提升前端技能
文章评论