CroftSoft / Library / Tutorials

Rust-webpack Project Setup

2023 Jan 15 Sun

David Wallace Croft



In recommended reading order


In 2022, I read the book published in that same year Game Development with Rust & WebAssembly by Eric Smith which uses the rust-webpack-template. The author speculated that the rust-webpack-template might be updated in the near future so some instructions might need to be adjusted as time goes on. While writing a tutorial checklist on how to set up a project using the rust-webpack-template, I noted that the GitHub project for it had not been updated in three years.

I ran into an issue during development of a project that was initialized using the rust-webpack-template that I suspected could be resolved by reading through the webpack documentation. The version of webpack that the rust-webpack-template supported was so old that I had trouble finding documentation for it. Also, the latest major version of webpack had changed enough that it did not work with the rust-webpack-template setup.

After a fair amount of effort, much experimentation, and some reading of the webpack documentation, I was able to migrate my Rust project that was set up using the rust-webpack-template into something that is now compatible with a recent major version of webpack. This also resolved my original development issue. This tutorial checklist captures that knowledge in a repeatable step-by-step fashion and should be considered as an updated alternative to using the rust-webpack-template.

Project Setup

  1. Start by following the instructions in the Rust Project Setup
  2. Install node.js
    • This will also install Node Package Manager (npm)
  3. Update your project root directory .gitignore file to include the following: node_modules /dist /target /pkg /wasm-pack.log
  4. Append the following to your Cargo.toml file: [dependencies] console_error_panic_hook = "0.1.7" js-sys = "0.3.60" wasm-bindgen = "0.2.83" wee_alloc = { version = "0.4.5", optional = true } rand = "0.8.5" futures = "0.3.25" wasm-bindgen-futures = "0.4.33" anyhow = "1.0.66" [dependencies.getrandom] version = "0.2.8" features = [ "js", ] [dependencies.web-sys] version = "0.3.60" features = [ "CanvasRenderingContext2d", "Document", "HtmlCanvasElement", "HtmlDivElement", "Window", "console", ] [dev-dependencies] futures = "0.3.25" js-sys = "0.3.60" wasm-bindgen-futures = "0.4.33" wasm-bindgen-test = "0.3.33" [features] default = ["wee_alloc"] [lib] crate-type = ["cdylib"] [profile.release] lto = true
  5. Delete src/ and replace it with src/ use js_sys::Object; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; use web_sys::console; use web_sys::window; use web_sys::CanvasRenderingContext2d; use web_sys::Document; use web_sys::Element; use web_sys::HtmlCanvasElement; use web_sys::HtmlDivElement; use wee_alloc::WeeAlloc; #[cfg(feature = "wee_alloc")] #[global_allocator] static ALLOC: WeeAlloc = WeeAlloc::INIT; #[wasm_bindgen(start)] pub fn main_js() -> Result<(), JsValue> { console_error_panic_hook::set_once(); let document: Document = window().unwrap().document().unwrap(); hello_canvas(&document); hello_console(); hello_div(&document); Ok(()) } fn hello_canvas(document: &Document) { let element: Element = document.get_element_by_id("canvas").unwrap(); let html_canvas_element: HtmlCanvasElement = element.dyn_into().unwrap(); let object: Object = html_canvas_element.get_context("2d").unwrap().unwrap(); let canvas_context: CanvasRenderingContext2d = object.dyn_into().unwrap(); canvas_context.set_font("normal 14px serif"); canvas_context.stroke_text("Hello, Canvas!", 0.0, 14.0).unwrap(); } fn hello_console() { console::log_1(&JsValue::from_str("Hello, Console!")); } fn hello_div(document: &Document) { let element: Element = document.get_element_by_id("div").unwrap(); let html_div_element: HtmlDivElement = element.dyn_into().unwrap(); html_div_element.insert_adjacent_text("afterbegin", "Hello, Div!").unwrap(); }
  6. Make a single-line JavaScript file named js/entry-index.js: import("../pkg/index.js").catch(console.error);
  7. Make a static/index.html file: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> Project Name </title> </head> <body> <canvas height="25" id="canvas" width="100"> </canvas> <div id="div"> </div> <script src="my-app.js"> </script> </body> </html>
  8. Make a webpack.config.js file in your project root directory: const path = require('path'); const CopyPlugin = require('copy-webpack-plugin'); const WasmPackPlugin = require('@wasm-tool/wasm-pack-plugin'); module.exports = { devServer: { allowedHosts: ['localhost'], client: { logging: 'verbose', overlay: true, progress: true, }, open: true, static: false, }, entry: { index: './js/entry-index.js' }, experiments: { asyncWebAssembly: true, }, mode: 'production', output: { filename: 'my-app.js', path: path.resolve(__dirname, 'dist') }, plugins: [ new CopyPlugin([ path.resolve(__dirname, 'static') ]), new WasmPackPlugin({ crateDirectory: __dirname, }), ] };
  9. Make a package.json in your root directory: { "name": "my-app", "version": "0.1.0", "author": "My Name ", "description": "My App description", "scripts": { "build": "rimraf dist pkg && webpack", "start": "rimraf dist pkg && webpack serve", "test": "cargo test && wasm-pack test --firefox --headless" }, "devDependencies": { "@wasm-tool/wasm-pack-plugin": "^1.6.0", "@webpack-cli/serve": "^2.0.1", "copy-webpack-plugin": "^5.1.2", "rimraf": "^3.0.2", "wasm-pack": "^0.10.3", "webpack": "^5.75.0", "webpack-dev-server": "^4.11.1" } }
  10. Launch the project npm install npm start

© 2023 CroftSoft Inc

- Books
- Code
- Courses
- Links
- Media
- Software
- Tutorials
CroftSoft Web