├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── bin └── wasm2js ├── example.js ├── example.wasm ├── package.json └── wasm2js.js /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | node_modules 16 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | node_modules 16 | 17 | example.wasm 18 | example.js 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2017 Thorsten Lorenz. 2 | All rights reserved. 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wasm2js 2 | 3 | Compile WebAssembly .wasm files to a commonjs module. 4 | 5 | ```js 6 | const wasm2js = require('wasm2js') 7 | const fs = require('fs') 8 | 9 | const wasmBuffer = fs.readFileSync('path/to/my.wasm') 10 | const js = wasm2js(wasmBuffer) 11 | ``` 12 | 13 | ## CLI 14 | 15 | ```sh 16 | wasm2js example.wasm -o example.js 17 | ``` 18 | 19 | ## Installation 20 | 21 | npm install wasm2js 22 | 23 | ## [API](https://thlorenz.github.io/wasm2js) 24 | 25 | 26 | 27 | ### wasm2js 28 | 29 | Takes a `.wasm` binary and wraps it inside a commonJS module that can be required 30 | in Node.js and the browser. 31 | 32 | **Parameters** 33 | 34 | - `wasmBuf` **[Buffer](https://nodejs.org/api/buffer.html)** a buffer of the .wasm code 35 | 36 | Returns **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** the commonJS module code that wraps the wasm 37 | 38 | ## Kudos 39 | 40 | 90% of this code was extracted from @mafintosh's [wat2js](https://github.com/mafintosh/wat2js). 41 | 42 | ## License 43 | 44 | MIT 45 | -------------------------------------------------------------------------------- /bin/wasm2js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | process.title = 'wasm2js' 4 | 5 | const minimist = require('minimist') 6 | const fs = require('fs') 7 | const wasm2js = require('../') 8 | 9 | const argv = minimist(process.argv.slice(2), { 10 | alias: {output: 'o', watch: 'w'}, 11 | boolean: ['w'] 12 | }) 13 | 14 | const inp = argv._[0] 15 | 16 | if (!inp) { 17 | console.error(` 18 | Usage: wasm2js [input.wasm file] [options...] 19 | --output, -o [output.js file] 20 | --watch, -w [recompile on input.wat change] 21 | `.trim()) 22 | process.exit(1) 23 | } 24 | 25 | if (argv.watch && !argv.output) { 26 | console.error('--watch requires --output') 27 | process.exit(2) 28 | } 29 | 30 | if (argv.watch) fs.watch(inp, build) 31 | build() 32 | 33 | function build() { 34 | const wasmBuffer = fs.readFileSync(inp) 35 | const src = wasm2js(wasmBuffer) 36 | if (argv.output) fs.writeFileSync(argv.output, src) 37 | else process.stdout.write(src) 38 | } 39 | -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = loadWebAssembly 3 | 4 | loadWebAssembly.supported = typeof WebAssembly !== 'undefined' 5 | 6 | function loadWebAssembly (opts) { 7 | if (!loadWebAssembly.supported) return null 8 | 9 | var imp = opts && opts.imports 10 | var wasm = toUint8Array('AGFzbQEAAAABBwFgAn9/AX8DAgEABwcBA2FkZAAACgkBBwAgACABags=') 11 | var ready = null 12 | 13 | var mod = { 14 | buffer: wasm, 15 | memory: null, 16 | exports: null, 17 | realloc: realloc, 18 | onload: onload 19 | } 20 | 21 | onload(function () {}) 22 | 23 | return mod 24 | 25 | function realloc (size) { 26 | mod.exports.memory.grow(Math.ceil(Math.abs(size - mod.memory.length) / 65536)) 27 | mod.memory = new Uint8Array(mod.exports.memory.buffer) 28 | } 29 | 30 | function onload (cb) { 31 | if (mod.exports) return cb() 32 | 33 | if (ready) { 34 | ready.then(cb.bind(null, null)).catch(cb) 35 | return 36 | } 37 | 38 | try { 39 | if (opts && opts.async) throw new Error('async') 40 | setup({instance: new WebAssembly.Instance(new WebAssembly.Module(wasm), imp)}) 41 | } catch (err) { 42 | ready = WebAssembly.instantiate(wasm, imp).then(setup) 43 | } 44 | 45 | onload(cb) 46 | } 47 | 48 | function setup (w) { 49 | mod.exports = w.instance.exports 50 | mod.memory = mod.exports.memory && mod.exports.memory.buffer && new Uint8Array(mod.exports.memory.buffer) 51 | } 52 | } 53 | 54 | function toUint8Array (s) { 55 | if (typeof atob === 'function') return new Uint8Array(atob(s).split('').map(charCodeAt)) 56 | return new (require('buf' + 'fer').Buffer)(s, 'base64') 57 | } 58 | 59 | function charCodeAt (c) { 60 | return c.charCodeAt(0) 61 | } 62 | -------------------------------------------------------------------------------- /example.wasm: -------------------------------------------------------------------------------- 1 | asm`add 2 |  j -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wasm2js", 3 | "version": "0.2.0", 4 | "description": "Compile WebAssembly .wasm files to a commonjs module.", 5 | "main": "wasm2js.js", 6 | "bin": "./bin/wasm2js", 7 | "repository": { 8 | "type": "git", 9 | "url": "git://github.com/thlorenz/wasm2js.git" 10 | }, 11 | "homepage": "https://github.com/thlorenz/wasm2js", 12 | "dependencies": { 13 | "minimist": "~1.2.0" 14 | }, 15 | "keywords": [ 16 | "WebAssembly", 17 | "wast", 18 | "wat", 19 | "wasm" 20 | ], 21 | "author": { 22 | "name": "Thorsten Lorenz", 23 | "email": "thlorenz@gmx.de", 24 | "url": "http://thlorenz.com" 25 | }, 26 | "license": { 27 | "type": "MIT", 28 | "url": "https://github.com/thlorenz/wasm2js/blob/master/LICENSE" 29 | }, 30 | "engine": { 31 | "node": ">=4" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /wasm2js.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * Takes a `.wasm` binary and wraps it inside a commonJS module that can be required 5 | * in Node.js and the browser. 6 | * 7 | * @name wasm2js 8 | * 9 | * @param {Buffer} wasmBuf a buffer of the .wasm code 10 | * @returns {String} the commonJS module code that wraps the wasm 11 | */ 12 | module.exports = function wasm2js(wasmBuf) { 13 | const wasm = wasmBuf.toString('base64') 14 | 15 | return ` 16 | module.exports = loadWebAssembly 17 | 18 | loadWebAssembly.supported = typeof WebAssembly !== 'undefined' 19 | var PAGE_SIZE = 65536 20 | function loadWebAssembly (opts) { 21 | if (!loadWebAssembly.supported) return null 22 | 23 | var imp = opts && opts.imports 24 | var wasm = toUint8Array('${wasm}') 25 | var ready = null 26 | 27 | var mod = { 28 | buffer: wasm, 29 | memory: null, 30 | exports: null, 31 | realloc: realloc, 32 | onload: onload 33 | } 34 | 35 | onload(function () {}) 36 | 37 | return mod 38 | 39 | function realloc (size) { 40 | if (size <= mod.memory.byteLength) return 41 | mod.exports.memory.grow(Math.ceil(Math.max(0, (size - mod.memory.byteLength) / PAGE_SIZE))) 42 | mod.memory = new Uint8Array(mod.exports.memory.buffer) 43 | } 44 | 45 | function onload (cb) { 46 | if (mod.exports) return cb() 47 | 48 | if (ready) { 49 | ready.then(cb.bind(null, null)).catch(cb) 50 | return 51 | } 52 | 53 | try { 54 | if (opts && opts.async) throw new Error('async') 55 | setup({instance: new WebAssembly.Instance(new WebAssembly.Module(wasm), imp)}) 56 | } catch (err) { 57 | ready = WebAssembly.instantiate(wasm, imp).then(setup) 58 | } 59 | 60 | onload(cb) 61 | } 62 | 63 | function setup (w) { 64 | mod.exports = w.instance.exports 65 | mod.memory = mod.exports.memory && mod.exports.memory.buffer && new Uint8Array(mod.exports.memory.buffer) 66 | } 67 | } 68 | 69 | function toUint8Array (s) { 70 | if (typeof atob === 'function') return new Uint8Array(atob(s).split('').map(charCodeAt)) 71 | return (require('buf' + 'fer').Buffer).from(s, 'base64') 72 | } 73 | 74 | function charCodeAt (c) { 75 | return c.charCodeAt(0) 76 | } 77 | `.replace(/^ {4}/gm, '') 78 | } 79 | --------------------------------------------------------------------------------