Simple Rust WebAssembly Boilerplate [RUST+WASM]
Tags: rust, webassembly, webpack
Published: 2020-06-08 15:24:52

You can notice the above image has mention of crates, rust macros (unused_imports) and that is all compiled via Webpack.

You can skip my introduction, if you are just interested in RUST + WebAssembly boilerplate code [here](https://github.com/steelx/rust-wasm-boilerplate)

{% youtube MJwYzOUPm3U %}

## Intro
I recently got hooked to RUST programming language.
Rust initially looks very difficult, and yes it is.
But it was also a bit welcoming to me since Rust does not have
classes. (WIN WIN for me I don't like CLASS) The same reason why I liked GO very much and built a 2D RPG Game in [GoLang](https://www.youtube.com/watch?v=XBQ6jMGGk_Y)

But since the day I started reading RUST, I stopped using GO. (In no way GO is bad, its just Rust has something magical)

Rust definitely made me understand what is a Garbage Collector (that's what I like to think so o_0), cause Rust gives its memory safety guarantees without needing a garbage collector. I really love Rust how to helped me understand Stack & Heap (I had NO computer science background, I'm just a Frontend developer... JavaScript world).

WebAssembly has become quite mature in the past couple of years. It’s certainly no longer a bleeding-edge technology. Build tools became quite sophisticated, so you can build everything with one npm command.

Folder structure :
├── src
|    └── lib.rs
├── public
|    └── index.js
|    └── index.html
├── package.json
├── webpack.config.js
└── cargo.toml
└── web.config

![rust-lang](https://dev-to-uploads.s3.amazonaws.com/i/f1vixqs7x7bxcdhtmnbl.gif)

## Let's begin * [_](#setup)

__Cargo.toml__ needs to define crate type as dynamic C library hence we define it like below
```rust
[lib]
crate-type = ["cdylib"]
```

And some special dependencies.
Please update `dependencies.web-sys` as you add more feature from JavaScript world.

```rust
[dependencies]
console_error_panic_hook = "=0.1.6"
js-sys = "0.3.39"
lazy_static = "1.4.0"
nalgebra = "0.21.0"
wasm-bindgen = "0.2.62"

[dependencies.web-sys]
version = "0.3.39"
features = [
    'Document',
    'Element',
    'EventTarget',
    'MouseEvent',
    'Window',
]
```



## Next it is web.config file
This file includes Rust .wasm file into our application
```config
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
   <system.webServer>
      <staticContent>
         <mimeMap fileExtension=".wasm" mimeType="application/wasm" />
      </staticContent>
   </system.webServer>
</configuration>
```


### webpack.config
This is where all magic happens. Webpack compiles our Rust code into JavaScript during development and into Web-Assembly if you run `npm run build`

```javascript
const webpack = require('webpack');
const WasmPackPlugin = require('@wasm-tool/wasm-pack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = (env, args) => {
  const isProduction = (args.mode === 'production');//package.json scripts -> build

  return {
      entry: './public/index.js',
      output: {
          path: path.resolve(__dirname, 'dist'),
          filename: isProduction ? '[name].[contenthash].js' : '[name].[hash].js'
      },
      plugins: [
            new HtmlWebpackPlugin({
                template: './public/index.html'
            }),
            new WasmPackPlugin({
                crateDirectory: path.resolve(__dirname, ".")// (where the cargo.toml file is located)
            }),
            new webpack.ProvidePlugin({
                TextDecoder: ['text-encoding', 'TextDecoder'],
                TextEncoder: ['text-encoding', 'TextEncoder'],
            }),
      ],
  }
};
```


And of course make srue you have a `./public` folder with a index.html and `index.JS` file.


## index.js
This is the main front-end file, it reads our Rust code. Please make sure you don't use ES6 imports here, use commonjs alike import to avoid compile errors. This line `../pkg/index.js` webpack will create `pkg` folder, don't worry. Here `say_hello_from_rust` is actually coming from `src/lib.rs` file.

```javascript
const rust = import('../pkg/index.js');

rust.then(r => {
    r.say_hello_from_rust();
})
.catch(console.error);
```


## src/lib.rs
And now inside RUST `./src/lib.rs` file :

`wasm_bindgen` created by [Rust team](https://rustwasm.github.io/), a library that facilitate high-level interactions between wasm modules and JavaScript.

```rust
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);
}

#[wasm_bindgen]
pub fn say_hello_from_rust() {
    log("Hello from Rust World!");
}


```


## package.json

`npm i @wasm-tool/wasm-pack-plugin html-webpack-plugin text-encoding webpack webpack-cli webpack-dev-server --save-dev`

There are few more __scripts__ which helps us compile the code inside package.json

But you need to add this line to your project before every build
`rustup run nightly cargo build --target wasm32-unknown-unknown`

So I created these helper script calls, which can be found inside package.json

`npm run build` which will give you production ready code to be deployed without worrying to add the above scary line every-time.


## Result

After a couple of days experimenting with Rust+Wasm, it seems to be a good combo. Great performance and feature support opens a land of opportunities. Build tools are also great and Wasm should now be supported by all major browsers.

__Source code__: [https://github.com/steelx/rust-wasm-boilerplate](https://github.com/steelx/rust-wasm-boilerplate)


Hope you have fun working with RUST and WASM. I'm definitely going to stick with RUST :)