• 创建一个新的 Hugo 站点
  • 创建 Rust 项目
  • 从 JavaScript 调用 Rust
  • 将WebAssembly嵌入网站
  • 结论
  • 首页
  • 文章
  • 笔记
  • 书架
  • 作者
🇺🇸 en 🇫🇷 fr 🇮🇳 ml

Nathaniel Thomas

构建并将 Rust 部署到 Hugo 网站

2024年4月22日

我们将通过一个简单的示例,让你能够在 Hugo 网站的客户端运行 Rust 代码。我们将把 Rust 代码编译成 WebAssembly(wasm),从而在浏览器中获得接近原生的性能!

创建一个新的 Hugo 站点

首先,让我们初始化 Hugo 的快速启动站点:

hugo new site quickstart_wasm
cd quickstart_wasm
git init
git submodule add https://github.com/theNewDynamic/gohugo-theme-ananke.git themes/ananke
echo "theme = 'ananke'" >> hugo.toml
hugo server

你应该会看到类似以下的输出:

# 日志 ...
构建时间:28 毫秒
环境: "development"
从磁盘提供页面
运行在快速渲染模式。如需在更改时完全重建:hugo server --disableFastRender
Web 服务器已启动,访问地址:http://localhost:55802/ (绑定地址 127.0.0.1)

如果你打开 localhost 的链接,应该会看到类似这样的页面:

空的 Hugo 站点
一个空的 Hugo 站点

创建 Rust 项目

我们将使用 Rust 作为 wasm 的源语言,主要是因为它的宏使得创建绑定变得极其简单。为了方便起见,让我们在 Hugo 站点的 assets 目录中初始化这个库。

# 在 Hugo 站点文件夹中
cd assets
mkdir rust_app && cd rust_app
cargo init --lib

打开 Cargo.toml 并添加以下内容

# 在底部添加
[lib]
crate-type = ["cdylib", "rlib"]

现在,我们需要添加 wasm-bindgen 作为依赖项,这将为我们提供一种单行解决方案来创建绑定。

cargo add wasm-bindgen

在 src/lib.rs 中,让我们编写一个性能关键的函数,我们需要从我们的 web 应用程序中调用它。

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn sieve_of_eratosthenes(n: usize) -> Vec<i32> {
    let mut primes = Vec::new();
    let mut is_prime = vec![true; n + 1];
    is_prime[0] = false;
    is_prime[1] = false;

    for i in 2..=n {
        if is_prime[i] {
            primes.push(i as i32);

            let mut j = 2 * i;
            while j <= n {
                is_prime[j] = false;
                j += i;
            }
        }
    }

    primes
}

我们将使用以下命令构建它

wasm-pack build --target web

你应该会在 pkg 中看到编译后的输出。

ls pkg
package.json  rust_app.d.ts  rust_app.js  rust_app_bg.wasm  rust_app_bg.wasm.d.ts

从 JavaScript 调用 Rust

现在,在 rust_app 文件夹中,让我们创建一个将使用我们的素数筛的 Web 应用。

# 在 assets/rust_app 中
mkdir www && cd www
touch index.js

将以下内容放入 index.js 文件中

import init, * as wasm from '../pkg/rust_app';

init(wasm_path).then(_ => {
    function computePrimes()
    {
        var inputNumber = parseInt(
            document.getElementById('inputNumber').value,
        );
        if (!isNaN(inputNumber) && inputNumber >= 1) {
            var primes = wasm.sieve_of_eratosthenes(inputNumber);
            document.getElementById('output').innerText = primes.join(', ');
        } else {
            document.getElementById('output').innerText =
                '请输入一个有效的整数。';
        }
    }
    let button = document.getElementById('computeButton');
    button.addEventListener('click', () => {
        computePrimes();
    });
});

将WebAssembly嵌入网站

现在,我们希望将wasm函数的输出显示在网站上。因此,让我们创建一个可以在文章中插入的小型Web应用的短代码。

在 ~/quickstart_wasm/layouts/shortcodes/wasm_app.html 中:

<!doctype html>
<html lang="en">
  <head>
    <title>质数查找器</title>
  </head>
  <body>
    <input type="number" id="inputNumber" placeholder="输入一个整数..." />
    <button id="computeButton">计算</button>
    <div id="output"></div>

    <!-- rust_app 必须在 /assets 目录下才能被检测到! -->
    {{ $wasm_path := resources.Get "rust_app/pkg/rust_app_bg.wasm" }}

    <script>
      wasm_path = "{{ $wasm_path.Permalink }}";
    </script>

    {{ $index_js := resources.Get "rust_app/www/index.js" | js.Build }}

    <script type="module" src="{{ $index_js.Permalink }}"></script>
  </body>
</html>

这里的关键部分是在JS环境中设置全局变量 wasm_path。这做了两件事:

  1. 告诉Hugo通过 fetch 请求使该路径可访问
  2. 为JS脚本提供要执行的wasm字节码

现在我们应该能够从主页使用质数生成器了!

质数生成器
hugo server – 从Rust生成的质数

结论

网上关于 wasm + Hugo 的资源并不多,所以我想我应该写第一个教程。如果你有替代/更好的方法来部署 wasm,请在评论中告诉我。


←
转向 Obsidian
最大似然估计
→

back to top