前言

使用vuereactangular等技术开发过程中,我们都会遇到以下问题:

  1. 首屏加载慢
  2. 每一次更新都需要清除浏览器缓存才能看到效果(经常被测试吐槽)

这两个问题可以从很多方面进行优化,今天我就从前端页面部署阶段来优化一下这两个问题。PS:以下内容都基于vue-cli3+

前端页面文件缓存方案

vue-cli3打包说起

路由使用按需加载后,打包生成的文件,每一个路由页面都对应一个jscss文件,入口main.js及其依赖则打包成了app.jsapp.css,公共依赖都放到了chunk-vendors.js

vue-cli3打包后的dist/js文件夹:

可以看到,打包生成的js/css/img等文件的文件名都带有hash值,当源文件内容改变时,重新打包后对应的文件hash值也会改变。举个栗子,我们修改了about.vuejs的内容,重新打包时about.jshash值会改变,以及依赖about.vue的文件app.jshash值也会改变,而其他没有修改的文件,打包后的hash值都不会改变。

我们知道,文件名带hash是为了消除缓存带来的影响的,但是所有文件都不缓存肯定不是一个很好的解决方案。

vue-cli3打包生成的文件名带hash值的作用

为了缓存的最优体验

我们先来简单回顾下http缓存的知识(参考MDN):

  1. HTTP1.0 是通过Expires(文件过期时间)和Last-Modified(最近修改时间)来告诉浏览器进行缓存的,这两个字段都是 UTC 时间(绝对时间)。Expires 过期控制不稳定,因为浏览器端可以随意修改本地时间,导致缓存使用不精准。而且 Last-Modified 过期时间只能精确到秒。
  2. HTTP1.1 通过Cache-ContorlEtag(版本号)进行缓存控制。浏览器先检查 Cache-Control,如果有,则以 Cache-Control 为准,忽略 Expires。如果没有 Cache-Control,则以 Expires 为准。

Cache-Control 除了可以设置 max-age(相对过期时间,以秒为单位)以外,还可以设置如下几种常用值:

  • public,资源允许被中间服务器缓存。浏览器请求服务器时,如果缓存时间没到,中间服务器直接返回给浏览器内容,而不必请求源服务器。
  • private,资源不允许被中间代理服务器缓存。浏览器请求服务器时,中间服务器都要把浏览器的请求透传给服务器。
  • no-cache,不管本地副本是否过期,每次访问资源,浏览器都要向服务器询问,如果文件没变化,服务器只告诉浏览器继续使用缓存(304)。
  • no-store,浏览器和中间代理服务器都不能缓存资源。每次访问资源,浏览器都必须请求服务器,并且,服务器不去检查文件是否变化,而是直接返回完整的资源。
  • must-revalidate,本地副本过期前,可以使用本地副本;本地副本一旦过期,必须去源服务器进行有效性校验。
  • proxy-revalidate,要求代理服务器针对缓存资源向源服务器进行确认。
  • s-maxage:缓存服务器对资源缓存的最大时间。

现在99%的浏览器都是HTTP1.1及以上版本,我们配置缓存就使用Cache-ContorlEtag配合就好了。

那么问题来了,检查文件是否最新不是用etag吗,为什么文件名还需要有hash值?

(1)如果文件名不带hash值,文件版本得用etag来标记,浏览器需要先去检查下是否过期,服务器则需要检查文件是否最新。

(2)而文件名带有hash值,可以直接将文件的过期时间设置为1年,浏览器就不用检查是否过期,直接使用。

原因是,如果页面源文件有修改,生成的js/csshash值就会修改,对应的请求js/css地址也会变化,htpp地址改了,也就不用检查是否过期。没修改的文件的hash则不变,可以使用缓存文件。

所以利用文件名带hash来做缓存,即能保证,页面有修改浏览器能请求到最新的文件,又能节省服务器的请求(检查是否过期的请求)。

实现无感知发版

只有一台服务器的情况下,我们的页面文件需要更新,通常操作是:先删掉旧文件,然后上传新文件,这段时间系统将不可用,对用户有一定的影响。

仅更新前端页面的前提下,文件名带有hash值还可以实现用户无感知发版:系统更新时,只需要将打包之后的文件除index.html以外的文件(js/css/img),全部上传到服务器网站目录,未修改文件(即重名文件)直接跳过,有修改的文件由于文件的hash值不同会被上传,上传完毕我们再将index.html覆盖掉旧版就行。这段时间用户已请求旧版本index.html的无影响(不会出现文件404,因为新旧版本js/css同时存在),而新访问用户则请求的是新版index.html,访问旧页面用户刷新也会请求新版文件,并且无缓存影响,即对用户使用0影响。一段时间之后,我们只需要按文件生成时间对比一下删除旧文件即可。PS:替换前端文件不需要重启服务器。

总结: 凡是文件名带有hash值的的文件都可以设置为“永久缓存”(一年),其他不带hash的文件使用etag来设置缓存,由Nginx判断是否过期。

优化打包结果

页面部署的时候,有个问题,如何区分文件名是否带有hash值呢?正则匹配显然不是很好的办法。其实办法很简单,打包生成的文件都带有hash值,而public目录里面的文件不会经过打包处理。所以只需要将public目录里面的文件除了index.html全部放到一个static目录(注意引入路径)

那么打包后的文件目录就会变成这样:

static目录里面的文件和index.html的文件名是不带hash值的,其他的文件都是带有hash值的

补充:打包后发现一些页面文件很小,只有几K

如下图所示,虽然是按需加载,但是感觉浪费服务器请求

这时,我们可以配置webpack的特殊注释(需要 Webpack > 2.4),将一些按需加载的路由打包到同一个js文件

const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
复制代码

这里需要注意一下,虽然每个文件单独打包都是1k,但是1k+1k不等于2k,也就是说,打包到一起的体积会比原来分开的大,4个1k的文件打包到一起,体积大约是10k,体积达到10k,刚好就会触发gzip压缩,压缩之后体积在4k左右,所以并没有什么影响。

服务器配置缓存

理论知识有了,现在我们来实际操作一下:文件名带hash的(即cssjsfontimg目录下的所有文件)设置一个月缓存,浏览器可以直接使用缓存不需要请求服务器。其他的文件(index.htmlstatic目录下的文件)设置为no-cache,即每次都来服务器检查是否最新。

为什么缓存时间是一个月,刚才不是说设置一年?设置为一年,当然没有任何问题。不变的文件可以一直使用,有改动的文件,会重新请求,但是有该动的旧文件已经没有用了,由于过期时间是一年,所以不会被删的,一直占用用户的硬盘,系统更新越频繁,无用旧文件越多,占用的存储也越多,这样是不好的(用户看了想打人)。所以设置一个合理的时间比较好,一个月就挺好。

废话不说,以Nginx服务器为例,配置如下(配置文件nginx.confhttp模块):

server {
location = /index.html {
add_header Cache-Control no-cache;
} location ~ /static/ {
add_header Cache-Control no-cache;
} location ~ /(js/*|css/*|img/*|font/*) {
expires 30d;
add_header Cache-Control public;
}
}
复制代码

效果如下图:当我们修改index.html内容时,会重新请求,没有修改就会304,文件名带hash的都是直接从本地缓存读取。

有两点需要注意的地方:

  1. 项目里面不要用service-worker,这会影响我们的缓存设置,浏览器会优先使用service-worker缓存。vue-cli4生成的模板自带service-worker

  1. 调试的时候记得允许缓存

前端文件设置gzip压缩

webpack配置生成gzip压缩的文件

webpack有一个文件压缩的插件,可以将大文件压缩成gzip的格式。使用起来也非常简单,先安装:npm install --save-dev compression-webpack-plugin

然后修改webpack配置(vue.config.js):

const CompressionWebpackPlugin = require("compression-webpack-plugin");
// 可加入需要的其他文件类型,比如json
// 图片不要压缩,体积会比原来还大
const productionGzipExtensions = ["js", "css"]; module.exports = {
configureWebpack: config => {
if (process.env.NODE_ENV === "production"){
return {
plugins: [
new CompressionWebpackPlugin({
// filename: '[path].gz[query]',
algorithm: "gzip",
test: new RegExp("\\.(" + productionGzipExtensions.join("|") + ")$"),
threshold: 10240, //对超过10k的数据进行压缩
minRatio: 0.6 // 压缩比例,值为0 ~ 1
})
]
};
}
}
};
复制代码

打包完的js/css文件,都会多一份对应的gzip文件,部署的时候需要配置一下,启用gzip,这样支持gzip压缩的浏览器请求的就是压缩文件,不支持的浏览器请求的就是源文件,gzip压缩文件体积会小很多。

字体文件是否需要gzip

网站中常见的图片的格式有jpg(jpeg)、pnggifwebp,这些格式的图片本身已经优化了,所以不再需要gzip。实际上对图片进行gzip压缩,不仅没有效果,反而可能使图片体积更大。那么字体文件呢,是不是和图片一样?

从阿里巴巴矢量图库生成的图标字体的css中我们可以看出,一般常见的字体文件有:eotwoffttfsvg,另外woff2是以base64的格式存储的。

@font-face {font-family: "iconfont";
src: url('iconfont.eot?t=1587624344896'), /* IE9 */
url('iconfont.woff?t=1587624344896') format('woff'),
url('data:application/x-font-woff2;charset=utf-8;base64,...') format('woff2'),
url('iconfont.ttf?t=1587624344896') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url('iconfont.svg?t=1587624344896#iconfont') format('svg'); /* iOS 4.1- */
}
复制代码

查阅资料后发现:eotttf 格式一般情况下本身不压缩,也就是说可以进行gzip压缩。而woff格式具有内建压缩,不需要gzip压缩。

实际测试一下,发现eotttf可以进行压缩,效果还不错,而woff格式的,CompressionWebpackPlugin插件根本不支持压缩,即使你写了配置了压缩woff文件,它也不会生成gz文件。

并且实验发现,svg虽然是图片,但是也可以进行gzip压缩,压缩效果还不错:

结论svgeotttf 这三种格式的字体文件可以使用CompressionWebpackPlugin进行压缩,并且配合Nginxgzip_types配置,woffwoff2格式的字体文件不需要gzip

服务器配置gzip压缩

Nginx是前端文件常用的服务器,Nginx服务器的配置文件nginx.confhttp模块:

server {
# 开启gzip on为开启,off为关闭
gzip on;
# 检查是否存在请求静态文件的gz结尾的文件,如果有则直接返回该gz文件内容,不存在则先压缩再返回
gzip_static on;
# 设置允许压缩的页面最小字节数,页面字节数从header头中的Content-Length中进行获取。
# 默认值是0,不管页面多大都压缩。
# 建议设置成大于10k的字节数,配合compression-webpack-plugin
gzip_min_length 10k;
# 对特定的MIME类型生效,其中'text/html’被系统强制启用
gzip_types text/javascript application/javascript text/css application/json;
# Nginx作为反向代理的时候启用,开启或者关闭后端服务器返回的结果
# 匹配的前提是后端服务器必须要返回包含"Via"的 header头
# off(关闭所有代理结果的数据的压缩)
# expired(启用压缩,如果header头中包括"Expires"头信息)
# no-cache(启用压缩,header头中包含"Cache-Control:no-cache")
# no-store(启用压缩,header头中包含"Cache-Control:no-store")
# private(启用压缩,header头中包含"Cache-Control:private")
# no_last_modefied(启用压缩,header头中不包含"Last-Modified")
# no_etag(启用压缩,如果header头中不包含"Etag"头信息)
# auth(启用压缩,如果header头中包含"Authorization"头信息)
# any - 无条件启用压缩
gzip_proxied any;
# 请求加个 vary头,给代理服务器用的,有的浏览器支持压缩,有的不支持,所以避免浪费不支持的也压缩
gzip_vary on;
# 同 compression-webpack-plugin 插件一样,gzip压缩比(1~9),
# 越小压缩效果越差,但是越大处理越慢,一般取中间值
gzip_comp_level 6;
# 获取多少内存用于缓存压缩结果,‘16 8k’表示以8k*16 为单位获得。
# PS: 如果没有.gz文件,是需要Nginx实时压缩的
gzip_buffers 16 8k;
# 注:99.99%的浏览器基本上都支持gzip解压了,所以可以不用设这个值,保持系统默认即可。
gzip_http_version 1.1;
}
复制代码

检查gzip是否生效

浏览器文件请求的请求头包含字段Accept-Encoding: gzip代表浏览器支持gzip压缩文件

文件响应头包含字段Content-Encoding: gzip代表返回的是压缩文件

同时NetWork一栏还可以查看到文件的实际大小和实际的请求(gzip)文件大小

检查Nginx是否使用了我们提供的gz文件

Nginx自带gzip压缩功能,如果我们没提供,它会实时压缩(例如index.html文件),这就很浪费服务器资源了。现在我们已经提供jscssgz文件,如何判断Nginx是使用了我们提供的gz文件,而不是自己压缩的呢?

上面有一个配置项:gzip_static on;,开启之后Nginx会优先使用我们的gz文件,但是还是不能确定,Nginx有没有使用gz文件。

查看network请求发现,每一个文件都有etag响应头,如果Nginx使用了已有的gz文件,那么这个请求的etag值不带有W/,反之,如果是文件是Nginx压缩的,etag值则会带有W/

例如index.html:

chunk-vendors.js做一个实验,这个文件本身是带有gz文件的,请求的etag如下(不带有W/):

这时候我们删掉服务器上chunk-vendors.js对应的gz文件,刷新页面,请求如下:

综上,我们就可以验证,只要我们配置了gzip_static on;Nginx就会优先使用了我们提供的gz文件。

附录 - windows安装Nginx服务器

  1. 下载windowsNginx的安装包:nginx.org/en/download…

  1. 解压压缩包

  1. Nginx的目录下使用cmd命令行,启动命令:start nginx,关闭命令:nginx -s stop

备注:修改配置文件需要重载配置:nginx -s reload。启动之后,打开http://localhost:80就能看的效果

总结

页面文件合理的设置缓存和gzip压缩是实实在在能提升用户体验的操作,而且比少写几个循环、删除几行代码优化强得多,但是需要前端和运维的密切配合,才能实现最佳方案。

service worker是用来实现离线应用的,文章中没有详细赘述。vue-cli4生成的模板自带service worker,或许这才是vue项目缓存的最佳实践?

最后,Nginx并不是很熟悉,有什么问题和错误,欢迎指出!

作者:沉末_
链接:https://juejin.im/post/5eb2243e51882555d8457833
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

vue项目部署的最佳实践的更多相关文章

  1. vue项目的一些最佳实践提炼和经验总结

    项目组织结构 ajax数据请求的封装和api接口的模块化管理 第三方库按需加载 利用less的深度选择器优雅覆盖当前页面UI库组件的样式 webpack实时打包进度 vue组件中选项的顺序 路由的懒加 ...

  2. Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践(二)

    Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践(一) 接上一篇 3. Nginx配置反向代理 3.1 cnetos 安装nginx 首先,我们需要在服务器上安装N ...

  3. Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践(一)

    环境 本地 win7 服务器:Virtual Box 上的Centos ssh工具: Xshell 文件传输: xftp 1.在本地创建asp.net core应用发布 1.1 使用Vs2017 新建 ...

  4. Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践

    原文:Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践 环境 本地 win7 服务器:Virtual Box 上的Centos ssh工具: Xshell 文件传输 ...

  5. node vue 项目部署问题汇总

    场景:vue-router为history模式,不带项目名访问的部署,如果资源是用相对路径加载,则资源匹配路径不对 一.带项目名称访问,如部署到tomcat服务上 webpack:  build/ut ...

  6. Vue项目部署问题及解决方案

    Vue项目部署问题及解决方案 Vue-Router 有两种模式,默认是 hash 模式,另外一种是 history 模式. hash:也就是地址栏里的 # 符号.比如 http://www.examp ...

  7. vue 项目部署

    vue项目部署到PHP项目 入口目录 vue项目打包后, 是一个单文件html 我们只需要把打包后的文件夹放在php项目的public下面 访问 xxx.com/h5/index.html 就可以访问 ...

  8. 阿里云安装Nginx+vue项目部署

    阿里云安装Nginx+vue项目部署 nginx安装包下载 http://nginx.org/en/download.html nginx安装 首先先安装PCRE pcre-devel 和Zlib,因 ...

  9. vue 单文件组件最佳实践

    vue 单文件组件最佳实践 生命周期 template <template> <section> <h1>vue single file components te ...

  10. django项目、vue项目部署云服务器

    目录 上线架构图 服务器购买与远程连接 安装git 安装mysql 安装redis(源码安装) 安装python3.8(源码安装) 安装uwsgi 安装虚拟环境 安装nginx(源码安装) vue项目 ...

随机推荐

  1. Scrapy爬虫文件代码基本认识和细节解释

    import scrapy from scrapy.http.request import Request from scrapy.http.response.html import HtmlResp ...

  2. Python 潮流周刊第 32 期(摘要)

    本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...

  3. TypeScript Vs JavaScript 区别

    一.观察 1. JS 平常的复制类型 let val; val = 123; val = "123"; val = true; val = [1, 3, 5]; 注意点: 由于JS ...

  4. 『Flutter』开篇

    什么是 Flutter Flutter 是由 Google 开发的开源框架 Flutter 用于构建跨平台的移动应用程序 Flutter 它允许开发者使用同一套代码来同时为 IOS 和 Android ...

  5. 【开源项目推荐】Great Expectations—开源的数据质量工具

    大家好,我是独孤风. 又到了本周的开源项目推荐.数据质量是企业进行数据治理非常重要的一个环节,高质量的数据对管理决策,业务支撑都有非常重要的作用. 只有持续的数据质量改进才能推动数据治理体系的完善,差 ...

  6. C#中对比两个对象是否相等最佳实践,IEquatable和IEqualityComparer的差异

    前言 IEquatable<T> IEqualityComparer<T> 后言 参考 前言 IEquatable<T> 和 IEqualityComparer&l ...

  7. Python中的@abstractmethod

      @abstractmethod 是 Python 中 abc 模块(Abstract Base Classes)提供的一个装饰器,用于声明抽象方法.抽象方法是指在抽象类中声明但没有提供具体实现的方 ...

  8. openGauss数据库在CentOS上的安装实践

    本文分享自华为云社区<openGauss数据库在CentOS上的安装实践>,作者:Gauss小松鼠 . 1.安装前准备 安装数据库前先要有已安装centOS 7.6的服务器+数据库安装包. ...

  9. 论文复现丨基于ModelArts进行图像风格化绘画

    摘要:这个 notebook 基于论文「Stylized Neural Painting, arXiv:2011.08114.」提供了最基本的「图片生成绘画」变换的可复现例子. 本文分享自华为云社区& ...

  10. 一文详解什么是可解释AI

    摘要:本文带来什么是可解释AI,如何使用可解释AI能力来更好理解图片分类模型的预测结果,获取作为分类预测依据的关键特征区域,从而判断得到分类结果的合理性和正确性,加速模型调优. 1. 为什么需要可解释 ...