aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/webassembly/rust_to_wasm/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'files/zh-cn/webassembly/rust_to_wasm/index.html')
-rw-r--r--files/zh-cn/webassembly/rust_to_wasm/index.html321
1 files changed, 321 insertions, 0 deletions
diff --git a/files/zh-cn/webassembly/rust_to_wasm/index.html b/files/zh-cn/webassembly/rust_to_wasm/index.html
new file mode 100644
index 0000000000..0b2a70598e
--- /dev/null
+++ b/files/zh-cn/webassembly/rust_to_wasm/index.html
@@ -0,0 +1,321 @@
+---
+title: 编译 Rust 为 WebAssembly
+slug: WebAssembly/Rust_to_wasm
+tags:
+ - WebAssembly
+ - rust
+ - wasm
+ - 编译
+translation_of: WebAssembly/Rust_to_wasm
+---
+<div>{{WebAssemblySidebar}}</div>
+
+<p class="summary">如果你写了一些 Rust 代码,你可以把它编译成 WebAssembly!这份教程将带你编译 Rust 项目为 wasm 并在一个现存的 web 应用中使用它。</p>
+
+<h2 id="Rust_和_WebAssembly_用例">Rust 和 WebAssembly 用例</h2>
+
+<p>Rust 和 WebAssembly 有两大主要用例:</p>
+
+<ul>
+ <li>构建完整应用 —— 整个 Web 应用都基于 Rust 开发!</li>
+ <li>构建应用的组成部分 —— 在现存的 JavaScript 前端中使用 Rust。</li>
+</ul>
+
+<p>目前,Rust 团队正专注于第二种用例,因此我们也将着重介绍它。对于第一种用例,可以参阅 <code><a href="https://github.com/DenisKolodin/yew">yew</a></code> 这类项目。</p>
+
+<p>在本教程中,我们将使用 Rust 的 npm 包构建工具 <code>wasm-pack</code> 来构建一个 npm 包。这个包只包含 WebAssembly 和 JavaScript 代码,以便包的用户无需安装 Rust 就能使用。他们甚至不需要知道这里包含 WebAssembly!</p>
+
+<h2 id="安装_Rust_环境">安装 Rust 环境</h2>
+
+<p>让我们看看安装 Rust 环境的所有必要步骤。</p>
+
+<h3 id="安装Rust">安装Rust</h3>
+
+<p>前往 <a href="https://www.rust-lang.org/install.html">Install Rust</a> 页面并跟随指示安装 Rust。这里会安装一个名为 “rustup” 的工具,这个工具能让你管理多个不同版本的 Rust。默认情况下,它会安装用于惯常Rust开发的 stable 版本 Rust Release。Rustup 会安装 Rust 的编译器 <code>rustc</code>、Rust 的包管理工具 <code>cargo</code>、Rust 的标准库 <code>rust-std</code> 以及一些有用的文档 <code>rust-docs</code>。</p>
+
+<div class="note">
+<p><strong>Note</strong>: 需要注意,在安装完成后,你需要把 cargo 的 <code>bin</code> 目录添加到你系统的 <code>PATH</code> 。一般来说它会自动添加,但需要你重启终端后才会生效。 </p>
+</div>
+
+<h3 id="wasm-pack">wasm-pack</h3>
+
+<p>要构建我们的包,我们需要一个额外工具 <code>wasm-pack</code>。它会帮助我们把我们的代码编译成 WebAssembly 并制造出正确的 <code>npm</code> 包。使用下面的命令可以下载并安装它:</p>
+
+<pre class="brush: bash notranslate"><code class="shell language-shell">$ cargo install wasm-pack
+</code></pre>
+
+<h3 id="安装_Node.js_并获取_npm_账户">安装 Node.js 并获取 npm 账户</h3>
+
+<p>在这个例子中我们将会构建一个 npm 包,因此你需要确保安装 Node.js 和 npm 已经安装。另外,我们将会把包发布到 npm 上,因此你还需要一个 npm 账号。它们是免费的。发布这个包并不是必须的,但是发布它非常简单,因此在本例中我们默认你会发布这个包。</p>
+
+<p>在 <a href="https://www.npmjs.com/get-npm">Get npm!</a> 页面按照说明下载并安装 Node.js 和 npm。在选择版本时,选择一个你喜欢的版本;本例不限定特定版本。</p>
+
+<p>在 <a href="https://www.npmjs.com/signup">npm signup page</a> 注册 npm 账户,并填写表格。</p>
+
+<p>接下来,在命令行中运行 <code>npm adduser</code>:</p>
+
+<pre class="brush: bash notranslate"><code class="rust language-rust">&gt; npm adduser
+Username: yournpmusername
+Password:
+Email: (this IS public) you@example.com
+</code></pre>
+
+<p>你需要完善你的用户名,密码和邮箱。如果成功了,你将会看到:</p>
+
+<pre class="brush: bash notranslate"><code>Logged in as yournpmusername on https://registry.npmjs.org/.
+</code></pre>
+
+<p>如果并未正常运行,请联系 npm 解决。</p>
+
+<h2 id="构建我们的_WebAssembly_npm_包">构建我们的 WebAssembly npm 包</h2>
+
+<p>万事俱备,来创建一个新的 Rust 包吧。打开你用来存放你私人项目的目录,做这些事:</p>
+
+<pre class="brush: bash notranslate"><code class="shell language-shell">$ cargo new --lib hello-wasm
+ Created library `hello-wasm` project
+</code></pre>
+
+<p>这里会在名为 <code>hello-wasm</code> 的子目录里创建一个新的库,里面有下一步之前你所需要的一切:</p>
+
+<pre class="notranslate"><code class="shell language-shell">+-- Cargo.toml
++-- src
+ +-- lib.rs
+</code></pre>
+
+<p>首先,我们有一个 <code>Cargo.toml</code> 文件,这是我们配置构建的方式。如果你用过 Bundler 的 <code>Gemfile</code> 或者 npm 的 <code>package.json</code>,你应该会感到很熟悉。Cargo 的用法和它们类似。</p>
+
+<p>接下来,Cargo 在 <code>src/lib.rs</code> 生成了一些 Rust 代码:</p>
+
+<pre class="notranslate"><code class="rust language-rust">#[cfg(test)]
+mod tests {
+ #[test]
+ fn it_works() {
+ assert_eq!(2 + 2, 4);
+ }
+}
+</code></pre>
+
+<p>我们完全不需要使用这些测试代码,所以继续吧,我们删掉它。</p>
+
+<h3 id="来写点_Rust_代码吧!">来写点 Rust 代码吧!</h3>
+
+<p>让我们在 <code>src/lib.rs</code> 写一些代码替换掉原来的:</p>
+
+<pre class="notranslate"><code class="rust language-rust">extern crate wasm_bindgen;
+
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen]
+extern {
+ pub fn alert(s: &amp;str);
+}
+
+#[wasm_bindgen]
+pub fn greet(name: &amp;str) {
+ alert(&amp;format!("Hello, {}!", name));
+}
+</code></pre>
+
+<p>这就是我们这个 Rust 项目的内容。它有三个主要部分,让我们按顺序来讲。这里将会给出一个缺少部分细节的高级说明;如果想要了解更多 Rust 知识,请查看在线书籍 <a href="https://doc.rust-lang.org/book/">The Rust Programming Language</a>。</p>
+
+<h4 id="使用_wasm-bindgen_在_Rust_与_JavaScript_之间通信">使用 <code>wasm-bindgen</code> 在 Rust 与 JavaScript 之间通信</h4>
+
+<p>第一部分看起来像这样:</p>
+
+<pre class="notranslate"><code class="rust language-rust">extern crate wasm_bindgen;
+
+use wasm_bindgen::prelude::*;
+</code></pre>
+
+<p>第一行就像在说 “哇 Rust,我们在用一个叫做 wasm_bindgen 的库”。在 Rust 当中,库被称为 “crates”,因为我们使用的是一个外部库,所以有  "extern"。</p>
+
+<p>明白了吗? <strong>Cargo ships crates</strong>.</p>
+
+<p>第三行包括了一个将库中的代码引入到你的代码中的使用命令。在这个情况下,将会引入 <code>wasm_bindgen::prelude</code> 的全部模块。我们将在下一节中使用这些内容。</p>
+
+<p>在我们开始下一节之前,我们将讲一讲 <code>wasm-bindgen</code>.</p>
+
+<p><code>wasm-pack</code> 使用 <code>wasm-bindgen</code>,其它工具,去提供一个连接 JavaScript 和 Rust 的桥。它允许 JavaScript 使用 string 调用 Rust API,或者调用一个 Rust function 去捕获 JavaScript 异常。</p>
+
+<p>我们将在我们的包中使用 <code>wasm-bindgen</code> 的功能。事实上,这是下一节的内容!</p>
+
+<h4 id="在_Rust_中调用来自_JavaScript_的外部函数">在 Rust 中调用来自 JavaScript  的外部函数</h4>
+
+<p>接下来的部分看起来像这样:</p>
+
+<pre class="notranslate"><code class="rust language-rust">#[wasm_bindgen]
+extern {
+ pub fn alert(s: &amp;str);
+}
+</code></pre>
+
+<p>在 <code>#[]</code> 中的内容叫做 "属性",并以某种方式改变下面的语句。在这种情况下,下面的语句是一个 <code>extern</code>,它将告诉 Rust that <span class="tlid-translation translation" lang="zh-CN"><span title="">我们想调用一些外部定义的函数</span></span>。这个属性告诉我们 "wasm-bindgen 知道如何找到这些函数"。</p>
+
+<p>第三行是用 Rust 写的函数签名。它告诉我们 "<code>alert</code> 函数接受一个叫做 s 的字符串作为参数。"</p>
+
+<p>你可能会疑惑这个函数是什么,你的疑惑可能是正确的:这是 <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/alert">the <code>alert</code> function provided by JavaScript</a>!我们将在下一节中调用这个函数。</p>
+
+<p>当你想调用新的 JavaScript 函数时,你可以在这里写他们,<code>wasm-bindgen</code> 将负责为您设置一切。<span class="tlid-translation translation" lang="zh-CN"><span title="">并非一切都得到支持,但我们正在努力!如果缺少某些内容,</span></span>请 <a href="https://github.com/rustwasm/wasm-bindgen/issues/new">file bugs</a> 。</p>
+
+<h4 id="编写能够在JavaScript中调用的_Rust_函数">编写能够在JavaScript中调用的 Rust 函数</h4>
+
+<p>最后一部分是这样的:</p>
+
+<pre class="notranslate"><code class="rust language-rust">#[wasm_bindgen]
+pub fn greet(name: &amp;str) {
+ alert(&amp;format!("Hello, {}!", name));
+}
+</code></pre>
+
+<p>我们又看到了 <code>#[wasm_bindgen]</code> 属性。在这里,它并非定义一个 <code>extern</code> 块,而是 <code>fn,</code>这代表我们希望能够在 JavaScript 中使用这个 Rust 函数。 这和 <code>extern</code> 正相反:我们并非引入函数,而是要把函数给外部世界使用。</p>
+
+<p>这个函数的名字是 <code>greet</code>,它需要一个参数,一个字符串 (写作 <code>&amp;str</code>)。它调用了我们前面在 <code>extern</code> 块中引入的 <code>alert</code> 函数。它传递了一个让我们串联字符串的 <code>format!</code> 宏的调用。</p>
+
+<p><code>format!</code> 在这里有两个参数,一个格式化字符串和一个要填入的变量。格式化字符串是 <code>"Hello, {}!"</code> 部分。它可以包含一个或多个 <code>{}</code>,变量将会被填入其中。传递的变量是 <code>name</code>,也就是这个函数的参数。所以当我们调用 <code>greet("Steve")</code>时我们就能看到 <code>"Hello, Steve!"。</code></p>
+
+<p>这个传递到了 <code>alert()</code>,所以当我们调用这个函数时,我们应该能看到他谈弹出了一个带有 "Hello, Steve!" 的消息框。</p>
+
+<p>我们的库写完了,是时候构建它了。</p>
+
+<h3 id="把我们的代码编译到_WebAssembly">把我们的代码编译到 WebAssembly</h3>
+
+<p>为了能够正确的编译我们的代码,首先我们需要配置 <code>Cargo.toml</code>。打开这个文件,将内容改为如下所示:</p>
+
+<pre class="notranslate"><code class="toml language-toml">[package]
+name = "hello-wasm"
+version = "0.1.0"
+authors = ["Your Name &lt;you@example.com&gt;"]
+description = "A sample project with wasm-pack"
+license = "MIT/Apache-2.0"
+repository = "https://github.com/yourgithubusername/hello-wasm"
+
+[lib]
+crate-type = ["cdylib"]
+
+[dependencies]
+wasm-bindgen = "0.2"
+</code></pre>
+
+<p>你需要改为自己的仓库,同时 Cargo 需要通过 <code>git</code> 来完善 <code>authors</code> 部分。</p>
+
+<p>最重要的是添加底下的部分。第一个部分 — <code>[lib]</code> — 告诉 Rust 为我们的包建立一个 <code>cdylib</code> 版本;在本教程中我们不会讲解它的含义。有关更多信息,请参阅 <a href="https://doc.rust-lang.org/cargo/guide/">Cargo</a> 和 <a href="https://doc.rust-lang.org/reference/linkage.html">Rust Linkage</a> 文档。</p>
+
+<p>第二个部分是 <code>[dependencies]</code> 部分。在这里我们告诉 Cargo 我们需要依赖哪个版本的 <code>wasm-bindgen</code> ;在这个例子中,它是 <code>0.2.z</code> 版本的 (不是 <code>0.3.0</code> 或者其他版本)。</p>
+
+<h3 id="构建包">构建包</h3>
+
+<p>现在我们已经完成了所有配置项,开始构建吧!在命令行输入以下命令:</p>
+
+<pre class="brush: bash notranslate"><code class="shell language-shell">$ wasm-pack build --scope mynpmusername
+</code></pre>
+
+<p>这个命令将做一系列事情 (这会花一些时间,特别是当你第一次运行 <code>wasm-pack</code>)。想了解详细情况,查看<a href="https://hacks.mozilla.org/2018/04/hello-wasm-pack/">这篇在 Mozilla Hacks 上的文章</a>。简单来说,<code>wasm-pack build</code> 将做以下几件事:</p>
+
+<ol>
+ <li>将你的 Rust 代码编译成 WebAssembly。</li>
+ <li>在编译好的 WebAssembly 代码基础上运行 <code>wasm-bindgen</code>,生成一个 JavaScript 文件将 WebAssembly 文件包装成一个模块以便 npm 能够识别它。</li>
+ <li>创建一个 <code>pkg</code> 文件夹并将 JavaScript 文件和生成的 WebAssembly 代码移到其中。</li>
+ <li>读取你的 <code>Cargo.toml</code> 并生成相应的 <code>package.json。</code></li>
+ <li>复制你的 <code>README.md</code> (如果有的话) 到文件夹中。</li>
+</ol>
+
+<p>最后的结果?你在 <code>pkg</code> 文件夹下有了一个 npm 包。</p>
+
+<h4 id="对代码体积的一些说明">对代码体积的一些说明</h4>
+
+<p>如果你检查生成的 WebAssembly 文件体积,它可能有几百 kB。我们没有让 Rust 去压缩生成的代码,从而大大减少生成包的体积。这和本次教程主题无关,但如果你想了解更多,查看 Rust WebAssembly 工作组文档上关于 <a href="https://rustwasm.github.io/book/game-of-life/code-size.html#shrinking-wasm-size">减少 .wasm 体积</a> 的说明。</p>
+
+<h3 id="把我们的包发布到_npm">把我们的包发布到 npm</h3>
+
+<p>把我们的新包发布到 npm registry:</p>
+
+<pre class="brush: bash notranslate"><code class="shell language-shell">$ cd pkg
+$ npm publish --access=public
+</code></pre>
+
+<p>我们现在有了一个 npm 包,使用 Rust 编写,但已经被编译为 WebAssembly 了。现在这个包已经可以被 JavaScript 使用了,而且使用它完全不需要用户安装 Rust ;包中的代码是 WebAssembly 代码,而不是 Rust 源码!</p>
+
+<h2 id="在网站上使用我们的包">在网站上使用我们的包</h2>
+
+<p><span class="tlid-translation translation" lang="zh-CN"><span title="">让我们建立一个使用我们包的网站!</span> <span title="">人们通过各种打包工具使用 npm包,在本教程中,我们将使用 </span></span><code>webpack</code><span class="tlid-translation translation" lang="zh-CN"><span title="">。</span> <span title="">它比其他某些打包工具稍微复杂一点,但展示了更实际的用法。</span><br>
+ <br>
+ <span title="">让我们离开</span></span><code>pkg</code><span class="tlid-translation translation" lang="zh-CN"><span title="">目录,并创建一个新目录</span></span><code>site</code><span class="tlid-translation translation" lang="zh-CN"><span title="">,尝试以下操作:</span></span></p>
+
+<pre class="brush: bash notranslate"><code class="bash language-bash">$ cd ../..
+$ mkdir site
+$ cd site
+</code></pre>
+
+<p>创建一个新文件 <code>package.json</code>,然后输入如下代码:</p>
+
+<pre class="brush: json notranslate"><code class="json language-json">{
+ "scripts": {
+ "serve": "webpack-dev-server"
+ },
+ "dependencies": {
+ "@mynpmusername/hello-wasm": "^0.1.0"
+ },
+ "devDependencies": {
+ "webpack": "^4.25.1",
+ "webpack-cli": "^3.1.2",
+ "webpack-dev-server": "^3.1.10"
+ }
+}
+</code></pre>
+
+<p><span class="tlid-translation translation" lang="zh-CN"><span title="">请注意,您需要在依赖项部分的 </span></span><code>@</code><span class="tlid-translation translation" lang="zh-CN"><span title=""> 之后填写自己的用户名。</span><br>
+ <br>
+ <span title="">接下来,我们需要配置Webpack。</span> <span title="">创建 </span></span><code>webpack.config.js</code><span class="tlid-translation translation" lang="zh-CN"><span title=""> 并输入:</span></span></p>
+
+<pre class="brush: js notranslate"><code class="javascript language-javascript">const path = require('path');
+module.exports = {
+ entry: "./index.js",
+ output: {
+ path: path.resolve(__dirname, "dist"),
+ filename: "index.js",
+ },
+ mode: "development"
+};
+</code></pre>
+
+<p><span class="tlid-translation translation" lang="zh-CN"><span title="">现在我们需要一个HTML文件。</span> <span title="">创建一个<code>index.html</code>并写入如下内容:</span></span></p>
+
+<pre class="notranslate"><code class="html language-html">&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;meta charset="utf-8"&gt;
+ &lt;title&gt;hello-wasm example&lt;/title&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+ &lt;script src="./index.js"&gt;&lt;/script&gt;
+ &lt;/body&gt;
+&lt;/html&gt;
+</code></pre>
+
+<p><span class="tlid-translation translation" lang="zh-CN"><span title="">最后,从HTML文件中引用<code>index.js</code>:</span></span></p>
+
+<pre class="brush: js notranslate"><code class="javascript language-javascript">const js = import("./node_modules/@yournpmusername/hello-wasm/hello_wasm.js");
+js.then(js =&gt; {
+ js.greet("WebAssembly");
+});
+</code></pre>
+
+<p><span class="tlid-translation translation" lang="zh-CN"><span title="">请注意,您需要再次填写您的npm用户名。</span><br>
+ <br>
+ <span title="">这将从<code>node_modules</code>文件夹导入我们的模块。</span><span title="">这不是最佳做法,但这里只做一个演示,因此暂时就这样用。</span> <span title="">加载后,它将从该模块调用<code>greet</code>函数,并传入字符串“WebAssembly”参数。</span><span title="">注意这里看上去没有什么特别的,但是我们正在调用 Rust 代码!</span> <span title="">就JavaScript代码所知,这只是一个普通模块。</span><br>
+ <br>
+ <span title="">我们已经完成了所有的文件!</span> <span title="">让我们试一下:</span></span></p>
+
+<pre class="brush: bash notranslate"><code class="shell language-shell">$ npm install
+$ npm run serve
+</code></pre>
+
+<p><span class="tlid-translation translation" lang="zh-CN"><span title="">这将启动一个Web服务器。</span> <span title="">访问 </span></span><a href="http://localhost:8080">http://localhost:8080 </a><span class="tlid-translation translation" lang="zh-CN"><span title="">,您应该会在屏幕上看到一个警告框,其中包含 </span></span><code>Hello, WebAssembly!</code><span class="tlid-translation translation" lang="zh-CN"> !<span title="">我们已经成功地从 JavaScript 调用了 Rust,并从 Rust 调用了 JavaScript。</span></span></p>
+
+<p>
+ </p><h2 id="结论">结论</h2>
+
+
+<p>本教程到此结束。希望你觉得它有用。</p>
+
+<p>在这个领域,有很多工作正在推进当中。如果你希望它变得更好,可以参阅  <a href="http://fitzgeraldnick.com/2018/02/27/wasm-domain-working-group.html">Rust Webassembly 工作组</a>。</p>