vite打包第三方wasm项目,生产报错的问题

前言

现有的项目中使用了第三方wasm项目。本地开发的时候没问题,但是打包后在生产出现了问题

前置文章

问题定位

原因是打包后获取不到import_meta.url,导致new URL报错

解决方案

直接修改第三方包的源码(不推荐)

这段代码是在第三方包中的。像我使用的wasm-xlsxwriter。

位置在node_modules/wasm-xlsxwriter/web/wasm_xlsxwriter.js

if (typeof module_or_path === 'undefined') {
        module_or_path = new URL('wasm_xlsxwriter_bg.wasm', import.meta.url);
    }

改为

if (typeof module_or_path === 'undefined') {
        module_or_path = new URL('wasm_xlsxwriter_bg.wasm', window.location.origin);
    }

这样打包的时候就会修改为相对路径

但是这样肯定是不行的,以后不好维护

写一个rollup插件处理

我的项目是基于vben构建的,所以这里的文件夹都是基于vben来的。你们使用的时候根据自己的项目情况修改就行

取消wasm文件名称处理

找到vite中关于rollup的配置

我的配置文件路径:shop_web_admin\internal\vite-config\src\config\application.ts

找到viteConfig->build->rollupOptions->output->assetFileNames

目前的配置:

assetFileNames: '[ext]/[name]-[hash].[ext]',

修改为:

assetFileNames: (assetInfo) => {
    return assetInfo.names[0]?.includes('.wasm')
    	? '[ext]/[name].[ext]'
        : '[ext]/[name]-[hash].[ext]';
},

这样打包后的wasm文件就没有hash了,方便后续处理

写一个处理插件

我的插件目录:shop_web_admin\internal\vite-config\src\plugins

在该目录下新增插件:

const MagicString = require('magic-string');

export default function ParseWasmUrl() {
  return {
    name: 'parse-wasm-url',
    transform: {
      handler(code: string, id: string) {
        const matches = [
          ...code.matchAll(
            /new URL\((?:'|")([^'"]+)(?:'|"),\s*import\.meta\.url\)(\.href)?/g,
          ),
        ];

        if (matches.length > 0) {
          const s = new MagicString(code);

          for (const match of matches) {
            const start = match.index;
            const [str] = match;
			// 这里因为我的项目只使用了一个wasm组件,所以直接写死了
            if (id.includes('wasm_xlsxwriter')) {
              s.overwrite(
                start,
                start + str.length,
                `new URL('/wasm/wasm_xlsxwriter_bg.wasm',window.location.origin)`,
              );
            }
          }

          return {
            code: s.toString(),
            map: s.generateMap({ source: id }),
          };
        } else {
          return null;
        }
      },
      order: 'post',
    },
  };
}

使用插件:

import parseWasmUrl from './parse-wasm-url';

/**
 * 根据条件获取通用的vite插件
 */
async function loadCommonPlugins(
  options: CommonPluginOptions,
): Promise<ConditionPlugin[]> {
  const { devtools, injectMetadata, isBuild, visualizer } = options;
  return [
    {
      condition: true,
      plugins: () => [
        topLevelAwait(),
        viteVue({
          script: {
            defineModel: true,
            // propsDestructure: true,
          },
        }),
        viteVueJsx(),
        wasm(),
        parseWasmUrl(),
      ],
    },
  ];
}

这样基本就没问题了,我们build一下

可以看到存在wasm文件夹

第三方的wasm文件已经打包好了

我们继续看打包后的源码

可以看到,已经修改成功。我们在页面上尝试一下:

已经成功获取

我们试一下功能

成功解决

参考:

https://www.rollupjs.com/plugin-development/#transform

https://www.rollupjs.com/configuration-options/#output-assetfilenames

https://juejin.cn/post/7146143545433260045

https://github.com/Menci/vite-plugin-wasm


vite打包第三方wasm项目,生产报错的问题
https://xuyuanhang.com/archives/viteda-bao-di-san-fang-wasmxiang-mu-sheng-chan-bao-cuo-de-wen-ti
作者
许远航
发布于
2025年08月21日
许可协议