3

Is there a way to use npm packages inside Rust code along with webassembly? Right now using webpack, @wasm-tool/wasm-pack-plugin and wasm_bindgen crate that were already present in this template: https://github.com/rustwasm/rust-webpack-template/tree/master/template

TIA.

Javed
  • 460
  • 4
  • 15

1 Answers1

3

Yes there is a way to use npm pakage inside your rust/wasm code. Let's say you want to use date-fns package you installed with npm i date-fns and you want to use it inside your rust project.

Here's what I did. - Bundle your javascript and use it with wasm-bindgen Folder structure

As you can see in the picture, I have my node_modules/package.json, cargo.toml in the same folder for convenience sake.

  1. npm i esbuild for esbuild. This is for bundling your javascript. this is my esbuild.js

esbuild.build({
  entryPoints: ['package.js'],
  bundle: true,
  outfile: 'src/package.js',
  format: 'esm',
  minify: true,
}).catch(() => process.exit(1));
  1. add build command in package.json "esbuild":"node esbuild.js"
  2. create package.js for functions you want to export to rust project.
import { format } from 'date-fns';

export function Dateformat(date, formatString) {
    return format(date, formatString);
}
  1. run esbuild command npm run esbuild After running the command you will see the package.js in your src folder. That's the javascript code you can use in your rust project.

  2. import javascript with wasm-bindgen

use js_sys::Date;
use wasm_bindgen::prelude::*;

#[wasm_bindgen(module = "/src/package.js")]
extern "C" {
    fn Dateformat(date: &Date, formatString: &str) -> String;
}

#[wasm_bindgen]
pub fn my_format(date: &Date, format_string: &str) -> String {
    Dateformat(date, format_string)
}
  1. use the imported function in your rust/wasm project.
// this is the project set up with yew.
use js_sys::Date;
use yew::prelude::*;

use crate::pages::date_fns::my_format;

#[function_component(NpmCode)]
pub fn npm_code() -> Html {
    let date = use_state(|| Option::<String>::None);
    
    let onclick = {
        let date = date.clone();
        Callback::from(move |_| {
            let now = Date::new_0();
            let formatted_date = my_format(&now, "'Today is a' eeee");
            date.set(Some(formatted_date));
        })
    };

    html! {
        <div class="flex flex-col items-center">
            <p class="text-lg font-bold mb-2">{"This time is generated with date-fns npm package"}</p>
            <p class="text-gray-500 mb-4">{date.clone().as_ref().map(|d| d.as_str()).unwrap_or("null")}</p>
            <button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" {onclick}>
                {"Generate Date"}
            </button>
        </div>
    }
}
  1. result Result

I also made a Proof of Concept where you directly download javascript in your browser using wasm-bindgen. In the link below. https://github.com/jinseok9338/WASM-POC I need to update the ReadMe. So you can understand better. It will be done in next few weeks.

Arnold Schrijver
  • 3,588
  • 3
  • 36
  • 65
서진석
  • 31
  • 4
  • Here's how I applied your approach. Please let me know if any objections to the open-source licensing https://github.com/maciejhirsz/kobold/pull/84 – Luke Schoen May 13 '23 at 13:07
  • What about debugging? Is there any way to add source map? – Amiya Behera May 20 '23 at 10:06
  • Got it: const esbuild = require('esbuild'); esbuild.build({ entryPoints: ['package.js'], bundle: true, outfile: 'src/package.js', format: 'esm', sourcemap: 'inline', minify: true, }).catch(() => process.exit(1)); – Amiya Behera May 20 '23 at 10:42