HTML转pdf的一种实现方案
几经波折,由厦门辗转到了广州。由于换了新工作,繁忙了些,博客也断更了两个月,今天想把最近两个月做的一些工作整理一下。适当是对过去做一些总结,不管是技术也好,生活也好,既是对发生的事的一些思考,也是未来发展的基石。
刚到新岗位的第一项任务便是实现一个前端 html 转 pdf 的功能,背景是这样的:我司是做健康管理相关的业务的,就有体检报告生成的功能,之前的体检报告一直都是由后端用模版引擎去做渲染,然后再使用 IText去做 html 转 pdf 的实现,由于体检报告中有大量的 ECharts 图表,还需先将图表转成图片,再将图片转为 pdf,这样一来,一份四十几页的团检报告,总的生成时间需要十几分钟,还不方便调试(需前端调好 html 样式,再给后端生成 pdf,再去看最终生成效果)。
总结,主要有两个不好的点:
- 生成效率差,需要十几分钟
- 报告样式不好调
由于我之前使用过 puppeteer 做过自动化测试,是知道 puppeteer 具有这个功能的,原理也挺简单,莫过于就是自动化的去实现浏览器自带的打印功能。
看了下 IText 生成 PDF 的原理是将一个 Document 对象输出成 pdf 文件,document 的内容也是使用一个个 API 去生成的,比如,Font,Paragraph 等。 可参考这里 https://blog.csdn.net/wzumath/article/details/8260286
所有 IText 最后生成的 pdf 跟 html 效果容易有偏差,内容复杂的 html 生成效率慢。
相比 IText,puppeteer 则是使用真实的浏览器引擎去渲染 html,最后再讲 html 转换为 pdf 文件。实践结果表示基本就是“所见即所得”。我们也可以使用使用 React 或者其它前端框架快速的制作体检报告的内容。
整体的架构设计:
之所以选用 Next 去做应用的开发,主要是看中了它强大的性能优化,且基于 React 去实现页面输出的话能给我们带来很高的开发效率,因为团队成员主要在使用 React。
这是一份 45 页的团检报告的生成时间:
上图的 log “open page”指使用 puppeteer 完成打开长度为 45 页的体检报告,打开并存为 pdf 大概总的用了 5 秒左右,第一次由于 puppeteer 需要启动,稍微慢了些。
所以,在这个场景下,next 使用 SSR 去渲染一份 45 页的体检报告(大多数页面包含一些图表和一些插图),大概只需要 3 秒,保存为 pdf 文件用了 2 秒左右。
以上的方案,总体上有效的解决了之前团队遇到的问题,也大大的提高了开发效率,下次有空再分享下遇到的一些问题和发现的一些好用 vscode 插件。
出去嗮太阳了,2 月的广州居然可以穿短袖 :)