hucre 是一个零依赖的 TypeScript 电子表格引擎,支持读写多种电子表格格式。
核心特点:
✅ 零依赖:没有任何第三方依赖
✅ 多格式支持:XLSX、CSV、ODS、JSON、NDJSON、XML
✅ 旧格式支持:支持读取 XLS(Excel 97-2003)和 XLSB(二进制格式)
✅ 纯 TypeScript:原生 TypeScript 编写,类型安全
✅ Tree Shaking:按需导入,减小打包体积
✅ 流式处理:支持大文件的流式读写
✅ 跨平台:Node.js、Deno、Bun、浏览器、Edge Runtime
✅ 安全:不使用 eval,符合 CSP 要求
快速开始
安装
Bash npm install hucre |
基本读写
TypeScript import { readXlsx, writeXlsx } from "hucre" // 读取 XLSX 文件 const workbook = await readXlsx(buffer) console.log(workbook.sheets[0].rows) // 写入 XLSX 文件 const xlsx = await writeXlsx({ sheets: [ { name: "Products", columns: [ { header: "Name", key: "name", width: 25 }, { header: "Price", key: "price", width: 12, numFmt: "$#,##0.00" }, { header: "Stock", key: "stock", width: 10 }, ], data: [ { name: "Widget", price: 9.99, stock: 142 }, { name: "Gadget", price: 24.5, stock: 87 }, ], }, ], }) |
Tree Shaking:按需导入
只导入你需要的模块:
TypeScript // 只使用 XLSX import { readXlsx, writeXlsx } from "hucre/xlsx" // 只使用 CSV(仅 ~2 KB gzipped) import { parseCsv, writeCsv } from "hucre/csv" // 只使用 ODS import { readOds, writeOds } from "hucre/ods" // 只使用 JSON / NDJSON import { parseJson, writeNdjson } from "hucre/json" // 只使用 XML import { readXml, writeXml } from "hucre/xml" |
包体积对比:
导入内容 | Gzipped 体积 |
CSV 读写 | ~3.7 KB |
XLSX 读取 | ~34 KB |
XLSX 读写 | ~68 KB |
完整库 | ~129 KB |
核心功能详解
1. 读取功能
支持多种数据类型:
TypeScript import { readXlsx } from "hucre/xlsx" const wb = await readXlsx(uint8Array, { sheets: [0, "Products"], // 按索引或名称过滤工作表 readStyles: true, // 解析单元格样式 dateSystem: "auto", // 自动检测日期系统(1900/1904) }) for (const sheet of wb.sheets) { console.log(sheet.name) // 工作表名称 console.log(sheet.rows) // CellValue[][] console.log(sheet.merges) // MergeRange[] } |
2. 写入功能
基本写入
TypeScript import { writeXlsx } from "hucre/xlsx" const buffer = await writeXlsx({ sheets: [ { name: "Report", columns: [ { header: "Date", key: "date", width: 15, numFmt: "yyyy-mm-dd" }, { header: "Revenue", key: "revenue", width: 15, numFmt: "$#,##0.00" }, { header: "Active", key: "active", width: 10 }, ], data: [ { date: new Date("2026-01-15"), revenue: 12500, active: true }, { date: new Date("2026-01-16"), revenue: 8900, active: false }, ], freezePane: { rows: 1 }, autoFilter: { range: "A1:C3" }, }, ], defaultFont: { name: "Calibri", size: 11 }, }) |
单元格级样式
TypeScript await writeXlsx({ sheets: [ { name: "Report", rows: [ [{ value: "Region", style: { font: { bold: true } } }, "Revenue"], ["EU", { value: 12500, style: { numFmt: "$#,##0.00" } }], ["Total", { formula: "SUM(B2:B2)" }], ], }, ], }) |
3. 自动列宽
根据内容自动计算最优列宽:
TypeScript const buffer = await writeXlsx({ sheets: [ { name: "Products", columns: [ { header: "Name", key: "name", autoWidth: true }, { header: "Price", key: "price", autoWidth: true, numFmt: "$#,##0.00" }, { header: "SKU", key: "sku", autoWidth: true }, ], data: products, }, ], }) |
4. 数据验证
TypeScript const buffer = await writeXlsx({ sheets: [ { name: "Sheet1", rows: [ ["Status", "Quantity"], ["active", 10], ], dataValidations: [ { type: "list", values: ["active", "inactive", "draft"], range: "A2:A100", showErrorMessage: true, errorTitle: "Invalid", errorMessage: "Pick from the list", }, { type: "whole", operator: "between", formula1: "0", formula2: "1000", range: "B2:B100", }, ], }, ], }) |
5. 超链接
TypeScript import { writeXlsx, link } from "hucre/xlsx" await writeXlsx({ sheets: [ { name: "Summary", columns: [ { header: "Link", key: "link" }, { header: "ID", key: "id" }, ], data: [ { link: link("Open", "https://example.com/items/abc-123"), id: "abc-123" }, { link: { text: "Open", hyperlink: "https://example.com/items/def-456" }, id: "def-456" }, ], }, ], }) |
6. 流式处理:处理大文件
hucre 提供了完整的流式 API,可以处理超大文件而不占用过多内存。
流式读取
TypeScript import { streamXlsxRows } from "hucre/xlsx" // 逐行读取,不一次性加载整个文件 for await (const row of streamXlsxRows(buffer)) { console.log(row.index, row.values) } // 从网络流读取 const res = await fetch("https://example.com/huge.xlsx") for await (const row of streamXlsxRows(res.body!)) { console.log(row.index, row.values) } // 限制读取行数(预览/采样) for await (const row of streamXlsxRows(buffer, { maxRows: 100 })) { console.log(row.index, row.values) } // 读取指定范围 for await (const row of streamXlsxRows(buffer, { range: "B2:D1000" })) { console.log(row.values) // 只包含 B/C/D 列 } |
流式写入
TypeScript import { writeXlsxStream } from "hucre/xlsx" // 生成器函数提供数据源 function* rows() { for (let i = 0; i < 5_000_000; i++) yield [i + 1, Math.random()] } // 流式写入,内存占用恒定 return new Response( writeXlsxStream( rows(), { name: "BigData", columns: [{ header: "ID" }, { header: "Value" }], freezePane: { rows: 1 }, }, ), { headers: { "content-type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", }, }, ) |
性能对比
行数 | writeXlsxStream 内存 | XlsxStreamWriter 内存 |
300,000 | 41 MB | 328 MB |
1,000,000 | 67 MB | 1,037 MB |
3,000,000 | 70 MB | 不可行 |
7. 密码保护
支持读写加密的 XLSX 文件(ECMA-376 Agile 加密):
TypeScript import { writeXlsx, readXlsx, EncryptedFileError, DecryptionError } from "hucre" // 写入加密文件 const encrypted = await writeXlsx({ sheets: [{ name: "Secret", rows: [["pin", 1234]] }], encryption: { password: "hunter2" }, }) // 读取加密文件 const wb = await readXlsx(encrypted, { password: "hunter2" }) // 错误处理 try { await readXlsx(encrypted) } catch (e) { if (e instanceof EncryptedFileError) console.log("需要密码") } |
XLSB(二进制 Excel)
读取 .xlsb 文件,比 .xlsx 更小更快:
TypeScript import { readXlsb } from "hucre" const wb = await readXlsb(bytes) |
XLS(Excel 97-2003)
读取传统的 .xls 文件:
TypeScript import { readXls } from "hucre" const wb = await readXls(bytes) |
注意:旧格式仅支持读取,支持单元格值和合并单元格。
9. 往返保留(Round-trip Preservation)
打开、修改、保存文件,而不丢失图表、宏等 hucre 不原生处理的功能:
TypeScript import { openXlsx, saveXlsx } from "hucre/xlsx" const workbook = await openXlsx(buffer) workbook.sheets[0].rows[0][0] = "Updated!" const output = await saveXlsx(workbook) // 图表、VBA、主题都被保留 |
重要区别:
readXlsx / writeXlsx:创作路径,从模型重建工作簿
openXlsx / saveXlsx:编辑路径,保留 hucre 不建模的部分
10. 高级功能
数据透视表
TypeScript import { writeXlsx } from "hucre" const xlsx = await writeXlsx({ sheets: [ { name: "Data", rows: [ ["Region", "Product", "Revenue"], ["EU", "A", 100], ["EU", "B", 50], ["US", "A", 200], ["US", "B", 75], ], }, { name: "Pivot", pivotTables: [ { name: "SalesPivot", sourceSheet: "Data", rows: ["Region"], columns: ["Product"], values: [{ field: "Revenue", function: "sum" }], }, ], }, ], }) |
图表
TypeScript import { addChart, writeXlsx } from "hucre" const dashboard = { name: "Dashboard", rows: [ ["Quarter", "Revenue", "Forecast"], ["Q1", 12000, 11500], ["Q2", 15500, 15000], ["Q3", 14000, 14500], ["Q4", 17800, 17200], ], } addChart(dashboard, { type: "column", title: "Quarterly Revenue", series: [ { name: "Revenue", values: "B2:B5", categories: "A2:A5", color: "1F77B4" }, { name: "Forecast", values: "C2:C5", categories: "A2:A5", color: "FF7F0E" }, ], axes: { x: { title: "Quarter" }, y: { title: "Revenue (USD)", numberFormat: { formatCode: "$#,##0" } }, }, legend: "bottom", dataLabels: { showValue: true, position: "outEnd" }, }) await writeXlsx({ sheets: [dashboard] }) |
与其他库对比
vs JavaScript/TypeScript 库
特性 | hucre | SheetJS CE | ExcelJS | xlsx-js-style |
依赖数量 | 0 | 0* | 9 | 0* |
包体积(gzip) | 4-129 KB† | ~300 KB | ~500 KB | ~300 KB |
原生 ESM | ✅ | 部分 | ❌(CJS) | 部分 |
TypeScript | 原生 | 后加 | 后加 | 后加 |
Edge Runtime | ✅ | ❌ | ❌ | ❌ |
CSP 兼容 | ✅ | ✅ | ❌(eval) | ✅ |
npm 发布 | ✅ | ❌(仅 CDN) | 停滞 | ✅ |
读写支持 | ✅ | ✅(付费版 $) | ✅ | ✅ |
样式 | ✅ | ❌(付费版 $) | ✅ | ✅ |
条件格式 | 13 种 | ❌(付费版 $) | ✅ | ❌ |
流式读写 | ✅ | 仅 CSV | ✅ | 仅 CSV |
ODS 支持 | ✅§ | ✅ | ❌ | ✅ |
往返保留 | ✅ | 部分 | 部分 | 部分 |
迷你图 | ✅ | ❌ | ❌ | ❌ |
* SheetJS 已从 npm 下架,必须从 CDN 安装 † 取决于导入内容,完全可 Tree Shake § ODS 支持值、公式、合并和六种样式属性
vs 其他语言库
特性 | hucre (TS) | openpyxl (Py) | XlsxWriter (Py) | rust_xlsxwriter | Apache POI (Java) |
读取 XLSX | ✅ | ✅ | ❌ | ❌ | ✅ |
写入 XLSX | ✅ | ✅ | ✅ | ✅ | ✅ |
流式处理 | 读写 | 读写 | const_memory | const_memory | SXSSF(写) |
图表 | 往返保留 | 15+ 种 | 9 种 | 12+ 种 | 有限 |
数据透视表 | 读写(骨架) | 只读 | ❌ | ❌ | 有限 |
条件格式 | 13 种 | ✅ | ✅ | ✅ | ✅ |
迷你图 | ✅ | ✅ | ✅ | ✅ | ❌ |
公式计算 | ❌ | ❌ | ❌ | ❌ | ✅ |
多格式 | XLSX/ODS/CSV | 仅 XLSX | 仅 XLSX | 仅 XLSX | XLS/XLSX |
零依赖 | ✅ | lxml 可选 | ❌ | ✅ | ❌ |