使用vue
、react
、angular
等技术开发过程中,我们都会遇到以下问题:
这两个问题可以从很多方面进行优化,今天我就从前端页面部署阶段来优化一下这两个问题。PS:以下内容都基于vue-cli3+
。
vue-cli3
打包说起路由使用按需加载后,打包生成的文件,每一个路由页面都对应一个js
和css
文件,入口main.js
及其依赖则打包成了app.js
和app.css
,公共依赖都放到了chunk-vendors.js
。
vue-cli3
打包后的dist/js
文件夹:
可以看到,打包生成的js/css/img
等文件的文件名都带有hash
值,当源文件内容改变时,重新打包后对应的文件hash
值也会改变。举个栗子,我们修改了about.vue
中js
的内容,重新打包时about.js
的hash
值会改变,以及依赖about.vue
的文件app.js
的hash
值也会改变,而其他没有修改的文件,打包后的hash
值都不会改变。
我们知道,文件名带hash
是为了消除缓存带来的影响的,但是所有文件都不缓存肯定不是一个很好的解决方案。
vue-cli3
打包生成的文件名带hash
值的作用我们先来简单回顾下http
缓存的知识(参考MDN:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Caching_FAQ):
HTTP1.0
是通过Expires
(文件过期时间)和Last-Modified
(最近修改时间)来告诉浏览器进行缓存的,这两个字段都是 UTC
时间(绝对时间)。Expires
过期控制不稳定,因为浏览器端可以随意修改本地时间,导致缓存使用不精准。而且 Last-Modified
过期时间只能精确到秒。HTTP1.1
通过Cache-Contorl
和 Etag
(版本号)进行缓存控制。浏览器先检查 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-Contorl
和Etag
配合就好了。
那么问题来了,检查文件是否最新不是用etag
吗,为什么文件名还需要有hash
值?
(1)如果文件名不带hash
值,文件版本得用etag
来标记,浏览器需要先去检查下是否过期,服务器则需要检查文件是否最新。
(2)而文件名带有hash
值,可以直接将文件的过期时间设置为1年,浏览器就不用检查是否过期,直接使用。
原因是,如果页面源文件有修改,生成的js/css
的hash
值就会修改,对应的请求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
值的
如下图所示,虽然是按需加载,但是感觉浪费服务器请求
这时,我们可以配置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
的(即css
、js
、font
和img
目录下的所有文件)设置一个月缓存,浏览器可以直接使用缓存不需要请求服务器。其他的文件(index.html
和static
目录下的文件)设置为no-cache
,即每次都来服务器检查是否最新。
为什么缓存时间是一个月,刚才不是说设置一年?设置为一年,当然没有任何问题。不变的文件可以一直使用,有改动的文件,会重新请求,但是有该动的旧文件已经没有用了,由于过期时间是一年,所以不会被删的,一直占用用户的硬盘,系统更新越频繁,无用旧文件越多,占用的存储也越多,这样是不好的(用户看了想打人)。所以设置一个合理的时间比较好,一个月就挺好。
废话不说,以Nginx
服务器为例,配置如下(配置文件nginx.conf
的http
模块):
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
2.调试的时候记得允许缓存
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
)、png
、gif
、webp
,这些格式的图片本身已经优化了,所以不再需要gzip
。实际上对图片进行gzip
压缩,不仅没有效果,反而可能使图片体积更大。那么字体文件呢,是不是和图片一样?
从阿里巴巴矢量图库生成的图标字体的css
中我们可以看出,一般常见的字体文件有:eot
、woff
、ttf
、svg
,另外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- */
}
查阅资料后发现:eot
和 ttf
格式一般情况下本身不压缩,也就是说可以进行gzip
压缩。而woff
格式具有内建压缩,不需要gzip
压缩。
实际测试一下,发现eot
和ttf
可以进行压缩,效果还不错,而woff
格式的,CompressionWebpackPlugin
插件根本不支持压缩,即使你写了配置了压缩woff
文件,它也不会生成gz
文件。
并且实验发现,svg
虽然是图片,但是也可以进行gzip
压缩,压缩效果还不错:
结论:svg
、eot
和 ttf
这三种格式的字体文件可以使用CompressionWebpackPlugin
进行压缩,并且配合Nginx
的gzip_types
配置,woff
和woff2
格式的字体文件不需要gzip
。
gzip
压缩Nginx
是前端文件常用的服务器,Nginx
服务器的配置文件nginx.conf
的http
模块:
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
文件),这就很浪费服务器资源了。现在我们已经提供js
和css
的gz
文件,如何判断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.下载windows
下Nginx
的安装包:nginx.org/en/download…
2.解压压缩包
3.在Nginx
的目录下使用cmd
命令行,启动命令:start nginx
,关闭命令:nginx -s stop
备注:修改配置文件需要重载配置:nginx -s reload
。启动之后,打开http://localhost:80
就能看的效果
页面文件合理的设置缓存和gzip
压缩是实实在在能提升用户体验的操作,而且比少写几个循环、删除几行代码优化强得多,但是需要前端和运维的密切配合,才能实现最佳方案。
service worker
是用来实现离线应用的,文章中没有详细赘述。vue-cli4
生成的模板自带service worker
,或许这才是vue
项目缓存的最佳实践?
最后,Nginx
并不是很熟悉,有什么问题和错误,欢迎指出!
本文由哈喽比特于4年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/2YXpQ6GACj1ew42KV-oqHA
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。