When I run pnpm build
, I get this error:
▲ Next.js 14.1.0
Creating an optimized production build ...
✓ Compiled successfully
✓ Linting and checking validity of types
✓ Collecting page data
Generating static pages (0/4) [ ]Error: ENOENT: no such file or directory, open '.next/server/app/automerge_wasm_bg.wasm'
at Object.openSync (node:fs:581:18)
at Object.readFileSync (node:fs:457:35)
at 9961 (.next/server/app/page.js:2:281)
at t (.next/server/webpack-runtime.js:1:142)
at 6959 (.next/server/app/page.js:1:16097)
at t (.next/server/webpack-runtime.js:1:142)
at F (node_modules/.pnpm/next@14.1.0_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:12:94693)
at node_modules/.pnpm/next@14.1.0_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:12:97108
at W._fromJSON (node_modules/.pnpm/next@14.1.0_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:12:97546)
at JSON.parse (<anonymous>) {
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: '.next/server/app/automerge_wasm_bg.wasm'
}
The build error is coming from these lines in
@automerge/automerge-wasm/nodejs/automerge_wasm.cjs:1993-1994
, which is generated by wbindgen
.
const path = require('path').join(__dirname, 'automerge_wasm_bg.wasm')
const bytes = require('fs').readFileSync(path)
It's looking for the wasm file at .next/server/app/automerge_wasm_bg.wasm
, but it looks like that
file is actually available at .next/static/wasm/2960c0a2c6b8ef3d.wasm
.
I've tried all the solutions proposed in this issue vercel/next.js#29362, but they don't seem to be applicable to this situation.
I was able to get past the ENOENT error using copy-webpack-plugin
to put the file where it expected it...
// next.config.mjs
import { join } from 'path'
import { access, symlink } from 'fs/promises'
import CopyPlugin from 'copy-webpack-plugin'
export default {
webpack(config, { isServer, dev }) {
config.experiments = {
asyncWebAssembly: true,
layers: true,
}
config.plugins.push(
new CopyPlugin({
patterns: [{ from: './static/wasm', to: './server/app/automerge_wasm_bg.wasm' }],
})
)
return config
},
}
... but that just got me to a new and different error,
Import #0 module="./automerge_wasm_bg.js": module is not an object or function
at 9961 (/Users/herbcaudill/Code/HerbCaudill/next-automerge-wasm/.next/server/app/page.js:2:327)
...
which makes me think that the file not found error is a red herring, especially in light of the following:
When I run pnpm dev
, I get this error:
### Unhandled Runtime Error
Error: Element type is invalid: expected a string (for built-in components) or a class/function
(for composite components) but got: object. You likely forgot to export your component from the
file it's defined in, or you might have mixed up default and named imports.
Check the render method of `StaticGenerationSearchParamsBailoutProvider`.
Call Stack
createFiberFromTypeAndProps
node_modules/.pnpm/next@14.1.0_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (27799:16)
...
I came across this comment suggests that this is intended behavior:
I don't think this is a bug. WebAssembly instantiation is supposed to be async. In a client component, you would probably want a dynamic import and React.lazy/suspense.
Following the proposed code, I was able to get this apalling monstrosity to run:
'use client'
import { useEffect, useState } from 'react'
export default function PageComponent() {
const [message, setMessage] = useState<string | undefined>(undefined)
useEffect(() => {
import('@automerge/automerge').then(({ next: A }) => {
const foo = A.from({ message: 'Hello, world!' })
setMessage(foo.message)
})
}, [])
return <p>{message ?? 'Loading...'}</p>
}