You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Next.js中导入Wasm?已配置asyncWebAssembly仍报错

在Next.js中导入WebAssembly模块的解决方案

问题背景

相同的WebAssembly导入逻辑在纯React项目中可正常运行,但迁移到Next.js后出现webpack解析错误,即便已在next.config.js中开启experiments.asyncWebAssembly配置,问题依然存在。

报错信息如下:

./public/js/gameplay.wasm
Module parse failed: Unexpected character '' (1:0)
The module seem to be a WebAssembly module, but module is not flagged as WebAssembly module for webpack.
BREAKING CHANGE: Since webpack 5 WebAssembly is not enabled by default and flagged as experimental feature.
You need to enable one of the WebAssembly experiments via 'experiments.asyncWebAssembly: true' (based on async modules) or 'experiments.syncWebAssembly: true' (like webpack 4, deprecated).
For files that transpile to WebAssembly, make sure to set the module type in the 'module.rules' section of the config (e. g. 'type: "webassembly/async"').
(Source code omitted for this binary file)


解决方案

方案1:调整webpack配置+动态导入

Next.js的webpack默认不会自动识别.wasm文件,需手动添加解析规则,同时确保Wasm加载逻辑仅在客户端执行(避免服务端渲染报错)。

  1. 修改next.config.js:
/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: (config) => {
    config.experiments = {
      asyncWebAssembly: true,
      layers: true,
    };
    // 添加Wasm文件解析规则
    config.module.rules.push({
      test: /\.wasm$/,
      type: 'webassembly/async',
    });
    return config;
  },
};

module.exports = nextConfig;
  1. 页面中使用动态导入:
    将Wasm文件放在src目录下(而非public),在客户端useEffect中异步加载:
import { useEffect, useState } from 'react';

export default function Home() {
  const [greetMsg, setGreetMsg] = useState<string | null>(null);

  useEffect(() => {
    const loadWasm = async () => {
      try {
        // 替换为你的Wasm文件实际路径
        const wasmModule = await import('../path/to/gameplay.wasm');
        setGreetMsg(wasmModule.greet());
      } catch (err) {
        console.error('Wasm加载失败:', err);
      }
    };
    loadWasm();
  }, []);

  return (
    <div>
      <h1>Next.js + Wasm</h1>
      {greetMsg && <p>{greetMsg}</p>}
    </div>
  );
}

方案2:通过Fetch加载public目录中的Wasm

如果Wasm文件必须放在public目录下,可直接通过Fetch获取资源并实例化,绕开webpack的解析流程:

import { useEffect, useState } from 'react';

export default function Home() {
  const [greetMsg, setGreetMsg] = useState<string | null>(null);

  useEffect(() => {
    const loadWasm = async () => {
      try {
        const response = await fetch('/js/gameplay.wasm');
        const bytes = await response.arrayBuffer();
        const { instance } = await WebAssembly.instantiate(bytes);
        // 根据你的Wasm实际导出函数调整
        setGreetMsg((instance.exports.greet as Function)());
      } catch (err) {
        console.error('Wasm加载失败:', err);
      }
    };
    loadWasm();
  }, []);

  return (
    <div>
      <h1>Next.js + Wasm</h1>
      {greetMsg && <p>{greetMsg}</p>}
    </div>
  );
}

方案3:使用wasm-bindgen生成绑定(推荐)

若你的Wasm由Rust编译,建议使用wasm-bindgen生成JS绑定文件,简化导入流程:

  1. 确保Rust编译时生成了绑定文件(通常在pkg目录下)
  2. 页面中导入绑定文件:
import { useEffect, useState } from 'react';

export default function Home() {
  const [greetMsg, setGreetMsg] = useState<string | null>(null);

  useEffect(() => {
    const loadWasm = async () => {
      const wasm = await import('../rust-wasm/pkg/rust_wasm');
      setGreetMsg(wasm.greet());
    };
    loadWasm();
  }, []);

  return <div>{greetMsg}</div>;
}

此方案同样需要在next.config.js中开启asyncWebAssembly配置。


核心原因

Next.js存在服务端渲染(SSR)环境,Wasm模块仅能在浏览器客户端运行,因此必须将加载逻辑限制在客户端执行。同时,Next.js默认webpack配置未包含.wasm文件的解析规则,需手动添加或改用Fetch绕开webpack处理。

内容的提问来源于stack exchange,提问作者Justin Zhang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 19:27:31