wasmerio / wasmer-js

Monorepo for Javascript WebAssembly packages by Wasmer

Home Page:https://wasmerio.github.io/wasmer-js/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to use in browsers?

michaelfranzl opened this issue · comments

The README of v1.0.2 states that browsers are supported. However, neither the README nor the example directory contain usage examples for the browser. Using the best guess in the browser,

import { init, WASI } from '@wasmer/wasi';
await init()

gives the following error:

Library.esm.min.js:25 Uncaught (in promise) ReferenceError: Buffer is not defined
    at Z (Library.esm.min.js:25:15897)

This comes from

const buffer = Buffer.from(data, encoding) as MimeBuffer;
Indeed there is no Buffer global in browsers.

How to use @wasmer/wasi in the browser? If Buffer is supposed to be polyfilled, could you add this to the README and refer to a library which fulfills the required API? Thanks.

I was probably about to encounter the same problem. I'd like to use this library in the browser as well.

Hi! Currently the Wasmer-JS libraries rely on a bundler for browser integration. Webpack and Rollup work well. Notice #290 and the comments below about defining wasmer_wasi_js_bg.wasm as external; it is actually not needed as its content is inlined in Library.esm.min.js (as a data URL).

@corwin-of-amber When you say that it "relies on a bundler", do you mean that a bundler has to be configured to polyfill Buffer? Like from rollup-plugin-polyfill-node or @esbuild-plugins/node-modules-polyfill?

In contrast, in v0.12.0, Buffer was included in wasmer-js/wasi (imported from buffer-es6 and injected as a dependency): https://github.com/wasmerio/wasmer-js/blob/v0.12.0/packages/wasi/src/index.ts#L11

Yes, exactly. I am pasting the contents of webpack.config.js from a hello-world project that I did to learn how to use it; if you find it useful then perhaps I can make a PR to add it to the WasmerJS docs.

const path = require('path');
const webpack = require('webpack');

module.exports = {
    name: 'hello',
    entry: './hello.js',
    mode: 'development',
    target: 'webworker',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'hello.js'
    },
    module: {
        rules: [
            {
                test: /\.wasm$/,
                type: 'asset/resource'
            }
        ]
    },
    externals: {
        'wasmer_wasi_js_bg.wasm': true
    },
    resolve: {
        fallback: {buffer: require.resolve('buffer/')}
    },
    plugins: [new webpack.ProvidePlugin({
        process: 'process/browser.js',
        Buffer: ['buffer', 'Buffer']
    })]
}

It is true that previous versions were bundled with Buffer. IMO this is now old-style; having your dependencies bundled hinders inter-operability esp. if types from the bundled package are part of the API. It makes passing the "right" objects quite tricky. Forcing the user to provide their own polyfills is certainly more cumbersome and goes against the OOP encapsulation concepts, but pragmatically is much more flexible.

I'd also like to use the library on the browser, also note that in parcel doesn't work out of the box sadly

Here is an esbuild configuration I am using successfully in the browser:
https://github.com/guregu/trealla-js/blob/9dfaf8b886033ea339cd36d005b2555091c56efa/make.cjs#L17-L19

The important bit:

const stdLibBrowser = require('node-stdlib-browser');

(async () => {
	await esbuild.build({
		entryPoints: ['index.js'],
// ...
		inject: [require.resolve('node-stdlib-browser/helpers/esbuild/shim')],
		define: {
			Buffer: 'Buffer'
		},
		plugins: [plugin(stdLibBrowser)]

After polyfilling buffer I'm getting
Uncaught (in promise) Error: Failed to instantiate WASI: RuntimeError: JsValue(TypeError: import object field 'env' is not an Object

EDIT: After compiling in all the functions that weren't in wasi-libc ... would be nice if you could provide env through JS too in case you want to implement the functions there, now I get this:

Error while running start function: RuntimeError: JsValue(Object({"ptr":1122200}))

Works in wasmtime though :/

EDIT2: prob this issue wasmerio/wasmer#2568 the app calls exit()
It's dumb but this workaround works

var exitCode = 1;
try { exitCode = wasi.start(); } catch (e) {}
commented

One thing I hate so far is everything i can find requires node Wich indirectly uses node. One of the cool things about wasm(if i not mistaken) looks like wasm should not need a bundler or anything other than a web browser ;i am reading wasm are binary(all though it could be text). I would like to use wapm without node i am surprised they have no instructions un using it with unpkg or skypack and no install IMHO it should need wasmer.