I'm working on a NextJS project that leverages a wasm package via npm; specifically this is duckdb-wasm.
duckdb-wasm needs to initialize from a set of bundles (e.g. based on browser capability). this can be done with JSDelivr or by specifying the bundles in your code (see here: https://www.npmjs.com/package/@duckdb/duckdb-wasm#Instantiation).
JSDelivr runs into a CORS issue when deployed and so I'm trying to get the second option (i.e. webpack via manual specification) working with NextJS. Unfortunately, this seems to run into problems: TypeError: url.replace is not a function.
Here's the _app.tsx for reference:
import "../styles/globals.css";
import * as duckdb from "@duckdb/duckdb-wasm";
import duckdb_wasm_coi from "@duckdb/duckdb-wasm/dist/duckdb-coi.wasm";
import duckdb_wasm_eh from "@duckdb/duckdb-wasm/dist/duckdb-eh.wasm";
import duckdb_wasm from "@duckdb/duckdb-wasm/dist/duckdb-mvp.wasm";
import {
  DuckDBConnectionProvider,
  DuckDBPlatform,
  DuckDBProvider,
} from "@duckdb/react-duckdb";
import type { AppProps } from "next/app";
let manualBundles: duckdb.DuckDBBundles;
const logger = new duckdb.ConsoleLogger(duckdb.LogLevel.WARNING);
manualBundles = {
  mvp: {
    mainModule: duckdb_wasm,
    mainWorker: new URL(
      "@duckdb/duckdb-wasm/dist/duckdb-browser-mvp.worker.js",
      import.meta.url
    ).toString(),
  },
  eh: {
    mainModule: duckdb_wasm_eh,
    mainWorker: new URL(
      "@duckdb/duckdb-wasm/dist/duckdb-browser-eh.worker.js",
      import.meta.url
    ).toString(),
  },
  coi: {
    mainModule: duckdb_wasm_coi,
    mainWorker: new URL(
      "@duckdb/duckdb-wasm/dist/duckdb-browser-coi.worker.js",
      import.meta.url
    ).toString(),
    pthreadWorker: new URL(
      "@duckdb/duckdb-wasm/dist/duckdb-browser-coi.pthread.worker.js",
      import.meta.url
    ).toString(),
  },
};
function App({ Component, pageProps }: AppProps) {
  return (
    <DuckDBPlatform logger={logger} bundles={manualBundles}>
      <DuckDBProvider>
        <DuckDBConnectionProvider>
          <Component {...pageProps} />
        </DuckDBConnectionProvider>
      </DuckDBProvider>
    </DuckDBPlatform>
  );
}
export default App;
And the nextjs.config.js:
const withTM = require("next-transpile-modules")(["@duckdb/react-duckdb"]);
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  //swcMinify: true,
  webpack: (config, options) => {
    config.output.webassemblyModuleFilename = "static/wasm/[modulehash].wasm";
    config.module.rules.push({
      test: /.*\.wasm$/,
      type: "asset/resource",
      generator: {
        filename: "static/wasm/[name].[contenthash][ext]",
      },
    });
    config.experiments = {
      asyncWebAssembly: true,
      ...config.experiments,
    };
    return config;
  },
};
module.exports = withTM(nextConfig);
One way to work around this is to bring the definition of the bundles into a useEffect but this isn't desirable for a number of reasons, for example the rendering of the child components needs to block on the value of bundles.