{"id":19430195,"url":"https://github.com/etherdream/mini-program-pack","last_synced_at":"2025-08-25T12:09:00.438Z","repository":{"id":218181537,"uuid":"745789154","full_name":"EtherDream/mini-program-pack","owner":"EtherDream","description":"小程序静态资源打包和压缩","archived":false,"fork":false,"pushed_at":"2024-02-01T06:49:50.000Z","size":25,"stargazers_count":10,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-11-09T02:07:46.059Z","etag":null,"topics":["assets-management","brotli","compression","mini-program"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/EtherDream.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2024-01-20T06:22:26.000Z","updated_at":"2024-09-21T03:00:45.000Z","dependencies_parsed_at":"2024-01-29T10:11:56.841Z","dependency_job_id":null,"html_url":"https://github.com/EtherDream/mini-program-pack","commit_stats":null,"previous_names":["etherdream/mini-pack","etherdream/mini-program-pack"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EtherDream%2Fmini-program-pack","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EtherDream%2Fmini-program-pack/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EtherDream%2Fmini-program-pack/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EtherDream%2Fmini-program-pack/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EtherDream","download_url":"https://codeload.github.com/EtherDream/mini-program-pack/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223963109,"owners_count":17232604,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["assets-management","brotli","compression","mini-program"],"created_at":"2024-11-10T14:23:55.126Z","updated_at":"2024-11-10T14:23:55.699Z","avatar_url":"https://github.com/EtherDream.png","language":"JavaScript","readme":"# 小程序静态资源打包方案\n\n## 解决问题\n\n小程序/小游戏由于受到包体积限制，因此一些体积较大的本地资源可考虑以压缩的格式进行存储，尤其是压缩率高、解压快的 brotli 格式。\n\n微信小程序现已提供原生解压 brotli 压缩文件的能力，但其他小程序目前不支持该 API，因此需要一个兼容方案。\n\n此外，开发者有时希望将多个文件打包成一个资源包，方便使用并能提升压缩率，因此需要记录额外的文件信息。\n\n本工具主要解决上述问题。\n\n## 兼容方案\n\n目前大部分小程序都支持加载 brotli 压缩后的 wasm 文件，因此开发者可将静态资源打包成一个只有数据段的 wasm 文件，并进行压缩；运行时直接加载 `.wasm.br` 文件，即可从导出对象的内存中读取原始数据。\n\n## 文件打包\n\n安装 [mini-program-pack](pack) 工具：\n\n```bash\nnpm i -g mini-program-pack\n```\n\n演示：\n\n```bash\necho \"Hello\" \u003e t1.txt\necho \"abc123\" \u003e t2.txt\n\nmini-program-pack --binary t1.txt t2.txt -o res.wasm.br\n```\n\n将 `t1.txt` 和 `t2.txt` 以二进制格式打包压缩，生成 `res.wasm.br`。\n\n该 wasm 文件不包含任何指令，仅用作数据载体而已。\n\n## 文件读取\n\n小程序项目中安装 [mini-program-unpack](unpack) 库：\n\n```bash\nnpm i mini-program-unpack\n```\n\n运行：\n\n```javascript\nimport unpack from 'mini-program-unpack'\n\nunpack('res.wasm.br').then(pkg =\u003e {\n  console.log(pkg.files)          // [\"t1.txt\", \"t2.txt\"]\n  console.log(pkg.read('t1.txt')) // Uint8Array(6) [72, 101, 108, 108, 111, 10]\n  console.log(pkg.read('t2.txt')) // Uint8Array(7) [97, 98, 99, 49, 50, 51, 10]\n})\n```\n\n解压过程是后台异步执行的，不会阻塞主线程。\n\n在支持原生 brotli 解压的环境中，程序不会调用 wasm 接口，而是直接解压 .wasm.br 文件，然后跳过 wasm 文件头，因此可快 10% 左右。\n\n## 文本优化\n\n由于小程序不支持 `TextDecoder` 等二进制转文本的 API，因此开发者只能自己实现 UTF-8 解码，这不仅需要额外的代码，而且性能很低。\n\n为此本工具提供了文本模式，可大幅提升文本读取性能。打包时通过 `--text` 指定使用文本模式的文件：\n\n```bash\necho \"Hello\" \u003e t1.txt\necho \"abc123\" \u003e t2.txt\necho \"你好😁\" \u003e t3.txt\n\nmini-program-pack --binary t1.txt --text t2.txt t3.txt -o res.wasm.br\n```\n\n读取文本文件，返回的是 `string` 类型：\n\n```javascript\nunpack('res.wasm.br').then(pkg =\u003e {\n  console.log(pkg.files)          // [\"t1.txt\", \"t2.txt\", \"t3.txt\"]\n  console.log(pkg.read('t1.txt')) // Uint8Array(6) [72, 101, 108, 108, 111, 10]\n  console.log(pkg.read('t2.txt')) // \"abc123\\n\"\n  console.log(pkg.read('t3.txt')) // \"你好😁\\n\"\n})\n```\n\n对于单字节文本，例如 `ASCII`、`ISO-8859-1` 格式，使用文本模式不会降低压缩率。\n\n对于多字节文本，例如含有汉字的内容，使用文本模式通常会损失 10%-20% 的压缩率，具体取决于汉字数量，汉字越多损失越少。\n\n原因是单字节文本的字符以 u8[] 存储，而多字节文本的字符以 u16[] 存储，由于每个字符都占用 2 字节，导致体积膨胀，尽管压缩可去除冗余，但相比二进制模式仍有损失。\n\n之所以直接存储字码，是因为读取时可通过 `String.fromCharCode.apply` 批量解码，相比逐字处理可以快几十倍。\n\n\u003cdetails\u003e\n\u003csummary\u003e性能测试：批量解码 vs 逐字处理\u003c/summary\u003e\n\n```javascript\nconst testData = new Uint16Array(1024 * 1024 * 8)\nfor (let i = 0; i \u003c testData.length; i++) {\n  testData[i] = i\n}\nconst chr = String.fromCharCode\nlet strApply = ''\nlet strLoop = ''\n\nconst t0 = Date.now()\n\nfor (let i = 0; i \u003c testData.length; i += 32768) {\n  const part = testData.subarray(i, i + 32768)\n  strApply += chr.apply(0, part)\n}\nconst t1 = Date.now()\n\nfor (let i = 0; i \u003c testData.length; i++) {\n  strLoop += chr(testData[i])\n}\nconst t2 = Date.now()\n\nconsole.log('apply time:', t1 - t0)\nconsole.log('loop time:', t2 - t1)\nconsole.log(strLoop === strApply)\n```\n\u003c/details\u003e\n\nhttps://jsbin.com/mofapad/edit?html,console\n\n## 兼容性\n\n* 微信小程序 v2.14.0\n\n  https://developers.weixin.qq.com/miniprogram/dev/framework/performance/wasm.html\n\n  微信小程序 v2.21.1 支持原生 br 解压\n\n  https://developers.weixin.qq.com/miniprogram/dev/api/file/FileSystemManager.readCompressedFile.html\n\n  由于 Worker 环境访问不到 wx 对象，因此无法原生 br 解压。但能访问 WXWebAssembly 对象（v2.15.0），仍可使用 .wasm.br 方案。\n\n* 抖音小程序 v2.92.0.0\n\n  https://developer.open-douyin.com/docs/resource/zh-CN/mini-app/develop/guide/experience-optimization/list/wasm\n\n* 支付宝小程序\n\n  https://opendocs.alipay.com/mini/0b2bz8\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fetherdream%2Fmini-program-pack","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fetherdream%2Fmini-program-pack","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fetherdream%2Fmini-program-pack/lists"}