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()
})
}