决定了,做一个纯前端的pptx预览库
大家好,我是前端林叔。
今年我github的vue-office文档预览库star已经达到了3600+,不过这个库没什么技术含量,只不过是站在前人的肩膀上简单封装了下。目前该库包含了word(docx)、excel(xls、xlsx)和pdf的预览,唯独缺少ppt文档的预览,很多朋友都提过,能不能做一个ppt的预览库,我一直也在纠结。
为什么迟迟不做ppt的预览库
说到底,还是收益的问题,我做这件事的收益到底是什么?
一般来说做一个开源库我们会有以下几个收益:
- 证明自己的技术实力,在找工作时增加自己的竞争力(回答面试官经常问的那个问题,怎么证明你的技术深度?)
- 锻炼自己的技术能力,做一个好的开源项目需要一定的技术功底,在实战中提升自己是最快的方式
- 反哺开源社区,用爱发电,提升社区知名度
- 做得好了还可以考虑商业化赚钱
我迟迟没有做这件事就是没有想好我到底要什么,而且今年一直在忙着写掘金小册,也确实没有时间,另外就是在做vue-office库的时候,真切的感觉到,用爱发电是不长久的,如果没有利益驱动,是很难坚持下去的,试问,在如今行情这么不好的情况下,怎么平衡工作和自己的业余爱好,每个周末都去免费解决用户的问题,谁能长久地坚持下去呢?
为什么又决定做了
最近正好小册已经完结了(估计最近就会上线),自己也闲下来了,突然感觉失去了方向,不知道做啥了,整个人都变得迷茫,而且能预期到明年裁员的大刀就要砍到自己头上了,也要为后面的面试做下准备了,毕竟年龄大了,没有拿得出手的技术作品,想必后面也是很难的,把近期想做的事情排了个优先级,觉得这个事情还是比较重要的,于是决定开干!
但对于选择开源还是闭源纠结了很久,开源的话比较容易积累star,但主要还是精神支持,对长期利益来看是好的;不过开源后代码很容易被人拷贝改做他用,将自己辛辛苦苦几个月的成果免费拿走,还是不太甘心(这里忏悔下自己的格局)。我最终决定还是闭源,打赏一定金额(比如50以上)可以索取源码,源码不得用于开源,仅做学习和自己项目使用,后期可以考虑开发企业版,通过license授权。
这么做肯定会被人骂的,不过没办法,免费的事情实在坚持不下去了。当然了,只是不免费开放源码,使用都是免费的,会把最终的库发布到npm。
可行性
对于pptx格式的文件,实际上可以看做一个压缩文件,我们把任意一个pptx文件的后缀改为zip,然后解压,就可以看到pptx文件的内容,大部分都是xml文件,我们可以通过分析这个xml中的内容来获取ppt文档的信息,文档符合Microsoft Open XML(简称OOXML)规范。而对于.ppt格式的文件则无法获取其具体格式,所以本库只支持.pptx格式的文件。
说起来容易,不过由于xml的格式比较晦涩难懂,分析过程还是非常痛苦的,下面是ppt中单个幻灯片的xml,可以体会下其中的复杂度。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<p:sld xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
<p:cSld>
<p:bg>
<p:bgPr>
<a:solidFill>
<a:schemeClr val="accent2">
<a:alpha val="34902"/>
</a:schemeClr>
</a:solidFill>
<a:effectLst/>
</p:bgPr>
</p:bg>
<p:spTree>
<p:nvGrpSpPr>
<p:cNvPr id="1" name=""/>
<p:cNvGrpSpPr/>
<p:nvPr/>
</p:nvGrpSpPr>
<p:grpSpPr>
<a:xfrm>
<a:off x="0" y="0"/>
<a:ext cx="0" cy="0"/>
<a:chOff x="0" y="0"/>
<a:chExt cx="0" cy="0"/>
</a:xfrm>
</p:grpSpPr>
<p:pic>
<p:nvPicPr>
<p:cNvPr id="2" name="图片 1">
<a:extLst>
<a:ext uri="{FF2B5EF4-FFF2-40B4-BE49-F238E27FC236}">
<a16:creationId xmlns:a16="http://schemas.microsoft.com/office/drawing/2014/main"
id="{92992223-295D-7122-C034-29375CD12672}"/>
</a:ext>
</a:extLst>
</p:cNvPr>
<p:cNvPicPr>
<a:picLocks noChangeAspect="1"/>
</p:cNvPicPr>
<p:nvPr/>
</p:nvPicPr>
<p:blipFill>
<a:blip r:embed="rId2"/>
<a:stretch>
<a:fillRect/>
</a:stretch>
</p:blipFill>
<p:spPr>
<a:xfrm>
<a:off x="1270000" y="635000"/>
<a:ext cx="1485900" cy="787400"/>
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst/>
</a:prstGeom>
</p:spPr>
</p:pic>
<p:pic>
<p:nvPicPr>
<p:cNvPr id="5" name="图片 4">
<a:extLst>
<a:ext uri="{FF2B5EF4-FFF2-40B4-BE49-F238E27FC236}">
<a16:creationId xmlns:a16="http://schemas.microsoft.com/office/drawing/2014/main"
id="{D071BB10-9D98-FEF0-768B-8E826152F476}"/>
</a:ext>
</a:extLst>
</p:cNvPr>
<p:cNvPicPr>
<a:picLocks noChangeAspect="1"/>
</p:cNvPicPr>
<p:nvPr/>
</p:nvPicPr>
<p:blipFill rotWithShape="1">
<a:blip r:embed="rId3"/>
<a:srcRect r="46000"/>
<a:stretch/>
</p:blipFill>
<p:spPr>
<a:xfrm>
<a:off x="0" y="0"/>
<a:ext cx="685800" cy="1270000"/>
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst/>
</a:prstGeom>
</p:spPr>
</p:pic>
<p:sp>
<p:nvSpPr>
<p:cNvPr id="3" name="矩形 2">
<a:extLst>
<a:ext uri="{FF2B5EF4-FFF2-40B4-BE49-F238E27FC236}">
<a16:creationId xmlns:a16="http://schemas.microsoft.com/office/drawing/2014/main"
id="{FC6BFD96-7710-5D5C-0E6D-5647BB89F8D0}"/>
</a:ext>
</a:extLst>
</p:cNvPr>
<p:cNvSpPr/>
<p:nvPr/>
</p:nvSpPr>
<p:spPr>
<a:xfrm>
<a:off x="7002462" y="2264229"/>
<a:ext cx="3110366" cy="522514"/>
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst/>
</a:prstGeom>
</p:spPr>
<p:style>
<a:lnRef idx="2">
<a:schemeClr val="accent1">
<a:shade val="15000"/>
</a:schemeClr>
</a:lnRef>
<a:fillRef idx="1">
<a:schemeClr val="accent1"/>
</a:fillRef>
<a:effectRef idx="0">
<a:schemeClr val="accent1"/>
</a:effectRef>
<a:fontRef idx="minor">
<a:schemeClr val="lt1"/>
</a:fontRef>
</p:style>
<p:txBody>
<a:bodyPr rtlCol="0" anchor="ctr"/>
<a:lstStyle/>
<a:p>
<a:pPr algn="ctr"/>
<a:endParaRPr kumimoji="1" lang="zh-CN" altLang="en-US">
<a:ln>
<a:solidFill>
<a:srgbClr val="FF0000"/>
</a:solidFill>
</a:ln>
</a:endParaRPr>
</a:p>
</p:txBody>
</p:sp>
</p:spTree>
<p:extLst>
<p:ext uri="{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}">
<p14:creationId xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="760063892"/>
</p:ext>
</p:extLst>
</p:cSld>
<p:clrMapOvr>
<a:masterClrMapping/>
</p:clrMapOvr>
</p:sld>
怎么做好这个库
就像我在我的掘金小册中说的那样,做前端开发,首先要做的就是设计,必须先编写设计文档,然后再开发,现在我也是这么做的。
第一步:分析pptx中每个xml的含义
第二步:整体架构设计
我把这个库分成了三层(我在小册中提到的分层思维)
- PPTX Reader层:负责读取pptx中的内容,将其转为便于理解的格式,也就是自己定义的PPTX的对象
- PPTX Render层:负责进行pptx单个幻灯片的渲染,入参为上一步得到的PPTX对象,不同的渲染方式实现不同的渲染对象,比如我们可以开发一个HtmlRender,将其渲染成为html格式,或者开发一个Canvas Render将其渲染成为Canvas,而不是写死,这样扩展性也更好一些(小册中提到的前端扩展方法)
- PPTX Preview层:负责整个pptx文件的预览,比如是采用左右翻页展示还是一下把pptx的幻灯片都展示出来,都由这个层来决定。
其中文件读取是非常复杂的,面对这种复杂的大型项目,必须考虑采用面向对象的方式来组织代码(也是小册中提到的),我将 PPTX Reader层细化为如下几个类。
- PPTX: pptx类,存储pptx文档的信息,比如缩略图,尺寸大小等信息
- Theme: 主题类,存储pptx的主题信息
- Slide: 单个幻灯片类,存储幻灯片信息
- PicNode:图片类,用它表示幻灯片中的一个图片
- ShapeNode:形状类,用它表示幻灯片中的一个一个形状
- Node:不同节点的基类
- ...
第三步:搭建代码仓库
这次决定还是采用monorepo方式组织代码,其中技术栈包括 turbo + ts + jest单测 + rollup打包 + eslint 等。
目前进展
目前正在开发 PPTX Reader 层的相关代码,争取元旦前完成PPTX中基础功能的预览,有什么心得和进展随时给大家同步。
感兴趣的同学可以关注我或者仓库,小册近期也要上线了,到时候大家多关注支持。
来源:juejin.cn/post/7418389059287908404