全网都找不到!小程序集成第三方 WASM npm 包
(金石瓜分计划上线,速戳上图了解详情)前言这又是一次被小程序折磨的故事!距我上一次被小程序折磨还是在上一次(去年9月做微信头像加国旗小程序的时候)。但这是我第二次做小程序,就让我再次遇到这么个大难题,就是在小程序中用 WASM,准确来讲是集成一个第三方 npm 包@jsquash/jpeg,而这个依赖包是一个基于 WebAssembly ,支持浏览器端运行的第三方 JPEG 编解码库。
业务&背景这次我开发的小程序是一个图像压缩工具——图像压缩暗房,它不仅能够完成图像压缩,还能够缩小图像尺寸、进行格式转换。当然,这其中最重要的一点是所有功能完完全全的本地运行。因为没钱买服务器,也才如此困难重重,有钱还是放服务端运行吧。
如果有服务器,可以搭建 NodeJS 环境用shrap,而如果要在浏览器环境实现则需要自己找其它的第三方依赖了,比如@jsquash/jpeg,它是jSquash中的一个包,而jSquash则是基于谷歌的Squoosh开源项目而来。因此我的小程序初期就直接尝试用@jsquash/jpeg来实现功能了。但从一开始就是重重磨难。所遇到的问题搜遍全网无一案例。
第一难:引入@jquash/jpeg首先来安装@jsquash/jpeg
npm install @jsquash/jpeg
之后在小程序中构建npm,到这里没有任何问题。
接着根据官方文档的示例引入@jquash/jpeg
importdecode, { initasinitJpegDecode }from'@jsquash/jpeg/decode';
importencode, { initasinitJpegEncode }from'@jsquash/jpeg/encode';
这时就报错了:模块没有被定义?这看得我很奇怪,根据这个信息,必然是微信在构建 npm 的时候出了差错(当然这是我排查了半天后得出的结论)。
好,来对比一下node_modules中的源码和miniprogram_npm,发现是因为encode.js、decode.js都没有被编译。(实际这一看就只有2个文件躺在miniprogram_npm里,匪夷所思)
在编译后的index.js最底部有注释,即这些文件被认为外部依赖,所以没被编译。
而为什么没有被编译,后面会提到。
//miniprogram-npm-outsideDeps=["./codec/enc/mozjpeg_enc.js","./codec/dec/mozjpeg_dec.js"]
//# sourceMappingURL=index.js.map
此时需要手动将源码中的相关的文件和整个codec复制到miniprogram_npm。
在@jsquash/jpeg中 REAMDE 也有提到:
?Note: You will need to either manually include the wasm files from the codec directory or use a bundler like WebPack or Rollup to include them in your app/server.
?第二难:禁用import.meta接着前面,清除小程序缓存并重新编译,依然报错,这次的错误是不能在模块外使用import.meta。
这个错误在miniprogram_npm/@jsquash/jpeg/codec/enc/mozjpeg_enc.js
实际上这就是codec中的 JS 文件没被构建编译的原因。在小程序中不能使用的东西,就直接不给编译了(悄悄地啥都不说,让你自己找)。
看一下源码中import.meta.url的作用,其实就是动态确定脚本文件路径。
直接把文件中所有的import.meta.url修改为实际值:
// var _scriptDir = import.meta.url;
var_scriptDir ='/miniprogram_npm/@jsquash/jpeg/codec/enc/mozjpeg_enc.js';
用不到的就注释:
/*if(import.meta.url===undefined){import.meta.url="https://localhost"}*/
下面这里没有改成/miniprogram_npm/@jsquash/jpeg/codec/enc/mozjpeg_enc.wasm,而是把.wasm文件另外放到项目根目录wasm中。这是因为小程序限制禁止访问miniprogram_npm,后面会遇到。
// wasmBinaryFile=new URL("mozjpeg_enc.wasm",import.meta.url).href
wasmBinaryFile="/wasm/mozjpeg_enc.wasm"
之后,miniprogram_npm/@jsquash/jpeg/codec/dec/mozjpeg_dec.js也一样修改。
第三难:禁用WebAssembly接着就需要初始化@jsquash/jpeg,也就是加载 WASM。
initJpegEncode('/miniprogram_npm/@jsquash/jpeg/codec/enc/mozjpeg_enc.wasm')
这时遇到了WebAssembly没有被定义的报错。
定位一下报错的代码位置,在initEmscriptenModule方法中:
exportfunctioninitEmscriptenModule(moduleFactory, wasmModule, moduleOptionOverrides = {}){
letinstantiateWasm;
if(wasmModule) {
instantiateWasm =(imports, callback) ={
constinstance =newWebAssembly.Instance(wasmModule, imports);
callback(instance);
returninstance.exports;
}
returnmoduleFactory({
// Just to be safe, don't automatically invoke any wasm functions
noInitialRun:true,
instantiateWasm,
...moduleOptionOverrides,
}
经过排查,这是由于微信小程序自己定义了一个WXWebAssembly(这也要干预?虽然不明白但感觉手脚不是很干净,改了参数但是其他啥也没讲,连个例子都没有)。
首先,这里的重点是WXWebAssembly.instantiate的path指向一个代码包内路径的.wasm文件。也就是前面提到的.wasm文件要单独放到项目根目录wasm中。放在miniprogram_npm是没用的,因为小程序限制禁止访问。
↓你敢尝试就敢给你报错
修改一下初始化方法中的代码,用微信的WXWebAssembly.instantiate。
exportfunctioninitEmscriptenModule(moduleFactory, wasmModule, moduleOptionOverrides = {}){
letinstantiateWasm;
if(wasmModule) {
instantiateWasm =async(imports, callback) = {
constresult =awaitWXWebAssembly.instantiate(wasmModule, imports);
constinstance = result.instance;
callback(instance);
returninstance.exports;
}
returnmoduleFactory({
// Just to be safe, don't automatically invoke any wasm functions
noInitialRun:true,
instantiateWasm,
...moduleOptionOverrides,
}
当然,这还不够。因为胶水文件mozjpeg_enc.js中还有很多原生使用WebAssembly对象的地方。我这里直接取巧全局替换了。
varWebAssembly = WXWebAssembly;
// var _scriptDir = import.meta.url;
var_scriptDir ='/miniprogram_npm/@jsquash/jpeg/codec/enc/mozjpeg_enc.js';
最后,我们的初始化入口方法参数直接传.wasm文件的代码包内路径。
initJpegEncode('/wasm/mozjpeg_enc.wasm')
后续突破三重难关,总算是能够使用@jquash/jpeg了。然而实际用下来发现,@jquash/jpeg的图片压缩效率实在是太低了,竟然要几十秒,这与我预想中的相差太远了,也是用户所不能容忍的。我本以为是哪里的参数设置不对,但是在谷歌官方的Squoosh应用中发现也是如此。因此我直接改用Canvas实现jpeg图片的处理了,而其他的gif、png格式处理则使用另外的wasm脚本,后面有机会再另讲一篇。
续集:《不是?全网都找不到案例?小程序集成 gifsicle wasm》
https://juejin.cn/post/7492417173630533671
小程序展示最后展示一下我这个“图像压缩暗房”小程序,设计都是我自己。
AI编程资讯AI Coding专区指南:
https://aicoding.juejin.cn/aicoding
点击"阅读原文"了解详情~
阅读原文
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。 项目经理在线