Repository: thedjinn/MiniWASM
Branch: main
Commit: ebe69abe5480
Files: 10
Total size: 12.1 KB
Directory structure:
gitextract_3xs41573/
├── .gitignore
├── Cargo.toml
├── Dockerfile
├── LICENSE
├── README.md
├── build.sh
├── docker-shell.sh
├── index.html
├── serve.sh
└── src/
└── lib.rs
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
target/
miniwasm.wasm
================================================
FILE: Cargo.toml
================================================
[package]
name = "miniwasm"
version = "1.0.0"
authors = ["Emil Loer <emil@koffietijd.net>"]
edition = "2018"
license = "MIT"
[lib]
crate-type = ["cdylib", "rlib"]
[features]
default = ["wee_alloc"]
[dependencies]
wee_alloc = { version = "0.4.5", optional = true }
[profile.release]
opt-level = "s"
lto = true
================================================
FILE: Dockerfile
================================================
FROM rust:1.50.0-buster
RUN set -ex; \
apt-get update && \
apt-get install --no-install-recommends -y binaryen wabt && \
rustup target add wasm32-unknown-unknown && \
mkdir -p /app
WORKDIR /app
================================================
FILE: LICENSE
================================================
Copyright 2021 Emil Loer
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
# MiniWASM - A minimalist Rust WebAssembly project template
This is a minimal Rust-powered WebAssembly application template. It was
designed to showcase what must be done to get Rust-powered WebAssembly going
with only a small amount of code, while still providing useful tools, such as
integration with `console.log`.
## How to build?
The easiest way is to install Docker on your system and run the
`docker-shell.sh` script. This script builds a Docker image containing Rust,
the wasm32-unknown-unknown target, and a couple of dependencies for optimizing
the generated `.wasm` files.
After building the Docker image the script then launches a container with that
image, giving you a shell with a proper build environment. Alternatively you
can just install Rust and the `wasm32` target on your host machine, and also
install `binaryen` and `wabt`.
Either way, after opening a shell with a build environment, you can just run
the `build.sh` script. This builds the `miniwasm.wasm` file and runs it
through the optimizer to reduce the file size.
Now that you have the compiled WebAssembly file you can run the `serve.sh`
script. This runs a web server in the current working directory (thanks to
Python). You can then go to `http://localhost:8000/` to view the application.
Open the console to see the log messages that the WebAssembly produces.
## Why not wasm-bindgen or wasm-pack?
Wasm-bindgen is awesome, so use it when you can. I myself am working on
projects that have more strict performance requirements, and wasm-bindgen's
translation layer often gets in the way of performance when I need to pass
data back and forth between Rust and JavaScript. Therefore I created MiniWASM
as a template to quickly prototype new experiments for my algorithms.
Another reason why you might want to use MiniWASM as a starting point is that
you want to build something small and don't want to depend on wasm-pack's NPM
packages.
## Compatibility
This application template should be compatible with all modern browsers.
However, it has only been tested with Chrome 88 and Safari 14. It will
probably work fine in Firefox too though.
## Technical details
This project consists of two components:
1. A Rust file serving as the entry point for the WebAssembly application.
2. An HTML file with embedded JavaScript code to bootstrap the WebAssembly
application.
### The Rust WebAssembly application
The Rust WebAssembly application is a single-file crate that performs a few
functions:
1. It sets up `wee_alloc` as the memory allocator.
2. It has a bridge to send log messages to JavaScript. This is done by
importing some proxy functions (one for `console.log` and one for
`console.error`) and calling them with the address and length of a `&str`.
The JavaScript implementation of these functions then looks into the
WebAssembly application's `WebAssembly.Memory` instance and extracts the
characters, converting the raw bytes back into a JavaScript-representation
before handing them off to the JavaScript console functions.
3. It defines a struct that holds the application's global state and stores
this in a cell in thread local storage.
4. It defines functions that act as a bridge between the WebAssembly module's
external interface and the application struct.
5. It has a bootstrapping function that sets up a new panic handler so that we
can see panics in the JavaScript console.
### JavaScript bootstrapping code
Instantiating a WebAssembly module is easy. We just have to fetch the `.wasm`
file and pass its contents into `WebAssembly.instantiate`.
To get logging to work we need to do a little bit more though. When
instantiating the WebAssembly module we provide an import descriptor that
exposes `console.log` and `console.error`. We can't expose those functions
directly though, because WebAssembly's calling convention only allows us to
use primitive types as arguments and return values. Therefore we wrap the
logging functions with a function that takes the location of a string slice
and extracts the bytes from the WebAssembly application's `Memory` instance.
These bytes are converted into a JavaScript string and then handed off to the
logging function.
## License
Copyright 2021 Emil Loer.
This project is licensed under the MIT license. A copy of the license can be
found in the project repository.
================================================
FILE: build.sh
================================================
#!/bin/bash
set -e
TARGET_PATH="target/wasm32-unknown-unknown/release/miniwasm.wasm"
# Build the wasm32 release target
cargo build --target wasm32-unknown-unknown --release --lib
# Run the wasm optimizer
wasm-opt ${TARGET_PATH} -o ${TARGET_PATH} -Oz --strip-debug --strip-producers --vacuum
# Copy the wasm file to the root directory so it can be served.
cp ${TARGET_PATH} ./miniwasm.wasm
================================================
FILE: docker-shell.sh
================================================
#!/bin/bash
# This script builds the development docker image and runs it with port
# 8000 exposed. It also mounts the current working directory in to /app
# inside the container so you can use an editor that is running outside
# of the container.
set -e
docker build -t miniwasm -f Dockerfile .
docker run -ti --mount type=bind,source="$PWD",target=/app -p 8000:8000 miniwasm
================================================
FILE: index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>MiniWASM</title>
</head>
<body>
<h1>MiniWASM</h1>
<p>Open the development console to see log messages.</p>
<script>
class MiniBridge {
async bootstrap(url) {
// Fetch wasm file
const response = await fetch(url);
if (!response.ok) {
throw Error("Error loading wasm file: " + response.status);
}
// Instantiate WebAssembly context
const data = await response.arrayBuffer();
const webAssembly = await WebAssembly.instantiate(data, {
env: {
console_log: this.extractString(console.log),
console_error: this.extractString(console.error)
}
});
// Grab the wasm instance and its memory (wrapped in an Uint8Array)
this.wasm = webAssembly.instance;
this.buffer = new Uint8Array(this.wasm.exports.memory.buffer);
// Call the wasm module's entry point
this.wasm.exports.initialize();
}
extractString = fn => (ptr, len) => {
// Get a fresh Uint8Array if the wasm memory buffer was moved
const buffer = this.wasm.exports.memory.buffer;
if (this.buffer !== buffer) {
this.buffer = new Uint8Array(buffer);
}
// Make a string from the slice of memory and pass it into fn
fn(String.fromCharCode.apply(null, this.buffer.slice(ptr, ptr + len)));
}
}
const bridge = new MiniBridge();
bridge.bootstrap("miniwasm.wasm").then(function() {
console.log("Bootstrap completed, now go build something awesome!");
// Call example function
const value = bridge.wasm.exports.hello(256);
console.log("The value returned by hello() was " + value);
});
</script>
</body>
</html>
================================================
FILE: serve.sh
================================================
#!/bin/bash
set -e
# Run Python's built-in web server.
python3 -m http.server
================================================
FILE: src/lib.rs
================================================
//! This is a minimal WebAssembly application. It was designed to showcase what must be done to get
//! Rust-powered WebAssembly going with only a small amount of code, while still providing useful
//! tools, such as integration with console.log.
use std::cell::RefCell;
use std::panic;
/// Use wee_alloc as the global allocator
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
thread_local! {
/// Assign some memory to global state. We don't use lazy_alloc or something similar to prevent
/// pulling in a lot of threading code. This of course limits this example to a single threaded
/// application, but that's fine for most use cases.
///
/// Note: wrapping the RefCell in a Box appears to result in smaller code size
static APP: Box<RefCell<App>> = Box::new(RefCell::new(App::new()));
}
/// A custom panic handler that delegates to console.error so we can see panics inside the browser
/// console.
fn panic_handler(info: &panic::PanicInfo) {
error(&info.to_string());
}
/// Import some callbacks that map to console functions.
extern "C" {
#[link_name="console_log"]
fn _console_log(a_ptr: *const u8, a_len: usize);
#[link_name="console_error"]
fn _console_error(a_ptr: *const u8, a_len: usize);
}
/// A helper function to wrap an unsafe external callback (that requires memory addresses) with a
/// function that accepts a &str. The &str is split into an address/length tuple so the
/// JavaScript-side knows where to find its argument.
fn wrap(s: &str, f: unsafe extern "C" fn(*const u8, usize)) {
let ptr = s.as_ptr();
let len = s.len();
unsafe {
f(ptr, len);
}
}
/// Forward the provided &str to JavaScript's console.log
pub fn log(s: &str) {
wrap(s, _console_log);
}
/// Forward the provided &str to JavaScript's console.error
pub fn error(s: &str) {
wrap(s, _console_error);
}
/// Initialization entry point for the WebAssembly module. This sets a new panic handler and calls
/// the initialize function on the global App instance.
#[no_mangle]
pub extern "C" fn initialize() {
panic::set_hook(Box::new(panic_handler));
APP.with(|k| k.borrow_mut().initialize());
}
/// Example exported custom function. This one calls a method on the App instance and returns its
/// result. Note that calling methods from the App instance is optional, but this approach makes
/// things more flexible by providing a container for global state.
#[no_mangle]
pub extern "C" fn hello(arg: u32) -> u32 {
APP.with(|k| k.borrow_mut().hello(arg))
}
/// The WebAssembly application's global state struct.
struct App {
}
impl App {
/// Create a new App instance. This is called by thread_local! on first use of the global
/// instance.
fn new() -> Self {
Self {
}
}
/// Initialize the application here.
fn initialize(&self) {
log("App initialized");
}
/// Example custom function
fn hello(&self, arg: u32) -> u32 {
log("Hello, world!");
// Return an example value. Note that WebAssembly's calling convention only allows us to
// accept/return primitive types and pointers to said types.
arg * arg
}
}
gitextract_3xs41573/
├── .gitignore
├── Cargo.toml
├── Dockerfile
├── LICENSE
├── README.md
├── build.sh
├── docker-shell.sh
├── index.html
├── serve.sh
└── src/
└── lib.rs
SYMBOL INDEX (12 symbols across 1 files)
FILE: src/lib.rs
function panic_handler (line 24) | fn panic_handler(info: &panic::PanicInfo) {
function _console_log (line 31) | fn _console_log(a_ptr: *const u8, a_len: usize);
function _console_error (line 34) | fn _console_error(a_ptr: *const u8, a_len: usize);
function wrap (line 40) | fn wrap(s: &str, f: unsafe extern "C" fn(*const u8, usize)) {
function log (line 50) | pub fn log(s: &str) {
function error (line 55) | pub fn error(s: &str) {
function initialize (line 62) | pub extern "C" fn initialize() {
function hello (line 72) | pub extern "C" fn hello(arg: u32) -> u32 {
type App (line 77) | struct App {
method new (line 83) | fn new() -> Self {
method initialize (line 89) | fn initialize(&self) {
method hello (line 94) | fn hello(&self, arg: u32) -> u32 {
Condensed preview — 10 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (13K chars).
[
{
"path": ".gitignore",
"chars": 22,
"preview": "target/\nminiwasm.wasm\n"
},
{
"path": "Cargo.toml",
"chars": 313,
"preview": "[package]\nname = \"miniwasm\"\nversion = \"1.0.0\"\nauthors = [\"Emil Loer <emil@koffietijd.net>\"]\nedition = \"2018\"\nlicense = \""
},
{
"path": "Dockerfile",
"chars": 212,
"preview": "FROM rust:1.50.0-buster\n\nRUN set -ex; \\\n apt-get update && \\\n apt-get install --no-install-recommends -y binaryen "
},
{
"path": "LICENSE",
"chars": 1049,
"preview": "Copyright 2021 Emil Loer\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software "
},
{
"path": "README.md",
"chars": 4367,
"preview": "# MiniWASM - A minimalist Rust WebAssembly project template\n\nThis is a minimal Rust-powered WebAssembly application temp"
},
{
"path": "build.sh",
"chars": 394,
"preview": "#!/bin/bash\n\nset -e\n\nTARGET_PATH=\"target/wasm32-unknown-unknown/release/miniwasm.wasm\"\n\n# Build the wasm32 release targe"
},
{
"path": "docker-shell.sh",
"chars": 381,
"preview": "#!/bin/bash\n\n# This script builds the development docker image and runs it with port\n# 8000 exposed. It also mounts the "
},
{
"path": "index.html",
"chars": 2309,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <title>MiniWASM</title>\n </head>\n\n"
},
{
"path": "serve.sh",
"chars": 80,
"preview": "#!/bin/bash\n\nset -e\n\n# Run Python's built-in web server.\npython3 -m http.server\n"
},
{
"path": "src/lib.rs",
"chars": 3255,
"preview": "//! This is a minimal WebAssembly application. It was designed to showcase what must be done to get\n//! Rust-powered Web"
}
]
About this extraction
This page contains the full source code of the thedjinn/MiniWASM GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 10 files (12.1 KB), approximately 2.9k tokens, and a symbol index with 12 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.