明白如何高效地管理网站静态资源

背景因为网址导航的“草根”网民相对多,同样访问量的网址导航网站与其他网站相比,广告收入要多一些。因为草根,对广告与内容分辨不清,容易接触新事物,所以网址导航网站的广告价值很高。
随着互联网开发和迭代速度越来越快,网站也变得越来越庞大,存在大量静态资源,我们原有管理静态资源的方式变得越来越不适用,就如同封面图一样,静态资源之间的关系错综复杂,给工程师带来了很多麻烦:
人工管理依赖的噩梦,工程师需要频繁管理和维护每个页面需要的js&css文件,包括静态资源之间的依赖关系以及加载顺序等。
性能优化成本高且不可持续性,为了提高网站性能,工程师总是在忙于优化页面静态资源的加载,包括动态加载静态资源、按需加载静态资源和修改静态资源合并策略等,但是过了一段时间性能又降下来了,又需要周而复始的重复。
静态资源差异化的挑战,pc和无线的适配,不同的网络和终端需要适配相应的静态资源;当网站需要支持国际化的时候,需要对不同的国家进行差异化处理,返回不同的静态资源,这些需求对原有的静态资源管理方式提出巨大挑战。
缺少快速迭代和试验新功能的有效支持,从开发到上线流程繁琐,导致项目迭代周期长
每天工程师都会提交大量的newfeaturebugfixes,每次项目发布和迭代都面临着以上的问题,是否可以有一套系统帮助我们管理调度静态资源来减少人工管理静态资源成本和风险,来达到更快、更可靠、低成本的自动化项目交付。在实际项目开发中,我们进行了大量探索和试验,实现了一套静态资源管理系统,对静态资源进行全流程的管理和调度:
帮助工程师管理静态资源间的依赖以及资源的加载
管理静态资源版本更新与缓存,自动处理cdn
自动生成最优的静态资源合并策略,实现网站自适应优化
实现静态资源的分级发布,快速迭代,轻松回滚
根据国际化和终端的差异,送达不同的资源给不同的用户
下面本文将会介绍我们是如何通过静态资源系统来高效管理静态资源的。
架构
静态资源管理系统主要包含compile、sourcemap、backend-framework、frontend-loader几个核心模块:
compile,对静态资源进行编译处理,包括对静态资源进行预处理,url处理(添加md5戳、添加cdn前缀),优化(压缩、合并),生成sourcemap等
sourcemap,在compile阶段系统会扫描静态资源,建立一张静态资源关系表,记录每个静态资源的部署路径以及依赖关系等信息
backend-framework,后端运行时根据组件使用情况来调度静态资源,为前端返回页面渲染需要的资源。
frontend-loader,前端运行时根据用户的交互行为动态请求静态资源。
静态资源管理系统通过自动化工具对静态资源进行预处理并产出sourcemap,sourcemap中记录着静态资源的调度信息,这样框架在运行时会根据sourcemap中提供的调度信息自动为用户进行静态资源调度,不仅可以做到送达不同资源给不同用户,还可以自适应优化静态资源合并和加载。
自动管理静态资源依赖
静态资源管理系统为工程师提供了声明依赖关系的语法和规则,在compile阶段系统会扫描静态资源,建立一张静态资源关系表,记录每个静态资源的部署路径以及依赖关系等信息。
在html中声明依赖
在项目的indexhtml里使用注释声明依赖关系:
在sourcemap中则可看到:
在js中声明依赖
支持识别js文件中的require函数,或者注释中的@require字段标记的依赖关系,这些分析处理对html的script标签内容同样有效。
在sourcemap中则可看到:
在css中声明依赖
支持识别css文件注释中的@require字段标记的依赖关系,这些分析处理对html的style标签内容同样有效。
在sourcemap中则可看到:
按需加载静态资源
在静态资源管理系统接管了项目中的静态资源后,可以知道静态资源的运行情况以及依赖关系,然后可以做到自动为页面按需加载静态资源,下面通过一个例子来详细讲解:
sidebartpl中的内容如下,
对项目编译后,自动化工具会分析依赖关系,并生成sourcemap,如下:
在sidebar模块被调用后,静态资源管理系统通过查询sourcemap可以得知,当前sidebar模块同步依赖sidebarjs、sidebarcss,异步依赖sdebarasyncjs,在要输出的html前面,生成静态资源外链,我们得到最终的html
如上可见,后端模块化框架将同步模块的scripturl统一生成到页面底部,将cssurl统一生成在head中,对于异步模块(requireasync)注册resourcemap代码,框架会通过{script}标签收集到页面所有script,统一管理并按顺序输出script到相应位置。
当我们想对模块进行打包,只需要使用一个pack配置项,对网站的静态资源进行打包,这样在sourcemap中,所有被打包的资源会有一个pkg属性指向该表中的资源,而这个资源,正是我们配置的打包策略。这样静态资源系统可以根据对应信息找到某个资源最终被合并后的package的url,最后把这个url返回给页面。
自动合并静态资源
静态资源管理系统可以根据产品线上静态资源使用的数据,自动完成静态资源合并工作,对工程师完全透明,解决手工维护的未及时排除废弃资源、不可持续、成本大等问题。
详情请见静态资源自动合并;
静态资源版本更新与缓存
静态资源管理系统采用基于文件内容的hash值来控制静态资源的版本更新,如下所示:
其中_82244e91这串字符是根据ajs的文件内容进行hash运算得到的,只有文件内容发生变化了才会有更改。这样做的好处有:
线上的ajs不是同名文件覆盖,而是文件名+hash的冗余,所以可以先上线静态资源,再上线html页面,不存在间隙问题;
遇到问题回滚版本的时候,无需回滚ajs,只须回滚页面即可;
由于静态资源版本号是文件内容的hash,因此所有静态资源可以开启永久强缓存,只有更新了内容的文件才会缓存失效,缓存利用率大增;
修改静态资源后会在线上产生新的文件,一个文件对应一个版本,因此不会受到构造cdn缓存形式的攻击
静态资源管理系统会在compile阶段识别文件中的定位标记(url),计算对应文件的hash,并自动替换为'文件名+hash',无需工程师手动修改。
静态资源分级控制
静态资源管理系统可以对静态资源做进一步控制(controllingaccesstofeatures)以达到分级发布的效果,主要包括以下两块核心功能,
featureflags,用来控制feature对应的静态资源是否加载
featureflippers,可以灵活控制feature,不仅仅是on或off,可以做到类似'3%用户可以访问此功能'、'对内部所有员工开放'类似的效果
通过以上的控制我们可以轻松做到发布一个新功能,让这个功能只对部分用户可访问,当功能完善后对所有用户开放,如果功能出现问题直接一键回滚即可。
在项目中的类似代码如下:
静态资源管理系统会根据配置在运行时对$configsome 进行干预实现对静态资源的访问权控制,通过运行时的配置(feature flag)来控制静态资源,还可以支持主干开发的方式,来达到更快的迭代速度。
我们还可以实现国际化的需求,原理同分级发布,在运行时的做一些更细致的差异化处理
总结
静态资源管理系统的核心是对静态资源进行调度,可以很灵活的适应各种性能优化和差异化处理的场景,来达到更快、更可靠、低成本的自动化项目交付。但是同时这个系统十分复杂,承载着各种职责,这个系统本身会成为整个网站的关键节点和瓶颈。
作者:walter(:weibocomu1916384703)-fis
来自::fexbaiducomblog201404fis-static-resource-management