某某茶叶有限公司欢迎您!
金沙棋牌在线 > Web前端 > 前端静态资源管理

前端静态资源管理

时间:2019-12-29 06:38

我们是如何做好前端工程化和静态资源管理

2016/07/30 · 基础技术 · 工程化, 静态资源

原文出处: 凹凸实验室   

图片 1

随着互联网的发展,我们的业务也日益变得更加复杂且多样化起来,前端工程师也不再只是做简单的页面开发这么简单,我们需要面对的十分复杂的系统性问题,例如,业务愈来愈复杂,我们要如何清晰地梳理;团队人员愈来愈多,我们要如何更好地进行团队协作;功能愈来愈多,我们要如何保证页面的性能不至于下降,等等。所有的这些都可以归结为如何提升开发体验和性能问题。

一 必备软件。

  • GIT 分布式版本控制系统
  • VScode 推荐前端代码编辑器,保持代码格式统一
  • SourceTree 可视化的GIT操作工具

首先要明确为什么要进行前端静态资源的版本管理,其主要目的是为了解决浏览器缓存问题,很多人会说浏览器缓存不是服务端通过设置Etag过期时间之类的就可以吗?为什么前端还要管理缓存?还有人可能会说,缓存这么麻烦,那么可以不缓存?

目前更新比较及时的项目是,https://github.com/cdnjs/cdnjs,5000多 star。

提升开发体验

我们主要从以下三个方面来提升我们的开发体验。

二 gitlab

GitLab是利用 Ruby on Rails 一个开源的版本管理系统,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目。它拥有与Github类似的功能,能够浏览源代码,管理缺陷和注释。可以管理团队对仓库的访问,它非常易于浏览提交过的版本并提供一个文件历史库。团队成员可以利用内置的简单聊天程序(Wall)进行交流。它还提供一个代码片段收集功能可以轻松实现代码复用,便于日后有需要的时候进行查找。

图片 2

image.png

带着上面的疑问,所以我们要了解浏览器缓存。

1、依托这个项目国外的资源库有,https://cdnjs.com/,优点是搜到的东西多,缺点是搜索慢;

规范化

当团队人员不断扩充时,我们需要制定统一的规范来对平时的开发工作做出一定约束和指导。统一的规范包括前端的代码规范,根据规范定义好一套代码检查的规则,在代码提交的时候进行检查,让开发人员知道自己的代码情况。

同时,根据以往的开发经验,我们制定了统一的项目框架,根据业务功能不同,将一个项目(app)拆分成不同的业务模块(module),而每一个模块都包含自身的页面(page)以及构成页面所需要的组件(widget),每一个项目涉及到app、module、page、widget这些已经约定好的概念,这样让项目结构更加清晰,而且让团队内不同业务的人员之间切换无障碍。

图片 3

三 SourceTree的使用

  • 1 先获取到GIT仓库的地址如:

图片 4

image.png

  • 2 克隆到我的电脑

图片 5

image.png

图片 6

image.png

  • 3 提交代码

图片 7

image.png

  • 4 新建分支

图片 8

image.png

  • 5 合并分支

选择当前需要合并的分支右击。注意:从哪到哪?

图片 9

image.png

  • 6 处理冲突
    两个用户修改了同一个文件的同一块区域

图片 10

image.png

感叹号代表的是冲突文件,
找 >>>>>>>>这种 和<<<<<<<<这种 =====这种 符号就知道哪里冲突了
再次勾选提交。

图片 11

image.png

浏览器缓存基本认识

浏览器缓存能有效减轻资源服务器的请求量,提高网页或应用程序的资源访问速度,所以一个WEB应用,缓存是必不可以少的优化利器。

缓存分为:

  • 强缓存
  • 协商缓存

2、国内的有,https://cdn.bytedance.com/,搜东西很方便,资源用的国内阿里云 cdn,支持多协议,支持资源拼接,搜索方便。

组件化

在项目中引入组件化的概念,这里的组件对应上文讲到的widget,每一个组件都会包含组件自身的模板、css、js、图片以及说明文件,我们使用组件来拼装页面,像搭积木一样来拼装我们的页面,同时一个组件内可以调用另一个组件。

图片 12

在拿到设计稿后,我们首先需要确定哪些需要做成公共组件,那些是要做成独立组件,以及组件间如何进行通信。在页面中调用这些组件后,会自动加载组件的模板以及组件的静态资源,而当组件不再需要时,只要移除掉组件引用,那么相应的模板和静态资源也会不再加载。

组件化的好处主要有这么几点

  • 管理方便,我们可以把一个独立功能相关的文件在工程目录中放在一起,这样代码管理起来会非常便利
  • 组件复用,通过抽取公共组件,可以实现组件复用,从而减少工作量,创造价值
  • 分而治之,这是组件化最重要的一点,将页面组件化,就是对页面功能的拆分,将一个大的工程拆成小的零件,我们只需要关注每一个零件的功能,极大地降低了页面的开发与维护的难度

四 前端资源目录

图片 13

image.png

强缓存

通过服务器返回response header中的Expires或者Cache-Control的时间来决定是否从本地读取缓存资源。

字段 http版本 说明
Expires http1.0 返回GMT的绝对时间
Cache-Control http1.1 以秒为单位的过期时间

自动化编译

在前端开发中,我们总是会去使用很多工具、手段来优化代码、提升开发效率,例如,我们会使用sass、less等CSS预处理工具来编写更好维护的样式代码,我们也会使用CSSLint、eslint等代码检查工具来检查代码的语法错误,使用文件合并压缩等手段来减少资源大小,除此之外我们还会去做雪碧图合并、多倍图处理、字体压缩处理、代码发布等等。

曾经有大神说过,超过90s的工作都应该自动化掉。而以上所有的这些工作,贯穿我们整个开发流程,但是不同工具的切换不但显得凌乱,而且影响开发效率。在自动化、工程编译的思想早已深入人心的当下,我们当然也要紧跟潮流,所以我们考虑通过自动化手段来提升我们的效率,让所有操作可以一键式开速执行完。

我们将通过定义好一系列的编译任务,按照一定顺序依次对我们的项目自动进行编译操作,最后产生出可上线的代码。

五 前端测试服务器

  • 1 IP地址 :172.16.4.11
  • 2 安装了jenkins。配合gitlab 里面的web钩子。提交代码则同步到测试服务器。
  • 3 配置的IIS站点指向store。

图片 14

image.png

协商缓存

当浏览器对某个资源的请求没有命中强缓存,就会发一个请求到服务器,验证协商缓存是否命中,如果协商缓存命中,请求响应返回的http状态为304。当浏览器收到304响应时,就会直接从本地缓存读取资源。

协商缓存是利用的是【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】这两对Header来管理的。

提升性能

我们主要从以下四个方面来做好性能优化。

强缓存和协商缓存的共同点

强缓存与协商缓存的共同点是:如果命中,都是从客户端缓存中加载资源,而不是从服务器加载资源数据;区别是:强缓存不发请求到服务器,协商缓存会发请求到服务器。

首屏优化

页面的打开速度一直是大家非常关心的一个指标,一个页面打开太慢会让让用户失去等待的耐心,为了让用户更快地看到页面,我们考虑将页面中部分静态资源代码直接嵌入页面中,我们通过工具处理,在工程编译阶段,将指定的静态资源代码内嵌入页面中,这样可以减少HTTP请求,提升首屏加载速度,同时降低页面裸奔风险。

前端刷新缓存

根据前面缓存的基本知识,当资源被强缓存时,而资源版本已在服务器更新,这时我们就需要刷新缓存。当文件重命名或文件URL添加参数,都可以刷新缓存。

一般通过两种方式来刷新:

  • 资源重新命名,如: index.js 更新为 index_a083082f.js
  • 资源链接添加变化的参数,如:index.js 更新为 index.js?hash=a083082f

按需加载

同时,我们考虑通过尽量减小页面体积来提升页面打开速度,在业务上我们将页面划分为一个个楼层组件,以京东美妆馆为例,页面中从上而下分为首焦、至IN尖货、今日特惠、潮流前沿、口碑榜单这么几个楼层组件,其实这个页面还有很长,内容非常多且复杂。

图片 15

之前我们的做法是整个页面直出,这样一次性加载的内容会非常多,为了提升打开速度,我们考虑通过按需加载的方式来优化页面的加载。我们在页面中只放每一个楼层的框架性代码,楼层的模板和数据都通过异步的方式去拉取,来实现楼层组件的按需加载,同时我们可以对模板以及数据进行缓存,以此来减少请求,做更极致的优化。在开发中我们以正常组件的方式去开发整个页面,随后通过编译工具,在代码编译阶段自动将楼层的模板抽离成一个独立的JS文件,并给楼层容器打上标记位,通过页面加载逻辑去按需拉取模板,再进行渲染。

通过给楼层容器和模板分别加上标记位 o2-out-tpl-wrapper o2-out-tpl

图片 16

在编译时自动将指定的模板代码抽离成独立js文件

图片 17

并且给楼层容器打上标记

图片 18

同时在逻辑脚本适当位置自动加入模板的版本

图片 19

通过上述步骤,实现按需加载的自动化生成,在提升性能的同时,很好地解放我们生产力。

资源重新命名

从可用性角度说,大型web应用中,资源重新命名是最优的选择,因为新的资源文件不会覆盖正在运行的资源文件,比如关键逻辑的JS脚本文件。而且CDN回源需要一定的时间才能全网生效,等资源文件生效后再进行HTML文件的发布。HTML文件强制不缓存,就能很好的达到WEB应用版本更新的目的。

资源重新命名,也同时会造成大量无效旧版文件存在于CDN或版本管理服务器(SVN,GIT)。

基于资源表加载

根据页面组件化,通过工具分析,我们将获得页面与组件的依赖关系表,同时也能确认页面所引用资源的依赖关系,例如,我们在页面hello中同步引用组件topbar,那么依赖关系表中将会记录同步引用关系hello引用topbar.tpl、topbar.css、topbar.js,那么页面hello将会自动加载组件topbar的CSS与JS,同时依赖表会记录异步引用的关系,假如我们在组件C中通过API异步引用了组件D的js,那么会在依赖表中记录C异步引用D.js这一个依赖关系,这样D.js这个资源将会在用到的时候被异步调用。

图片 20

图片 21

同步引用的资源通过生成combo形式链接,在服务端进行文件合并,这样在页面加载的时候,页面只会加载自己需要的同步资源,异步的资源将会在用到的时候再加载,有效避免资源冗余。同时删除、增加组件也非常方便,只需改动模板中对组件调用,通过编译工具会自动重新生成模板以及combo链接。

我们可以将资源加载的操作抽离出来,形成一套统一的资源加载框架设计,这样我们使用的模板可以变得更加灵活,无论是纯html模板,还是PHP或Java之类的后端模板都能有效支持。编译工具扫描代码后只生成资源依赖表,我们通过实现各语言平台的资源加载框架,让不同语言的模板都能基于同一个资源依赖表进行资源加载。

同时,对资源进行MD5重命名处理,文件md5重命名也是一种提升性能的有效手段,使用文件md5后开启服务器强缓存,可以提升缓存的利用率并避免不必要的缓存判断处理。但文件md5重命名后会出现开发时引用的文件名对不上的问题,这就需要在资源表中记录原文件名与md5重命名后之间的对应关系,当我们引用一个资源时,就会通过查表获取重命名后的资源名,然后利用代码中引用资源定位的能力来进行资源名自动替换。

图片 22

资源链接添加变化的参数

一般添加资源更新日期或文件内容的hash值。

但不管哪种方式,手动修改文件版本号,只适用于非常小型的应用。我们需要的是一个自动化的前端工具来做这件事。

于是笔者就造了以下两个轮子:

  • gulp-hash-list ,主要作用是读取资源,计算hash值,按指定的格式生成一个清单文件。
  • gulp-asset-revision
    读取资源列表的清单文件,替换HTML中的js,css等资源引用地址。

静态资源预加载

所谓静态资源预加载,就是当用户在进行浏览页面的时候,我们可以在当前页面静默加载下一个页面的静态资源,这样当用户进入到下一个页面时就能快速打开页面,从而在不知不觉中提升页面的打开速度。

图片 23

我们会在静态资源预加载平台上配置每一个页面id对应需要预加载页面资源的id,然后系统通过读取资源依赖表获取到所需要预加载的静态资源,生成预加载资源列表文件,再将文件推送到线上服务器,通过页面挂载js请求获取预加载资源列表,随后静默加载资源。在有了资源依赖表后,我们可以准确地分析到每一个页面引用资源的请求,就可以很好地实现静态资源预加载的功能。

图片 24

gulp-hash-list和gulp-asset-revision的使用

var gulp = require('gulp');
var hash = require('gulp-hash-list');
var revision = require('gulp-asset-revision');

gulp.task('hash', function() {
    return gulp.src(['./src/**/*.js','./src/**/*.css'])
        .pipe(hash({
            "template": "{name}{ext}?hash={hash}"
        }))
        .pipe(gulp.dest('./dist'))
        .pipe(hash.manifest('assets.json'))
        .pipe(gulp.dest('./manifest'));
});

gulp.task('revision', ['hash'], function() {
    return gulp.src(['./pages/*.html'])
        .pipe(revision({
            hasSuffix: false,
            manifest: './manifest/assets.json'
        }))
        .pipe(gulp.dest('./pages/'));
});

Athena

工欲善其事,必现利其器。为了实现我们对提升开发效率和产品性能的诉求,我们提出了比较完整的工程化解决方案以及对应的工具Athena。

Athena是由京东【凹凸实验室】(aotu.io) 推出的一套项目流程工具,通过Athena,我们可以很流程地跑完整个开发流程。Athena分为两部分,一是本地自动化编译工具,二是资源管理平台,其架构如下

图片 25

为什么要选用gulp-hash-list和gulp-asset-revision

其实Gulp生态已经有gulp-rev + gulp-rev-collector这种优秀的方案,但是它只支持生成新的文件名,不支持添加参数的形式。

gulp-hash-listgulp-asset-revision不仅可以支持生成新文件,同时支持添加参数的形式刷新资源版本号,以更新缓存。