将多个静态资源打包为单个资源以减小请求数目,是提升页面加载速度的经常使用手段。因而上个星期,我就在实现网站静态资源的自动打包功能,原觉得是个比较简单的问题,实现起来也没有遇到什么障碍,不过在开发完毕投入使用的时候却让我跌了下眼镜。因为静态资源在打包之后,它们的访问路径势必会改变,这样其余一些依赖于原有路径的资源就访问不到了。这方面最多见的例子,即是CSS样式表中引用的图片路径是相对于CSS文件路径的。当意识到这个问题之后,还真是让人手忙脚乱了一把。css
例如,有一个描述对话框组件的CSS文件,它的原有访问路径为/styles/dialog/core.css,其中有行样式表为url(header.png),这意味这幅图片的访问路径为/styles/dialog/header.png。一样,在另外一个文件/styles/menu/core.css中也有url(bg.png)这样的代码。那么好,若是咱们将这两个文件打包在一块儿,叫作/packed/styles/dialog-menu.css,那么浏览器就会去加载/packed/styles下的header.png和bg.png,为何?由于url(…)这段代码,在打包后出现的位置就不一样了。html
解决这个问题彷佛有多种办法,例如将资源文件复制到/packed/styles下面,但这就要处理文件重名的问题。若是使用组件化开发的方式,两个组件之间应该不去考虑资源的重名,不然就产生了依赖。另外一种方式,是在CSS内部使用绝对路径,例如在/styles/menu/core.css中使用url(/styles/menu/bg.png)而不是url(bg.png)。这么作能够解决打包上的问题,可是却破坏了组件化的开发方式。例如此时dialog组件就不是独立的了,它的图片路径是死的。而在理想状况下,一个组件的CSS文件和图片等资源应该是统一的,并独立与其余条件,这也是CSS中url(…)含义的设计目的。前端
固然,我并非说这种“组件化”的实践是必须遵照的,若是只是在开发一个独立的项目,即可以将“绝对路径”做为项目中的约定。可是在实际状况下,这种组件化及相对路径的使用是客观存在的。例如jQuery成百上千的插件,它们的CSS样式中必定不会使用绝对路径。那么咱们又该如何对它进行打包呢?正则表达式
其实路径问题也很容易解决,只要在“打包”的时候修改掉CSS文件内容里的路径便可。例如咱们能够知道,若是浏览器是在/packed/styles/dialog-menu.css文件中,访问到本来在/styles/dialog/core.css里的内容,那么本来的url(bg.png)就必须改写成url(/styles/dialog/bg.png)这样的绝对路径,或者是url(../…/styles/dialog/bg.png)这样相对于新地址的“相对路径”。浏览器
这样的修改其实并不复杂,例如在CSS中,彷佛须要替换的也只有url(…)这样的地址了,一个普通的正则表达式即可以解决,而比较麻烦的多是JavaScript文件了。在某些组件化的JavaScript中,它须要的一些资源也是根据脚本文件的地址相对计算出来的。此时,其中的路径可能只是一些普通的字符串而已,没有规律保险的替换规则。若是要解决这个问题,咱们能够在项目中造成某种约定,例如,计算相对路径时都不是简单的字符串拼接,而是使用一个函数调用。而这个函数调用,在进行“打包”时即可以看做是一个待替换的标志。函数
相对路径的问题彷佛就这么解决了,我想前面这段描述也已经足够清楚,比写代码还要清楚,因此暂时就先不提供我在项目里使用的动态打包机制了。不过这里还有个小小的花絮能够一谈。工具
负责前端开发的同事很重视静态资源的打包问题,所以也就一直催促我实现这方面的功能。以前他说,他须要一个工具,输入一个配置文件,即可以将指定文件打包,而后在正式站点发布时修改页面上引用的地址就好了。我说这样不行,会死人的。例如,一个组件会在多个页面上使用,那么它的更新会致使屡次打包,还要修改多个页面文件,这对于站点的快速升级更新也是一个灾难。此外,在页面上所使用的静态资源信息,还须要在打包工具的配置文件中重复,这也是一种违反DRY的状况。组件化
我理想中的打包机制要有如下几个条件:性能
上周实现的解决方案彷佛基本符合这些条件,有机会我再来分享吧。网站