前端工程化改造尝试

前端工程化改造尝试

最近线上问题多多,又因为性能问题被客户喷了,实在是需要静下心来弄一下性能问题了。

目录

  • 1.引子
  • 2.问题分析
  • 3.实践及遇到的问题
  • 4.效果

引子

我们的项目是那种很传统的Javaweb项目,只用jQ,bootstrap和各种jQ,bootstrap的插件开发,没用任何mvvm框架,也没用任何前端工程化的方法,压缩js,css还是用的maven插件做的。

其实在去年10月的时候就已经做过一次性能的改进,那时候没啥经验,看了半天,认为原因在很多script的加载阻塞了主页面的加载。最后也就是把所有的script标签全部加上defer标签,以让浏览器在加载脚本的时候只加载不执行,然后写了个异步加载js和css文件的函数,等到$document.ready方法被调用的时候再加载。有同学问那这样加载的时间不还是一点没少么,只是减少了DOMContentLoaded时间,但是增加了Loaded的时间啊。

但是不慌,用户那时候只看的DOMContentLoaded的时间,所以我就把所有css,js文件全部放到异步加载的函数里,一个一个试,最后能放的都放了,再放剩下的就出bug了T-T

过了几个月逍遥日子,最近用户又闹性能差了,去了一看,发现用户已经开始关注loaded时间了,也就是chrome的network标签页里红色的那个数字,这回可不是在$document.ready里加载就能够解决了

问题分析

把所有异步加载函数,各种init()函数全部注释掉,防止所有的页面加载后的异步调用影响咱分析问题。这时候看看network里的加载,看了下就知道问题在哪了————引用的静态资源太多了。

刚开始说过我们这是很传统的java文本项目,所有插件js,css文件全部在jsp的头部引用,仔细一看一个页面加载的静态资源,包括js,css和图片文件最少有50个,最多有60多个,最后导致的结果就是加载时间形成了一个梯形,每次加载6个,其他资源都在苦哈哈的排队……一直等到1580ms后才加载完毕,问题就在这了,如果能够合并起来就成了,看到这很多同学就能想到个东西了对吧,就是webpack,号称前端万能工具。

实践及遇到的问题

  • 1.准备

对于从来没有进行过前端工程化改造的项目来说,项目目录是极为简单的,一个Javaweb项目,无非就是一个webapp文件夹,里面有view,js,css,image文件夹,很简单。但是现代工程化的前端文件目录就复杂了,server文件夹放node服务端文件,app放开发文件,build放生产文件,task放任务命令文件等等,app里的每一个js文件都是很小很小的只有一个小功能,高度解耦,方便自由组合,使用的时候按需加载,这也是模块化的最大好处。

但现在我这项目第一次改造,目的也仅仅为了合并静态资源而已,就先学会走路吧,只加了个app文件存放开发文件,编译后的文件直接输出到js和css文件夹里,当然知道这种方式不太对劲,但是先完成再说。

  • 2.闭包实现的模块化js的处理

先是js文件,这可是阻塞加载的大头,css和img文件最多就占个下载文件的线程,js要是执行的时候可是能把其他动作都暂停掉啊,但是我们的js文件又有一个问题。如果是第三方的js文件,我还可以直接打包试试,但是我们自己的js文件,都是下面这种:

var module=function(window){
    function funOne(){
        //do something
    }
    return{
        funOne:funOne
    }
}(window)

用一种闭包的方式来将一个很大的js文件形成一个很大的模块,这样用着简单是简单,在其他页面里只需要引入这个技术文件,再用module.funOne()就可以调用了,但是这根本不是现代的模块化写法啊,而且用过webpack打包多个js文件的时候都有注意到,webpack会将所有js文件全部放到各个闭包里面,这样在其他页面或者文件里直接调用module.funOne()的时候根本就不能调用到。本来想全部改为es6的模块化写法,把var module那一层去掉,return到外面的函数用export{funOne},这样其他js文件能够用import的方式引入,后来发现这样做在jsp里面真的就没法调用了……

最后没办法就用了一个简单粗暴的方式,把var module改为window.module,全部挂在到window对象上,其他所有引用方式都改为window。module.funOne(),这样麻烦是麻烦点,不过起码能用了。

当然还有些外部的js文件并不一定是用模块化的方式写的,所以这些文件暂时不打包在一起,继续在头部引入……

  • 3.第三方插件的处理

由于引入了很多jQ和bootstrap的插件,导致打包的文件选择需要慎重,jQ,bootstrap这种基础包我还是不敢合并的,还是以外部链接方式引入,而像jQueryUi这种一打包就报错的也不合并。还有些特殊的插件,比如ckeditor,这是一个富文本编辑器插件,本来这个插件很大,js包就得有550KB,再加上只有在页面上某一个小地方才用到,就把他放到异步加载的函数里,等到最后运行的时候发现会报错,为啥呢,观察报错的地方就知道,这个插件并不只是这有这一个js和一个css文件,还有一些文件需要再初始化的时候由插件自动生成script和link节点引入更多的文件(看来他自己也知道文件太多了……),但这时候就有问题了,他使用了this关键字来定义路径引入更多的文件,如果放到jsp的头部引入,初始化的时候定义的路径就是对的,但如果是异步由本地生成节点引入,路径就会变成本地的路径,找不到任何资源而报错。当时定位这个问题也是花了蛮大功夫,最后带在异步引用代码的后面加上如果引入成功,就将引入路径改为正确的路径,完美解决。

  • 4.公共组件的选择

一开始把所有的js文件全部打包成一个,最后发现文件文件上MB了……

用过webpack的小伙伴们都想起了webpack有一个自带插件CommonsChunkPlugin,能够自定义让webpack根据各个入口的打包的文件按照一定的规则把打包次数多的js或者css文件打包成公共组件,也就是我们熟悉的vendor.js文件啦,可能文件名还包含哈希值。把那些到处引用的基础插件,性能统计插件,登陆维持插件啥的全部放进去打包!(真实填坑经历绝对不是那么顺利的……)

效果

由于项目涉密,没法截图,有些页面的整改效果还是不错的,减少了大量的请求,图片也不需要加载了(但是css变得文件好大啊……),那些页面都加载时间减少了300——400ms,人品好的时候能到700ms以下。但是诡异的是,有一个页面合并静态资源后加载时间还变长了,尴尬……

仔细对比了下打包前后的页面请求情况,打包前是很多几十kb的文件不断的加载,一个接一个,没有空闲时间,打包后几个文件都很大,在加载大文件的时候,居然没有再加载其他文件了!!明明有多余的线程可以加载啊,看来在文件大小和加载时间上是有一个平衡点的,并不是全部打包到一个大文件就行了(打包后的文件大小:两个400kb,两个300kb)。

你可能感兴趣的:(前端工程化改造尝试)