前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >vue项目部署的最佳实践

vue项目部署的最佳实践

作者头像
winty
发布于 2020-07-15 07:34:23
发布于 2020-07-15 07:34:23
1.7K00
代码可运行
举报
文章被收录于专栏:前端Q前端Q
运行总次数:0
代码可运行

前言

使用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:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Caching_FAQ):

  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文件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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模块):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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: , //对超过10k的数据进行压缩
            minRatio: 0.6 // 压缩比例,值为0 ~ 1
          })
        ]
      };
    }
  }
};

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

字体文件是否需要gzip

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@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模块:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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并不是很熟悉,有什么问题和错误,欢迎指出!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-07-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端Q 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
雅虎优化最佳实践
毕竟对于前端来说,优化是躲不开的主题。在看200(cache)和304区别的时候,翻到了雅虎这边归纳出来的准则,虽然是十多年前的东西了吧,但是还是具有参考价值的,因此在原文基础上我进行了一些归纳翻译。
全栈程序员站长
2022/09/14
1.5K0
前端性能优化之gzip
HTTP 可以对传输的内容进行压缩,减少网络实际传输数据的大小。服务器会将资源进行压缩后传输到客户端,浏览器收到文件后进行解析。对于纯文本文件可以压缩到之前大小的30%-40%,大大提高了传输效率。
can4hou6joeng4
2023/11/29
4360
前端缓存最佳实践
在介绍缓存的时候,我们习惯将缓存分为强缓存和协商缓存两种。两者的主要区别是使用本地缓存的时候,是否需要向服务器验证本地缓存是否依旧有效。顾名思义,协商缓存,就是需要和服务器进行协商,最终确定是否使用本地缓存。
小生方勤
2019/06/03
1.1K1
Nginx 静态资源部署
上网去搜索访问资源对于我们来说并不陌生,通过浏览器发送一个 HTTP 请求实现从客户端发送请求到服务器端获取所需要内容后并把内容回显展示在页面的一个过程。这个时候,我们所请求的内容就分为两种类型,一类是静态资源、一类是动态资源。
用户9615083
2022/12/25
5.6K0
Nginx 静态资源部署
nginx开启gzip压缩
nginx对于静态文件的处理模块 该模块可以读取预先压缩的gz文件,这样可以减少每次请求进行gzip压缩的CPU资源消耗。该模块启用后,nginx首先检查是否存在请求静态文件的gz结尾的文件,如果有则直接返回该gz文件内容。为了要兼容不支持gzip的浏览器,启用gzip_static模块就必须同时保留原始静态文件和gz文件。这样的话,在有大量静态文件的情况下,将会大大增加磁盘空间。我们可以利用nginx的反向代理功能实现只保留gz文件。
无道
2021/06/29
2.2K0
Nginx学习实践&总结
Nginx 是一个异步框架的 Web 服务器,也可以用作反向代理,负载平衡器 和 HTTP 缓存。
不愿意做鱼的小鲸鱼
2022/09/26
4850
Nginx学习实践&总结
SSR React同构渲染改造
SSR(Server Side Rendering),顾名思义英文单词翻译过来就是服务端渲染,约在十年前左右,服务端渲染主要是由后端人员来主持改造,前端提供页面模板,后端在模板中填充页面相关的数据然后直接以整个html的形式返回给用户浏览器进行展示,由于在填充数据时已经将原有javascript的功能直接在后端实现,所以在服务器性能比较稳定的前提下,用户侧可以很快看到整个完整页面加载出来,使用体验很好,加之搜索引擎都是基于爬虫来进行收录,服务端渲染对于SEO会有非常好的效果。
lealc
2024/01/12
5570
SSR React同构渲染改造
网站 cache control 最佳实践
通常,是因为 cache control 缓存控制策略定义不正确,导致服务端最新部署之后客户端没有接收到最新的更改。
dys
2020/02/12
1.5K0
网站 cache control 最佳实践
008.Nginx静态资源
Nginx作为静态资源Web服务器部署配置, 传输非常高效, 常常用于静态资源处理,请求以及动静分离。通常非服务器动态运行生成的文件属于静态资源。
木二
2020/07/16
1.4K0
前端 Web 开发常见问题概述
以下列举的,都是 JS 前端开发中最为常见的问题。知悉这些问题,不懂编程也能冒充前端大牛了。
LIYI
2019/09/02
1.4K0
前端 Web 开发常见问题概述
Nginx结构全解析(21)
1.全局块:配置影响nginx全局的指令。一般有运行nginx服务器的用户组,nginx进程pid存放路径,日志存放路径,配置文件引入,允许生成worker process数等。
陈不成i
2021/05/12
5890
「简明性能优化」双端开启Gzip指南
在 http/1.0 协议中关于服务端发送的数据可以配置一个 Content-Encoding 字段,这个字段用于说明数据的压缩方法
前端劝退师
2019/09/17
1.6K0
「简明性能优化」双端开启Gzip指南
前端性能优化总结
生产环境中,不需要打印日志。通过对webpack进行配置,打包时自动去掉console.log
前端进击者
2021/07/27
6320
前端缓存那些事
Cache-Control 比Expires比较要内涵,具备更多的属性,其中包括如下
树酱
2020/07/03
8060
前端缓存那些事
Nginx 从入门到实践,万字详解!
这篇文章会在 CentOS 环境下安装和使用 Nginx,如果对 CentOS 基本操作还不太清楚的,可以先看看 <半小时搞会 CentOS 入门必备基础知识> 一文先做了解。
前端下午茶
2020/04/30
1.4K0
Nginx下关于缓存控制字段cache-control的配置说明 - 运维小结
HTTP协议的Cache -Control指定请求和响应遵循的缓存机制。在请求消息或响应消息中设置 Cache-Control并不会影响另一个消息处理过程中的缓存处理过程。 请求时的缓存指令包括: no-cache、no-store、max-age、 max-stale、min-fresh、only-if-cached等。 响应消息中的指令包括: public、private、no-cache、no- store、no-transform、must-revalidate、proxy-revalidate、max-age。
洗尽了浮华
2019/05/25
8.9K0
鹅厂原创 | Web前端踩坑记--静态资源优化总结
文/pecliu 腾讯S1规划设计部——应用开发 工程师 0写在前面 此文总结了近期参与的几个项目, 在Web静态资源方面的一些优化的点。 (左右滑动查看代码) 1如何优化 用户在访问网页时, 最直观的感受就是页面内容出来的速度,我们要做的优化工作, 也主要是为了这个目标。那么为了提高页面加载(或者渲染)速度呢?一般来说有三个方面: 代码逻辑:优秀的代码逻辑结构可以有效减少渲染页面使用的内存和速度(比如虚拟DOM),此方面不在本文讨论范围内。 SSR服务器渲染,也就是所谓的“直出”。将首屏所有内容在服务器端
用户1097444
2022/06/29
4790
鹅厂原创 | Web前端踩坑记--静态资源优化总结
Nginx---静态资源处理
前面我们已经对Nginx服务器默认配置文件的结构和涉及的基本指令做了详细的阐述。通过这些指令的合理配置,我们就可以让一台Nginx服务器正常工作,并且提供基本的web服务器功能。
大忽悠爱学习
2021/12/08
2.7K0
Nginx---静态资源处理
网站性能优化实战——从12.67s到1.06s的故事
网站性能监测与优化策略 0.引言 作为互联网项目,最重要的便是用户体验。在举国“互联网+”的热潮中,用户至上也已经被大多数企业所接收,特别是在如今移动端快速发展的时代,我们的网页不仅只是呈现在用户的PC浏览器里,更多的时候,用户是通过移动产品浏览我们的网页。加之有越来越多的开发者投入到Web APP和Hybrid APP的开发队伍中,性能,又再一次成为了被程序员们重点关注的话题。我曾经看到过这样一句话:一个网站的体验,决定了用户是否愿意去了解网站的功能;而网站的功能,决定了用户是否会一票否决网站的
Java高级架构
2018/07/20
1.1K0
Nginx之gzip模块解读
gzip是GNUzip的缩写,最早用于UNIX系统的文件压缩。HTTP协议上的gzip编码是一种用来改进web应用程序性能的技术,web服务器和客户端(浏览器)必须共同支持gzip。目前主流的浏览器,Chrome,firefox,IE等都支持该协议。常见的服务器如Apache,Nginx,IIS同样支持gzip。
一个风轻云淡
2023/09/23
7470
相关推荐
雅虎优化最佳实践
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文