我正在做一个NextJS项目,它通过npm利用了一个wasm包;这是duckdb-wasm
duckdb-wasm
需要从一组bundle中初始化(例如基于浏览器的能力)。这可以通过jsdeliver完成,也可以通过在代码中指定bundle来完成(参见:https://www.npmjs.com/package/@duckdb/duckdb-wasm#Instantiation)。
jsdeliver在部署时遇到了CORS问题,因此我试图获得第二个选项(即通过手动规范的webpack)与NextJS一起工作。不幸的是,这似乎遇到了问题:TypeError: url.replace is not a function
.
下面是_app。TSX参考:
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;
和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);
解决这个问题的一种方法是将bundle的定义带入useEffect
,但由于许多原因,这是不可取的,例如,子组件的呈现需要阻塞bundle的值。
我没有使用过duckdb,但通常你应该能够修改webpack配置以包含wasm文件。
查看Webpack 5中的asyncWebAssembly
实验属性。
在next.config.js
中使用它的一个例子:
module.exports = {
webpack: (config) => {
const experiments = config.experiments || {}
config.experiments = { ...experiments, asyncWebAssembly: true }
config.output.assetModuleFilename = 'static/[hash][ext]'
config.output.publicPath = '/_next/'
config.module.rules.push({
test: /.wasm/,
type: 'asset/resource'
})
return config
}
}
除此之外,您可能还需要一个异步导入来导入模块:
async function loadDependencies() {
const duckdb_wasm = await import('@duckdb/duckdb-wasm/dist/duckdb-mvp.wasm')
}