yeow-fflate
v0.3.2
Published
fflate fork for Yeow: ZIP container/CRC kept in JS, raw DEFLATE and UTF-8 pluggable (default yeow-api Java bridge); promise-first API, Zip builder, no workers and no streams
Maintainers
Readme
yeow-fflate
fflate 的用于 Yeow 环境的 fork:保留 fflate 原生纯 JS 的容器逻辑(ZIP 结构拼装、CRC、内置 UTF-8),并把 raw DEFLATE 与 UTF-8 编解码抽象成可插拔的 codec 后端,默认桥接到 yeow-api(环境自带 DEFLATE / 编码器执行)。
设计原则
| 原则 | 实现 |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------- |
| 单一职责 | core.ts(原生算法/容器)· backends.ts(codec 配置)· async.ts(Promise-first 异步层)· index.ts(唯一公共入口) |
| Promise-first | 异步 API 直接 await;回调形态仅作 fflate 兼容 |
| 不泄露内部 | 公共入口只导出公开 API;b2/wzh/mrg 等内部工具不再出现在包导出里 |
| 保留 fflate 核心 | ZIP 格式、CRC32、ADLER32、纯 JS UTF-8 算法不重写,只换边界 |
架构
src/core.ts fflate 原生同步核心(deflate/inflate/gzip/zlib/zip/unzip、
CRC、ZIP 拼装、内置 UTF-8)+ 底层 codec 注册原语
src/backends.ts CodecConfig + configureCodecs / useYeowCodecs / useNativeCodecs
src/async.ts Promise-first 异步 API + Zip 增量构建器 + ZipReader(list/stat/单文件读取)
src/index.ts 公共入口:显式导出 + 默认启用 Yeow 后端安装
npm install yeow-fflate环境应有 yeow-api(peer dependency)。
快速开始
import { zipSync, unzipSync, gzipSync, gunzipSync, strToU8, strFromU8 } from 'yeow-fflate';
import { fs } from 'yeow-api';
// 同步 ZIP(内部 deflate 默认走 Yeow Gzip 桥接,输出为标准 deflate 流)
const zip = zipSync({ 'a.txt': strToU8('hello yeow') }, { level: 6 });
await fs.writeFile('archive.zip', zip); // Uint8Array 直接写入
const loaded = await fs.readFile('archive.zip'); // 默认返回 Uint8Array
const files = unzipSync(loaded);
console.log(strFromU8(files['a.txt'])); // hello yeow
// 同步 gzip(可被标准 gunzip 解压)
const gz = gzipSync(strToU8('hello'));
await fs.writeFile('hello.gz', gz);
const back = gunzipSync(await fs.readFile('hello.gz'));Promise-first 异步 API
import { zip, unzip, gzip, gunzip, decompress, strToU8 } from 'yeow-fflate';
import { fs } from 'yeow-api';
const buf = await zip({ 'a.txt': strToU8('hello yeow') }, { level: 6 });
await fs.writeFile('archive.zip', buf);
const files = await unzip(await fs.readFile('archive.zip'));
const gz = await gzip(buf);
await fs.writeFile('archive.zip.gz', gz);
const out = await gunzip(await fs.readFile('archive.zip.gz'));
const out2 = await decompress(gz); // 自动识别 gzip/zlib/raw deflatefflate 回调形态仍兼容:gzip(data, opts, cb) / gzip(data, cb)。
注意:回调模式返回 void——本库没有 Worker,不存在可终止的底层任务,
因此移除了 fflate 的 AsyncTerminable。
增量构建:Zip(异步压缩 + 同步装配)
import { Zip, unzipSync, strToU8, strFromU8 } from 'yeow-fflate';
import { fs } from 'yeow-api';
const zip = new Zip();
await zip.add('a.txt', strToU8('hello')); // Promise<void>,异步压缩(默认 level 6)
await zip.add('dir/b.bin', bytes, { level: 0 }); // level 0 = 不压缩存储
await zip.add('压缩/大文件.txt', big, { level: 9 }); // 中文文件名、子目录
await fs.writeFile('bundle.zip', zip.finish()); // 同步装配;与 zipSync 输出一致
const out = unzipSync(await fs.readFile('bundle.zip'));
console.log(strFromU8(out['a.txt'])); // hello
// 需要同步压缩时使用 addSync:
const sync = new Zip();
sync.addSync('a.txt', strToU8('hello'));
await fs.writeFile('bundle-sync.zip', sync.finish());add() 默认走注入的异步压缩器(Yeow 后端下在 Java 侧 ioExecutor 执行);
未注入异步压缩器时回退同步实现,但返回值始终是 Promise。
调用下一个 add / addSync / finish 前请先 await:finish() 在仍有
未完成 add 时会直接抛错,防止产出缺条目的损坏 ZIP。
单文件读取 / 列表 / stat:ZipReader
import { ZipReader } from 'yeow-fflate';
import { fs } from 'yeow-api';
const reader = new ZipReader(await fs.readFile('bundle.zip')); // 只解析中央目录,不解压文件
const entries = reader.list(); // ZipEntry[]:name/compression/size/originalSize/crc/mtime/attrs
const st = reader.stat('dir/b.bin'); // 单条目元数据;不存在返回 null
reader.has('a.txt'); // true
const file = await reader.read('dir/b.bin'); // 只解压目标文件 → Uint8Array
const text = await reader.read('a.txt', 'utf8'); // → string
const b64 = reader.readSync('a.txt', 'base64'); // 同步读取 → Base64 字符串
reader.readSync('missing.txt'); // null
// 读取原始压缩数据(不解压):DEFLATE 条目返回 raw deflate 流
const raw = reader.readRawSync('a.txt'); // Uint8Array | null
const raw2 = await reader.readRaw('dir/b.bin'); // 仅切片,不做解压list() / stat() 是同步操作(元数据来自中央目录,无解压开销);read /
readSync 只解压指定条目,编码语义与 fs.readFile 一致(默认
Uint8Array,显式 'utf8' / 'base64' 返回字符串);readRaw /
readRawSync 直接返回条目的原始压缩字节(DEFLATE 条目为 raw deflate 流,存储条目为原始文件字节),不做任何解压。
Codec 后端
包加载时默认执行 useYeowCodecs():DEFLATE 与 UTF-8 全部走 yeow-api 的环境实现。
import { configureCodecs, useYeowCodecs, useNativeCodecs } from 'yeow-fflate';
useNativeCodecs(); // 切回 fflate 原生纯 JS(压缩 + UTF-8 全部内置)
useYeowCodecs(); // 切回 Yeow 桥接(默认)
// 自定义/部分配置:省略的字段回退原生实现
configureCodecs({
deflate: (data, opts) => myDeflateRaw(data, { level: opts.level ?? 6 }),
inflate: (data) => myInflateRaw(data),
deflateAsync: (data, opts) => myAsyncDeflateRaw(data, opts), // Promise<Uint8Array>
inflateAsync: (data) => myAsyncInflateRaw(data),
encodeUTF8: (str) => myUtf8Encode(str),
decodeUTF8: (bytes) => myUtf8Decode(bytes),
});
configureCodecs(null); // 等价 useNativeCodecs():清除全部注入约定:注入的 deflate/inflate 处理 raw DEFLATE 流(无 gzip/zlib 包装);
gzip/zlib 头尾、ZIP 容器与 CRC 始终由本库拼装。dictionary 选项只被原生
实现支持——带 dictionary 的调用会自动回退原生路径。latin1 快速路径始终走内置实现。
与 fflate 的差异
- 无 Worker、无流式 API:移除了 worker 机制与全部流式类(
Deflate/Inflate/Gzip/Zip/Unzip/DecodeUTF8/Async*等)。 - 异步 API 为 Promise-first:
await zip(...);回调形态保留但返回void(无AsyncTerminable)。 Zip为增量构建器:await zip.add(...)异步压缩 +addSync(...)同步压缩 +finish()同步装配;原 fflate 流式Zip已移除。- Codec 后端统一配置:
configureCodecs()取代setDeflater/setInflater/...六个散落注入点(0.2.0 起这些 setter 不再对外导出)。 - 公共导出收敛:只导出 API 与类型,
err/b2/b4/wzh/...等内部工具不再泄露。 - UTF-8 内置:
strToU8/strFromU8使用内置纯 JS 实现(默认经后端用运行时全局TextEncoder/TextDecoder——utf-8、同步,小载荷 JS 直转、超阈值走 util 通道,性能最好)。大规模非阻塞编解码可用 yeow-api 的异步stringToBytes/bytesToString。 - 错误码:桥接产生的错误转为
FlateError,code为90(fflate 内置码为 1-7)。
验证
npm install
npm run verify # 47 项检查:桥接/原生/自定义后端、async/await、回调兼容、
# Zip 异步 add / addSync / finish 守卫、ZipReader list/stat/单文件/readRaw、
# UTF-8(中文/emoji/组合字符)、ZIP/CRC、标准兼容
npm run build # 产出 dist/index.mjs(ESM)+ dist/index.cjs(CJS)+ dist/index.d.tsverify.mjs 通过 --alias:yeow-api=./verify-shim.mjs 在本地用 node:zlib/Buffer 模拟 yeow-api(运行时实际走 Java 侧)。
License
MIT(fork 自 fflate)。
