0

Problem

When I try to run the following code I get an error that I haven't been able to fix.

// assets/js/app.js
41 ...
42 import * as automerge from "@automerge/automerge"
43 const doc = automerge.init()
44 ...

The error in the browser (Chrome) reads as follows.

Uncaught TypeError: (void 0) is not a function
    at Object.create2 [as create] (automerge_wasm_bg.js:220:14)
    at init (stable.js:55:31)
    at app.js:43:23

create2 @ automerge_wasm_bg.js:220
init @ stable.js:55
(anonymous) @ app.js:43

When I inspect automerge_wasm_bg.js:220 it shows the error in the following function.

206 export function create(text_v2, actor) {
207     try {
208         const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
209        var ptr0 = isLikeNone(actor) ? 0 : passStringToWasm0(actor, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
210        var len0 = WASM_VECTOR_LEN;
211        wasm.create(retptr, text_v2, ptr0, len0);
212        var r0 = getInt32Memory0()[retptr / 4 + 0];
213        var r1 = getInt32Memory0()[retptr / 4 + 1];
214        var r2 = getInt32Memory0()[retptr / 4 + 2];
215        if (r2) {
216            throw takeObject(r1);
217        }
218        return Automerge.__wrap(r0);
219    } finally {
220        wasm.__wbindgen_add_to_stack_pointer(16);
221    }
222 }

There are a lot of different Uncaught TypeError: (void 0) is not a function posts on StackOverflow and other websites, but I have not found a satisfactory explanation of why, and thus under what circumstances, (void 0) might give this error.

Tried so far

  • Update Node
  • Set specific Esbuild targets in build.js
  • Use other Esbuild plugins for importing wasm files
  • Update node packages
  • Reinstall node modules and package-lock.json
  • Double check Esbuild configuration for using Phoenix with plugins (explained at https://hexdocs.pm/phoenix/asset_management.html#esbuild-plugins)
  • Fresh Phoenix project with fresh Esbuild configuration
  • Use other browsers

Environment

  • MacOS 13.1
  • Chrome Version 110.0.5481.77
  • Phoenix 1.7
  • Phoenix LiveView 0.18
  • Node 18.14

Package.json

// package.json
{
  "name": "name",
  "version": "1.0.0",
  "description": "",
  "main": "js/app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "esbuild": "^0.16.17"
  },
  "dependencies": {
    "@automerge/automerge": "^2.0.1",
    "phoenix": "file:../deps/phoenix",
    "phoenix_html": "file:../deps/phoenix_html",
    "phoenix_live_view": "file:../deps/phoenix_live_view"
  }
}

build.js for Esbuild

const esbuild = require('esbuild')
const path = require('node:path')
const fs = require('node:fs')

// source for wasmPlugin:
// https://esbuild.github.io/plugins/#webassembly-plugin
let wasmPlugin = {
  name: 'wasm',
  setup(build) {
    build.onResolve({ filter: /\.wasm$/ }, args => {
      if (args.namespace === 'wasm-stub') {
        return {
          path: args.path,
          namespace: 'wasm-binary',
        }
      }
      if (args.resolveDir === '') {
        return // Ignore unresolvable paths
      }
      return {
        path: path.isAbsolute(args.path) ? args.path : path.join(args.resolveDir, args.path),
        namespace: 'wasm-stub',
      }
    })

    build.onLoad({ filter: /.*/, namespace: 'wasm-stub' }, async (args) => ({
      contents: `import wasm from ${JSON.stringify(args.path)}
        export default (imports) =>
          WebAssembly.instantiate(wasm, imports).then(
            result => result.instance.exports)`,
    }))

    build.onLoad({ filter: /.*/, namespace: 'wasm-binary' }, async (args) => ({
      contents: await fs.promises.readFile(args.path),
      loader: 'binary',
    }))
  },
}

const args = process.argv.slice(2)
const watch = args.includes('--watch')
const deploy = args.includes('--deploy')

let opts = {
  entryPoints: ['js/app.js'],
  bundle: true,
  target: 'es2017',
  outdir: '../priv/static/assets',
  logLevel: 'info',
  format: 'esm',
  plugins: [wasmPlugin]
}

if (watch) {
  opts = {
    ...opts,
    watch,
    sourcemap: 'inline'
  }
}

if (deploy) {
  opts = {
    ...opts,
    minify: true
  }
}

const promise = esbuild.build(opts)

if (watch) {
  promise.then(_result => {
    process.stdin.on('close', () => {
      process.exit(0)
    })

    process.stdin.resume()
  })
}

  • I have not solved the issue yet, but I am looking into other wasm loader plugins for Esbuild, because the current one is not working properly. – Coen Bakker Feb 14 '23 at 12:45

0 Answers0