Skip to content

easywasm/wasi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

66 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

easywasi

A working, zero-dependency implementation of WASI preview1, with lots of filesystem options. It will work in places other than a browser, but that is the primary target. It's easy, light, simple, effortless to modify/extend, and should work with any WASI-enabled wasm and any modern js runtime.

If you need framebuffer/audio/input WASI devices, check out web-zen-dev.

install

Install into your bundled project with npm i @easywasm/wasi. You can also use it on the web, directly from cdn:

<script type="module">
  import WasiPreview1 from 'https://esm.sh/@easywasm/wasi'
</script>

And I like to use sourcemaps:

<script type="importmap">
  {
    "imports": {
      "@easywasm/wasi": "https://esm.sh/@easywasm/wasi",
      "fflatefs": "https://easywasm.github.io/wasi/fflatefs.js",
      "fflate": "https://esm.sh/fflate/esm/browser.js"
    }
  }
</script>
<script type="module">
  import { WasiPreview1 } from '@easywasm/wasi'
</script>

usage

You can use it without a filesystem, like this:

import WasiPreview1 from '@easywasm/wasi'

const wasi_snapshot_preview1 = new WasiPreview1()

const {
  instance: { exports }
} = await WebAssembly.instantiateStreaming(fetch('example.wasm'), {
  wasi_snapshot_preview1
  // your imports here
})

wasi_snapshot_preview1.start(exports)

To really unlock it's power, though, give it an fs instance.

I used to use zenfs, but it seems broken every time I try, now. I think they intend that you use packaging and stuff, but I just want to import functional things from the web/cdn. In my opinion it's non-functional.

Now, i use a much simpler approach:

import WasiPreview1 from 'https://esm.sh/@easywasm/wasi'
import fflatefs from 'fflatefs'

const fs = await fflatefs('fs.zip')
const wasi_snapshot_preview1 = new WasiPreview1({ fs })

const {
  instance: { exports }
} = await WebAssembly.instantiateStreaming(fetch('example.wasm'), {
  wasi_snapshot_preview1
  // your imports here
})

wasi_snapshot_preview1.start(exports)

This implements the bare-min statSync/readFileSync. If you want more functionality, implement more, but that is all you really need to read files.

Have a look in example to see how I fit it all together.

Keep in mind, you can easily override every function yourself, too, like if you want to implement the socket-API, which is the only thing I left out:

import { defs, WasiPreview1 } from '@easywasm/wasi'

class WasiPreview1WithSockets extends WasiPreview1 {
  constructor(options = {}) {
    super(options)
    // do something with options to setup socket
  }

  // obviously implement these however
  sock_accept(fd, flags) {
    return defs.ERRNO_NOSYS
  }
  sock_recv(fd, riData, riFlags) {
    return defs.ERRNO_NOSYS
  }
  sock_send(fd, siData, riFlags) {
    return defs.ERRNO_NOSYS
  }
  sock_shutdown(fd, how) {
    return defs.ERRNO_NOSYS
  }
}

// usage
const wasi_snapshot_preview1 = new WasiPreview1WithSockets({ fs })

const {
  instance: { exports }
} = await WebAssembly.instantiateStreaming(fetch('example.wasm'), {
  wasi_snapshot_preview1
})
wasi_snapshot_preview1.start(exports)

Have a look at WasiPreview1 to figure out how to implement it, if you want things to work differently.

inspiration

  • this article has some nice initial ideas
  • this article has some good WASI imeplentations
  • browser-wasi-shim has a very nice interface, and this is basically the same in JS, but using more extensible filesystem, and I improved a few little things.

About

A working, zero-dependency implementation of WASI preview1, with lots of filesystem options.

Resources

License

Stars

Watchers

Forks

Packages

No packages published