What will bundling WebAssembly look like for C?

This article will show you how we will be able to bundle C in the future in our JavaScript projects!

To compile the C code in the examples to a WASM binary I used a custom version of dcodeIO/webassembly (where export and import are macros) and WebAssembly/binaryen.

Currently two bundlers planned to support theses features (Webpack and Rollup).
You can find more information in the corresponding pull requests:

Using modules

Imagine the following program written in C:

module.c
        
#include <strings.h>
#include <webassembly.h>

export void test() {
    console_log("Hi");
}
        
      

It would generate the following WASM module (textual representation):

module.wast
        
(module

  (import "@webassemblyjs/stdlib" "console_log"
    (func $console_log (param i32 i32))
  )

  (func (export "test")
    (call $console_log
      (i32.const 72)
      (i32.const 105)
    )
  )
)
        
      

Then load it into your JavaScript project:

index.js
        
import("./module.wasm").then(({test}) => {
  test();
});
        
      

The bundler will take care of importing the @webassemblyjs/stdlib package and passing the console_log function to the WASM program.

On Node.js you could import the builtin modules as well (http or fs for example).

Importing JavaScript files

Now imagine that you want to use JavaScript variables (exported from modules) in your C code:

module.c
        
#include <strings.h>
#include <webassembly.h>

import_js(./counter.js, number) int number;

export int get() {
      return number;
}
        
      

It would generate the following WASM module (textual representation):

module.wast
        
(module
  (import "./counter.js" "number" (global $number i32))

  (func (export "get") (result i32)
    (get_global $number)
  )
)
        
      

Then load it into your JavaScript project:

counter.js
        
export const number = 1;
        
      
index.js
        
import("./module.wasm").then(({get}) => {
  console.log(get());
});

        
      

Once again, the bundler will take care of passing the number constant which is in the counter.js file to our WASM program.

Under the hood

If you have already instantiated a WASM module manually, you had to pass the imports yourself (via the ImportObject).

We can see this procedure as a dynamic linking phase. It turns out that the bundler can do it instead and in addition allow to integrate into the JavaScript module system (and ecosystem).

Reach out

Say hello: [email protected].

Ping me on Twitter: @svensauleau.