vite 和 webpack 项目使用wasm-pack 生成的 npm 包

背景

出于某些原因,把数据统计工作放到前端了,表格最多 20 万行,20 多列,需要计算:最大值、最小值、中位数、方差、标准差、总和,进行简单基准测试时发现,10 万个数字进行计算时,大概需要 70ms,20 个指标同时计算就需要 70 * 20 = 1400 ms,再多数据和指标就会继续上升,也就是说极限情况计算理论上可以达到 4 秒以上,不太友好

于是,正好最近在学习 tauri 和 rust,就简单写一个 npm 包,使用 WebAssembly 来运行计算功能,计算代码也不复杂就不展示了,测试下来每个指标 10万数据需要 20 ms 左右,有波动,但基本上稳定在 js 计算的 1/4 时间消耗

但是!写完之后发现,更麻烦的是该怎么在项目中接入这些包,项目比较老,用的还是 webpack4,于是就调查总结了一下,在不同构建工具中使用 wasm

wasm-pack

  • wasm-bindgenrust/js底层互操作库和 cli 工具,实现 rust/js 类型转换,生成绑定代码
  • wasm-pack:基于 wasm-bindgen 的高级构建工具链,集成了 wasm-opt 等优化文件大小的工具,自动化了构建、优化、打包发布到npm的完整流程
sh 复制代码
# 检查版本和安装 wasm-pack
cargo -V
rustup update standable
cargo install wasm-pack
cargo install --list

# 用 wasm-pack 创建项目
# 具体功能代码略过,现在只需要打通流程,使用 demo 自带代码即可
wasm-pack new wasm-tools

# 打包成不同版本包
wasm-pack build --scope huli66 --target bundler
wasm-pack build --scope huli66 --target web

# 发布到 npm,前置条件是 npm login,手动使用 npm publish 也行
wasm-pack publish

--scope huli66 使用自己的 npm 用户名作为域,生成的 pkg 下面的 package.jsonname 也会带上 @huli66 前缀

两种打包 target 的区别

特性 bundler web
构建目标 --target bundler --target web
加载方式 同步/内联 异步/fetch
需要 init() 不需要 需要
需要 MIME 配置 不需要 需要
构建工具支持 需要 不需要

bundler

优点 内联到代码中,不需要配置 MIME,新版本打包工具支持都比较成熟

如果作为工具包使用,体积不大,推荐 bundler 方式,发布到 npm,前端使用一般加个 loader 或者 plugin 比较方便,不一定有权限配置 nginx(卑微)

web

优点 异步加载,如果 wasm 文件体积较大,不会阻塞主线程,放在静态文件目录中,可以开启 gzip 压缩减小加载体积 不需要构建工具支持,如果是老项目使用 webpack3 这种,或者不想找版本合适的 loader plugin 等,可以使用这种方式,只需要在生产环境的 nginx 上配置 MIME 类型(新的 nginx 配置默认支持)

nginx 复制代码
# mime.types,推荐修改,所有后缀为 .wasm 的文件都会自动带上返回头 Content-Type: application/wasm
types {
	application/wasm           wasm;
}

# 或者 default.conf 手动指定某个目录下的文件都带上指定返回头
location /static/wasm {
	add_header Content-Type application/custom;
}

可能遇到的问题:

直接调用 init() 出现报错 webpack4 不支持 import meta,可以在包中找到相关代码,删掉,或者尝试手动引入 .wasm 文件然后进行使用 console 出现乱码

js 复制代码
CompileError: WebAssembly.instantiate(): expected magic word 00 61 73 6d, found 3c 21 64 6f @+0
bash 复制代码
开发环境没有配置 `application/wasm`
vite 中配置
webpack5 配置
webpack4 配置

所有情况

打包工具 --target web --target bundler
vite 配置 MIME vite-plugin-wasm
webpack5 experiments: { asyncWebAssembly: true, syncWebAssembly: true }, experiments: { asyncWebAssembly: true, syncWebAssembly: true },
webpack4 配置 MIME 不推荐,loader 已废弃

可以使用 @huli66/test-wasm-web @huli66/test-wasm-bundler 两个包在自己的项目中尝试一下,代码如下

  • vite项目 使用 web 包需要开发环境和生产环境都配置 MIME,可以考虑把 wasm 文件放在静态服务器上,远程拉取进行 init bundler 包使用
js 复制代码
// vite.config.js
import wasm from 'vite-plugin-wasm';

export default defineConfig({
	plugins: [
		wasm()
	]
})
  • webpack5 项目 最简单,配置之后两种方式都能很简单运行
json 复制代码
{
	"experiments": {
		asyncWebAssembly: true,
		syncWebAssembly: true
	}
}

使用功能

js 复制代码
import {calculate_statistics as calc2} from '@huli66/test-wasm-bundler';
import init, {calculate_statistics} from '@huli66/test-wasm-web'

init().then(() => {
	const numbers = [1, 2, 3, 4, 5];
	const result = calculate_statistics(numbers);
	console.log(result, result.mean, result.median, result.standard_deviation);
});

const res2 = calc2([6, 7, 8, 9, 10]);
  • webpack4 项目 推荐使用 web 包,远程引入
相关推荐
苏西的网络日志1 分钟前
小程序 web-view 内嵌 H5 的会话管理:Token 失效跳转登录的完整方案
前端
小满zs3 分钟前
Next.js精通SEO第一章(引言)
前端·seo·next.js
Joyee6916 分钟前
RN 的新模块系统 Turbo module
前端·react native
阿民_armin7 分钟前
使用 IntersectionObserver + 哨兵元素实现长列表懒加载
前端·javascript·vue.js
电商API&Tina20 分钟前
1688 拍立淘接口(item_search_img)测试与接入实战心得
java·大数据·前端·物联网·oracle·json
不想说话的麋鹿36 分钟前
「性能优化」虚拟列表极致优化实战:从原理到源码,打造丝滑滚动体验
前端·vue.js·面试
ouzz37 分钟前
使用 react-canvas 制作一个 Figma 工具:从画布到编辑器
前端·javascript
万少41 分钟前
AI 智能记账 Skill,基于飞书 CLI + 多维表格构建。
前端
颜酱41 分钟前
语音合成与视觉模型api接入实现
前端·javascript·人工智能
你听得到1143 分钟前
Get 这波之后,我把 Flutter 状态管理重新看了一遍:新项目到底该选谁?
前端·flutter·架构