ueditor之一波多折

首先要承认,百度前端团队出品的ueditor可能是所有开源富文本编辑中,功能最全的一款编辑器。虽然2016年百度公司整体的业界口碑有所下滑,但是攻城狮的开源精神始终是值得称赞的。核心源码并没有细看,但从整个库的使用方式来看,模块化方案似乎做的并不是很好,后来百度的echarts这方面就做的好一些,另外它的版本号规范不符合semver规范,不过它本身也不支持npm包的使用方式。

说起我与ueditor的历史,最早要追溯到2013年年中的样子,那时我刚刚从后端转为全职前端,这款编辑器还是产品经理推荐的,当时ueditor用的什么版本大约是1.2左右吧。总之,几经波折终于成功用在项目中并发布上线了,感觉好开森~

然后再次接触ueditor已经是2016年了,在我来到当前东家时,ueditor已经在线上使用了,版本是1.3.6。那是一个老项目,纯jquery时代,没有CSS预处理器,没有模块化加载器,你懂的~由于我并不负责那块,一开始并没有关注。后来2016年年中,这个老项目要用vue重构(前后端彻底分离),ueditor当然也要用组件封装,于是去瞄了一下老项目里的ueditor配置。我惊讶的发现,它居然能够支持浏览器直传第三方存储(我们用的是又拍云),当然这也需要第三方存储支持HTTP方式上传。重构当然要选择ueditor的最新版啦,此时已经是1.4.3,发现关键配置项变化巨大。下面开始『折』:

一折

经过查阅官方的发布历史以及相关源码,发现从1.3.6到1.4.2,文件上传模块经过大规模重构,相应的用法也是几乎完全不同,更重要的是,1.4.3已经不支持直传第三方服务了!

那这就不能好好玩耍了,支持第三方直传不是挺好的嘛,不仅减少自有服务器流量,而且加快了上传速度。可是不升级的话,又享受不到后期的升级功能以及一些历史bug修复。

最后,考虑到,不想麻烦后端开放上传接口,以及希望保留浏览器直传第三方的优势,选择继续使用1.3.6版本。

二折

1.3.6版本的第三方直传需要修改dialogs/image/image.html这个文件中的源码(网上有很多文章介绍),原有的代码里各种全局变量,真是。。。再瞄一眼依赖的js,又是各种全局变量,我也是呵呵了~那代码怎么看怎么不舒服。

反观1.4.3版本的源码,相应文件全局变量确实少多了。

三折

上传附件的对话框,是个iframe(指向dialogs/image/image.html),而且和父页面有数据交互,这意味dialogs/image/image.html必须和父页面同域。而这次重构是打算把所有静态资源上传到又拍云的。

然后,就又不能好好玩耍了囧~~~

最后,为了使我们自己服务器干净整洁,我还是把ueditor静态资源包传到了又拍云,通过nginx代理到又拍云,如此才能使上传功能正常。但是,这么做,其实比把ueditor静态资源包放在我们自己服务器性能要低的,毕竟绕了一圈又回来了。

其实,iframe跨域确实有解决方案,最方便的跨子域设置domain的方案也觉得不很妥,而且下文会提到放在自己服务器也是可以接受的。

四折

上面那个项目重构好以后,后来的新项目,由于时间紧张,ueditor的封装,都拷贝了上个项目的源码。嗯,没错,就是『人肉拷贝』,仔细想想,这么重的组件,一次次的『人肉拷贝』,以后的维护工作将是个灾难。

鉴于后来,我们很多项目已经在生产环境上了NodeJS(koa2)服务作为中间层,犹豫了好几天,我决定玩把大的,把ueditor(最新版)封装为一个npm包,同时提供前端vue组件以及服务端中间件,减轻了与后端同学的沟通成本。

说真的,上了NodeJS中间层,任何与业务持久数据无关的,我们都可以自己搞定。

这里还是要说一下,为什么放弃1.3.6的直传第三方功能。

  • 因为1.3.6的源码略丑,不忍直视
  • 之前我们就遇到了XSS等安全问题,新版本已经修复了此问题
  • 第三方直传是需要后端要提供一个上传秘钥参数给附件上传表单的,我担心这个秘钥如果被恶意劫持到会威胁到我们的第三方存储
  • 我们用的第三方存储是又拍云,直传又拍云上传返回的数据结构与ueditor要求的并不相符合,需要重定向到另一个接口去做转换,这就需要额外再提供一个接口,增加了维护成本。
  • 静态资源交给Nodejs,性能并不差,可以接受

另外,查阅了官方的ueditor文档,似乎可以通过插件重写其自带的上传功能,这让实现直传第三方存储成为可能,但这工作量估计不小,而且即使实现了,也会存在上述的若干问题,于是决定不去尝试了。

五折

严格讲,这一折跟第二折是同一个问题,只不过,我是在koa实现的基础上再次尝试解决跨域问题。

我不死心,为了使ueditor源码能够存放在又拍云,我特地开通了单独的一个又拍云空间存放ueditor源码用于做实验,前端加载的ueditor主模块地址仍然指向同域,通过Nodejs将其重定向到又拍云,其实随便想想应该不能成功的,但还是想试一试,结论果然是失败。然后,将其改为通过node-http-proxy模块代理到又拍云,这个方案是能够解决问题的,但是本质上与通过nginx代理是一样的,有性能问题。

另外,通过Nodejs提供ueditor源码,还有一个小小的优势,Nodejs可以随意定义缓存时间,而又拍云缓存时间只能是固定的7天多一点。我们可以设置比较大的缓存时间,对于同一个客户端而言,只要访问过一次,很久都不必再次加载ueditor相关资源了。

六折

chrome@50左右版本开始,对image/*类型的file元素,弹出文件选择器将会非常慢,需要修改ueditor的源码,使得文件选择器更快弹出

DEMO

https://github.com/stoneChen/koa-ueditor-upyun-demo