这是一个关于前端 Excel 导出库
sheetex
的故事:我为什么要做这个库,它为什么会这么小,以及你是否值得一试
如过你问我"为什么非要在前端导出",那将是另一个故事。
我的数据导出史
不知道你是否还记得自己是从什么时候开始接触数据导出的?
我对自己的"数据导出史"还算有些印象:在还没有正式工作的时候,如果有人问我要数据,我会在数据库管理工具里写个查询语句,然后视对方的用途,导出成SQL 语句、CSV 文件或者Excel 等;待到工作了,需要开发面向最终用户的系统,就不能再这么手工处理,导出功能成为系统标配,用户点击一个按钮,就要下载到相应的文件。
最早是 CSV 格式,因为其生成相对容易,而且也可以通过 Excel 软件进行查看,加上主要是内部用户,偶有无法打开也只要简单培训就能解决。
但随着用户类型变得广泛起来,这种"偶尔"也逐渐变成无法忍受,那么干脆直接导出 Excel 文件吧,反正开源库也已经成熟,于是使用 SheetJS
(xlsx.js
) 导出 xlsx 文件成了我第二阶段的选项。
但是既然你都能导出 Excel 文件了,为什么不能加上边框,把标题合并居中呢?
经过这一切,我已经清楚,CSV是一个不错的数据交换格式,但给最终用户使用还是存在些许门槛,加上一些基本样式的Excel 才是给用户导出数据的终极答案。
然而真正的问题也出现了,SheetJS
只在商业版中提供样式支持,而我们已经上了 SheetJS
的船。此时成本最低的解决方案,就是使用类似 xlsx-style
这样的在 SheetJS
基础上增加样式支持的库。而代价就是这些库内置的 xlsx(SheetJS)
版本总是落后于官方版本,尽管官方版本修复的 bug 以及提供的新功能我们不一定用得上,但内心总是能感觉到用了一个充满漏洞的落后版本,而 npm 安装时的各种安全警告和 deprecated 信息又在反复提醒你这一点。更可怕的是,即使你愿意花更多时间换 exceljs
之类独立于 SheetJS
的库,其累积的 issue 也非常多,你无路可逃。
一个人能做成 Excel 导出库吗?
我们使用了 xlsx-style
,项目的具体问题解决了。但我心中已经萌生一个想法,要做一个类似的东西,但是没有安全漏洞和依赖过期的警告。
这并不是一件容易的事,从 SheetJS
和 exceljs
的文件体积、接口文档、以及 github 上的 issue 都能看出来,这个体量的库都是合众人之力,而非靠一己之力做出来的,甚至仅仅是想在上面打个补丁,修复个问题,动手前需要先了解的源代码就非常多了。
本身 Excel 经过这么多年的发展,其功能已经非常强大,完整的文件格式必然极度复杂。我们也都见过许多不同的 Excel 软件,比如 Microsoft Excel、WPS Office、LibreOffice、钉钉在线编辑等,他们相互之间就存在兼容性问题。
相信大家都听过类似的说法:约 90% 的用户只使用了其中约 10% 的功能。
这句话也是对 Excel 复杂性的总结,但此时正是我寻找的答案,既然大型的库研发成本高昂,维护压力巨大,为什么不反过来,就做这 10% 呢,这样也足以服务 90% 的用户。
好在我要做的是导出,不会有兼容性压力,我只要确保我实现的那 10% 符合标准,让其他软件能够正确读取。以设置颜色为例,可以通过 rgb、theme、indexed 三种方式实现,但我只要挑选 rgb 这种最简单且覆盖最广的方式去实现,我的软件并不需要理解 theme 和 indexed 。
上面那个说法还有下半句:但是每个人使用的那10% 并不相同。
因此必须对这"10%"有一个更明确的定义。我无法就此发起一个调查,最终只能结合历史项目和平常直接操作 Excel 的经验,把需求框定在下面几项:
- 单元格中数字和文本的写入,这是最基本的;
- "设置单元格格式"面板中的所有样式(数字、对齐、字体、边框、填充)
- 行高、列宽、合并单元格。
好,最终问题成了"一个人能做成一个正确写入数据、支持所有单元格样式、并能设置行高、列宽、合并单元格的 Excel 导出库吗?"
答案是:sheetex !

上图是一个真实项目中的案例,包含了合并单元格(横行和纵向)、字体、字号、颜色、加粗、背景色、对齐、行高、列宽等效果。
为什么要这么小?
正如前文所述,为了确保 sheetex 能被完成并得到长期维护,我在功能上做了取舍,只实现最必要的功能。做了这些,它的体积自然会变小。但最终能做到 12KB(gzip),并不是顺其自然就能产生结果,其中包含了刻意的努力。
为什么要这么小呢,还是回到我的数据导出史。
当我第一次把导出 CSV改成导出 Excel 的时候,第一反应就是"这个库好大,幸好是用在管理后台,如果放到手机上就惨了,只是为了换个后缀值得吗"。
当我再次从 SheetJS
换成 xlsx-style
的时候,为防止历史功能遇到兼容性问题,部分历史遗留的导出功能仍然在使用 SheetJS
,而新功能使用了 xlsx-style
,结果就成了这样。

虽然关键性项目最终都改成了只使用其中一个库,但一些受冷落的项目,从此就背上了两块大石头,直到它们死去。
所以,无论是刚刚经历从导出 CSV 转变成导出 Excel 的开发者,还是最终因为部分需求满足不了,而不得不引入一个其他库的开发者,我都希望 sheetex 可以帮助他们避免我所遭遇的问题。无论是升级、还是废弃,付出的代价都是极小的。
正是从这个目的出发,sheetex 的接口也设计的非常简单,没有一堆 API 需要学习,你想要什么样式,就参考相应的例子,组织好数据和样式来创建实例,然后就可以导出想要的文件。
到底是如何做到的?
讲完了原因,再讲讲是如何做到的。
简单来说,就是避免依赖,必要的情况下,慎重选择依赖。这个库只有两个依赖 mustache
和 fflate
。
Excel 文件内部,其实是几个按照规范命名并放置在特定目录结构下的 XML
文件,我刻意避免了 xml 库,而是选择了用 mustache
通过模版渲染的方式来生成这些文件,简单又直观。借助 mustache
的转义功能,加上代码中对属性的校验,还可以避免特殊符号导致的文件格式错乱并抵御通过数据内容和样式属性发起的恶意攻击。
Excel 文件本质上是改了后缀名的 zip 压缩包,所以 zip 库也少不了,fflate
非常好的满足了我的需求,可以方便的组织文件结构、同时支持浏览器和 Node.JS 环境、压缩效率高、本身还很小。
两个库加起来才占用了大约 7K 的体积,相当不错。
它适合你吗?
这是一个简单、轻量的 Excel 导出库,支持了最常用的样式,可以快速入门作为 CSV 的替代,也可以在很多场合顶替更重量的 SheetJS
和 exceljs
。
我的建议是,如果 sheetex 能够覆盖你目前的需求,请给它一个机会。
不知道亲爱的读者是否愿意一试?如果你有什么顾虑,也请告诉我,也许就是下个版本升级的动力。