For this tutorial, we will create a rust/wasm project called "wasm-lib" and a SvelteKit web application called "svelte-app" that uses "wasm-lib".
The "wasm-lib" project will be added to "svelte-app" as a git submodule, allowing us to keep it as a separate git repository that can be used in multiple projects, without publishing the package.
cargo generate --git https://github.com/rustwasm/wasm-pack-template --name wasm-lib
Optional step (repo can be kept local)
Adding locally hosted code to GitHub
The template comes with an initialized git repo. Make a commit, and push the changes to the remote.
We will add this repository as a Git Submodule to the SvelteKit application later.
The template comes with bindings for alert() and greet().
Let's add a binding and a macro for console.log() because why not? Check this for more.
lib.rs
//wasm-lib\src\lib.rs
// ...
#[wasm_bindgen]
extern "C" {
// ...
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
}
macro_rules! console_log {
($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
}
#[wasm_bindgen]
pub fn greet() {
// ...
console_log!("Hello, console!");
}
wasm-pack build --target web
We don't need that yet, just a sanity check.
Check the SvelteKit Docs
āļø Not in the rust (wasm-lib) project! āļø
npm create svelte@latest svelte-app
Optional:
cd svelte-app
npm install
git init
git add -A
git commit -m "initial commit"
Sanity Check:
npm run dev -- --open
Add the wasm-lib repo as a git submodule, using the remote repository created in step 3.1, or use the local path.
git submodule add https://github.com/Leangeful/wasm-lib
This clones the rust repo into our SvelteKit project.
npm install vite-plugin-wasm-pack -D
vite.config.ts
//svelte-app\vite.config.ts
// ...
import wasmPack from 'vite-plugin-wasm-pack';
// ...
plugins: [sveltekit(), wasmPack('./wasm-lib')]
// ...
Like we did in step 3.3, however this time in our svelte-app.
For convenience, we add the build script to our package.json.
//svelte-app\package.json
// ...
"scripts": {
"wasm": "wasm-pack build ./wasm-lib --target web",
// ...
}
We run this script with:
npm run wasm
By default, pages are rendered both on the server (SSR) for the initial request and in the browser (CSR) for subsequent navigation.
Our WebAssembly can only run in the browser and will cause errors if imported during SSR.
See SvelteKit Docs for solutions.
Here are two possible ways to do this.
Import in onMount( ).
<!-- src\routes\+page.svelte -->
<script lang="ts">
import { onMount } from 'svelte';
let lib: typeof import('wasm-lib');
onMount(async () => {
lib = await import('wasm-lib');
await lib.default();
lib.greet();
});
</script>
<button on:click={() => lib.greet()}>Greet</button>
Disable SSR for the page.
//src\routes\+page.server.ts
export const ssr = false;
<!-- src\routes\+page.svelte -->
<script lang="ts">
import { onMount } from 'svelte';
import * as lib from 'wasm-lib';
onMount(async () => {
await lib.default();
lib.greet();
});
</script>
<button on:click={() => lib.greet()}>Greet</button>
We use
await lib.default();
in the onMount( ) function to instantiate the WebAssembly in either case.
npm run dev
We should be greeted on load, and when clicking the button.