@radekmie
By Radosław Miernik · Published on · Comment on Meteor Forum, Reddit
Last month, in On CSS Modules in Meteor, I posted a step-by-step guide on creating a Meteor build plugin for CSS Modules. Here’s a reasonably short follow-up for WebAssembly, allowing us to easily integrate C++ or Rust code1.
First, we need some WebAssembly code to work with. While working on my PhD, I use Rust a lot (see On Automata in Rust for some sample), so Rust it is. For convenience, we’ll go with wasm-pack
to simplify the build process significantly.
This one command, similar to npm init
, will create an empty Rust project with wasm-pack
configured. The most important file is the src/lib.rs
:
use *;
If you don’t know Rust, don’t worry – this code does exactly what you think it does: returns a string. Now, let’s build it:
# The following files are created:
# ./pkg/README.md Tutorial, basic info, etc.
# ./pkg/index.d.ts Generated types for the bindings.
# ./pkg/index.js Entry point.
# ./pkg/index_bg.js Bindings and environment.
# ./pkg/index_bg.wasm WASM module itself.
# ./pkg/index_bg.wasm.d.ts Generated types for the environment.
# ./pkg/package.json Ready for publication on npm.
Our end goal is to make import { greet } from './pkg';
work in Meteor. This imports the entry point file, which finally imports a .wasm
file. Let’s create our build plugin first, reusing the configuration from the previous blog post:
// packages/wasm/package.js
;
;
;
// packages/wasm/compiler.js
;
,
new WASMCompiler,
;
And add it to our app:
The above was just some boilerplate we needed to wire up the build plugin lifecycle; now, let’s focus on two // TODO
s we left there. First, we need to think about how we actually keep the .wasm
file around. In the CSS Modules case, we translated all of the CSS code into a JS module.
While we could do that here, it’d incur a significant cost since WebAssembly is a binary format, and we’d need not only to somehow store it in a JS module but also analyze it twice (as a plain JS string and as a WASM module). Instead, we’re creating an asset, i.e., copying it into server-accessible files.
It’s important to eagerly register the asset (i.e., call addLazyWasmAsset
) in all scenarios. In other words, we have to call it in both addCompileResult
and compileOneFileLater
, not in compileOneFile
. Otherwise, a lazy module would register the asset after it was needed. However, it’s not a performance problem, as we register it as a lazy asset.
The asset is registered, and we can retrieve it using Assets.*
Meteor API. It must first be compiled into a WebAssembly.Module
and instantiated into an executable WebAssembly.Instance
. That makes our module only 4 lines long:
While this build plugin makes more sense to be packaged and released to Atmosphere, I still think there’s no need for that. Doing it in your project is fairly trivial and lets you change every bit of it if needed. And to be fully transparent, it’s also one less package to maintain for me.
There, I bought myself a month to think about the next post…
As I only wanted it on the server so far, we’ll focus on that. If needed, you can easily add support for client-side support as well, though it’ll need to be at least partially asynchronous, as the asset has to be downloaded first.