Nous allons passer en revue un exemple minimal qui vous permettra d’exécuter du code Rust côté client d’un site Hugo. Nous allons compiler le code Rust en WebAssembly (wasm), ce qui nous donnera des performances quasi-natives dans le navigateur !
Création d’un nouveau site Hugo
Commençons par initialiser le site de démarrage rapide de 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
Vous devriez voir quelque chose comme :
# Logs ...
Built in 28 ms
Environment: "development"
Serving pages from disk
Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender
Web Server is available at http://localhost:55802/ (bind address 127.0.0.1)
Si vous ouvrez l’URL localhost
, vous devriez voir quelque chose comme ceci :
Création d’un projet Rust
Nous allons utiliser Rust comme langage source pour notre wasm, principalement parce que ses macros rendent extrêmement facile la création de liaisons. Pour plus de commodité, initialisons la bibliothèque dans le répertoire assets
de notre site Hugo.
# Dans le dossier du site Hugo
cd assets
mkdir rust_app && cd rust_app
cargo init --lib
Ouvrez Cargo.toml
et ajoutez ce qui suit :
# Ajoutez ceci en bas
[lib]
crate-type = ["cdylib", "rlib"]
Maintenant, nous devons ajouter wasm-bindgen
comme dépendance, ce qui nous donnera une solution en une ligne pour créer des liaisons.
cargo add wasm-bindgen
Dans src/lib.rs
, écrivons une fonction critique en termes de performance que nous devons appeler depuis notre application 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
}
Nous allons compiler ceci avec :
wasm-pack build --target web
Vous devriez voir la sortie compilée dans pkg
.
ls pkg
package.json rust_app.d.ts rust_app.js rust_app_bg.wasm rust_app_bg.wasm.d.ts
Appeler Rust depuis Javascript
Maintenant, dans le dossier rust_app
, créons une application web qui utilisera notre crible de nombres premiers.
# dans assets/rust_app
mkdir www && cd www
touch index.js
Mettez ce qui suit dans le fichier 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 =
'Please enter a valid integer.';
}
}
let button = document.getElementById('computeButton');
button.addEventListener('click', () => {
computePrimes();
});
});
Intégration de WebAssembly dans le site
Maintenant, nous voulons que le résultat de la fonction wasm apparaisse sur le site. Créons donc un shortcode que nous pouvons insérer dans un article avec une petite application web.
Dans ~/quickstart_wasm/layouts/shortcodes/wasm_app.html
:
<!doctype html>
<html lang="en">
<head>
<title>Prime Number Finder</title>
</head>
<body>
<input type="number" id="inputNumber" placeholder="Enter an integer..." />
<button id="computeButton">Compute</button>
<div id="output"></div>
<!-- rust_app DOIT être dans /assets pour être détecté ! -->
{{ $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>
La clé ici est la partie où nous définissons la variable globale wasm_path
dans notre environnement JS. Cela fait deux choses :
- Indique à Hugo de rendre ce chemin accessible via des requêtes
fetch
- Donne au script JS le bytecode wasm à exécuter
Nous devrions maintenant pouvoir utiliser le générateur de nombres premiers depuis la page d’accueil !
hugo server
– Nombres premiers générés depuis Rust
Conclusion
Il n’y avait pas beaucoup de ressources en ligne sur wasm + Hugo, alors j’ai décidé de créer le premier tutoriel. Si vous avez une méthode alternative/meilleure pour déployer wasm, faites-le-moi savoir dans les commentaires.