├── .gitignore ├── LICENSE ├── README.md ├── example ├── README.md ├── addTwo.wasm ├── env.mjs ├── get.wasm └── index.mjs ├── loader.mjs └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Sven Sauleau 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # @wasm-tool/node 2 | 3 | > WASM loader for Node 4 | 5 | Requires the latest version of Node (Node v10). 6 | 7 | ## Installation 8 | 9 | ```sh 10 | npm i @wasm-tool/node 11 | ``` 12 | 13 | ## Usage 14 | 15 | ```sh 16 | node --experimental-modules --loader @wasm-tool/node index.mjs 17 | ``` 18 | 19 | Or, if your WASM is the main executable: 20 | 21 | ```sh 22 | node --experimental-modules --loader @wasm-tool/node index.wasm 23 | ``` 24 | 25 | See [example](https://github.com/wasm-tool/node-loader/tree/master/example). 26 | 27 | ## Development 28 | 29 | In order to test any changes you can clone this repository and run the example locally 30 | 31 | ```sh 32 | npm install 33 | cd example 34 | node --experimental-modules --loader ../loader.mjs index.mjs 35 | ``` 36 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # Example 2 | 3 | ## Run the example 4 | 5 | ```sh 6 | node --experimental-modules --loader ../loader.mjs index.mjs 7 | ``` 8 | 9 | A recent Node's version is required. 10 | -------------------------------------------------------------------------------- /example/addTwo.wasm: -------------------------------------------------------------------------------- 1 | asm` 2 | addTwo 3 |  j name addTwo -------------------------------------------------------------------------------- /example/env.mjs: -------------------------------------------------------------------------------- 1 | export const n = 1; 2 | -------------------------------------------------------------------------------- /example/get.wasm: -------------------------------------------------------------------------------- 1 | asm` ./env.mjsnget 2 | # 3 | name -------------------------------------------------------------------------------- /example/index.mjs: -------------------------------------------------------------------------------- 1 | // (module 2 | // (type (func (param i32) (param i32) (result i32))) 3 | // (func $addTwo (param i32) (param i32) (result i32) 4 | // (get_local 0) 5 | // (get_local 1) 6 | // (i32.add) 7 | // ) 8 | // (export "addTwo" (func $addTwo)) 9 | // ) 10 | import {addTwo} from "./addTwo.wasm"; 11 | 12 | 13 | // (module 14 | // (type (func (result i32))) 15 | // (import "./env.mjs" "n" (global i32)) 16 | // (func (result i32) 17 | // (get_global 0) 18 | // ) 19 | // (export "get" (func 0)) 20 | // ) 21 | import {get} from "./get.wasm"; 22 | 23 | console.log("addTwo", addTwo(1, 2)); 24 | 25 | console.log("get", get()); 26 | -------------------------------------------------------------------------------- /loader.mjs: -------------------------------------------------------------------------------- 1 | import fs from "fs" 2 | import path from "path" 3 | 4 | async function loadDependency(base, specifier, name) { 5 | const dep = await import(new URL(specifier, base)); 6 | return dep[name]; 7 | } 8 | 9 | function readFile(path) { 10 | return fs.readFileSync(path, null); 11 | } 12 | 13 | export async function dynamicInstantiate(url) { 14 | const buffer = readFile(new URL(url)); 15 | const module = new WebAssembly.Module(buffer); 16 | 17 | /** 18 | * generate importObject 19 | */ 20 | const importObject = {}; 21 | 22 | await Promise.all(WebAssembly.Module.imports(module).map(async ({ module: importURL, name }) => { 23 | if (typeof importObject[importURL] === "undefined") { 24 | importObject[importURL] = {}; 25 | } 26 | 27 | importObject[importURL][name] = await loadDependency(url, importURL, name); 28 | })); 29 | 30 | /** 31 | * instantiation 32 | */ 33 | const wasmInstance = new WebAssembly.Instance(module, importObject); 34 | 35 | const wasmExports = WebAssembly.Module.exports(module).map(({ name }) => name); 36 | 37 | return { 38 | exports: wasmExports, 39 | 40 | execute: exports => { 41 | wasmExports.forEach(name => { 42 | exports[name].set(wasmInstance.exports[name]); 43 | }); 44 | } 45 | }; 46 | } 47 | 48 | const baseURL = new URL('file://'); 49 | baseURL.pathname = `${process.cwd()}/`; 50 | 51 | export function resolve(specifier, base, defaultResolver) { 52 | const ext = path.extname(specifier); 53 | 54 | if (ext === ".wasm") { 55 | return { 56 | url: new URL(specifier, base || baseURL).href, 57 | format: 'dynamic' 58 | }; 59 | } 60 | 61 | return defaultResolver(specifier, base); 62 | } 63 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasm-tool/node", 3 | "version": "0.1.0", 4 | "description": "WASM loader for Node", 5 | "main": "./loader.mjs", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/wasm-tool/node-loader.git" 12 | }, 13 | "keywords": [ 14 | "loader", 15 | "wasm", 16 | "webassembly", 17 | "node" 18 | ], 19 | "author": "Sven Sauleau", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/wasm-tool/node-loader/issues" 23 | }, 24 | "homepage": "https://github.com/wasm-tool/node-loader#readme", 25 | "dependencies": {} 26 | } 27 | --------------------------------------------------------------------------------