之前做完的一个项目,业务逻辑写完之后,首屏渲染能到3~4秒,这对于用户体验是不能接受的,所以忙里偷闲把项目优化完之后:
http发送到响应时间:705ms,DOM构建完毕:452ms,页面加载完毕:678ms,清爽的感觉很上头~看来优化还是很有必要的!所以本篇记录一下优化过程。
正文
-
UglifyJsPlugin
UglifyJsPlugin
是一个webpack的解析、混淆、压缩JS的工具,低版本的UglifyJsPlugin
是不支持ES6的,所以在使用的时候要注意要么升级版本,要么添加文件.bablelrc
,在里面添加{ "pressets": ["es2015"] }
-
cdn
cdn
的话,尽可能把所有资源都使用cdn,比如vue
,vuex
,vue-router
,axios
,echart
,举个例子:// cdn链接 const cdn = { externals: { echarts: "echarts", "ant-design-vue": "AntDesignVue", vue: "Vue", "vue-router": "VueRouter", vuex: "Vuex", axios: "axios" }, // cdn的css链接 css: [], // cdn的js链接 js: [ "https://cdn.jsdelivr.net/npm/echarts@4/dist/echarts.min.js", "https://cdn.bootcss.com/vue/2.6.10/vue.min.js", "https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js", "https://cdn.bootcss.com/vue-router/3.0.7/vue-router.min.js", "https://cdn.bootcss.com/axios/0.18.0/axios.min.js" ] };
然后在两个地方使用,一个是webpack的
chainWebpack
配置,一个是configureWebpack
的配置:// 是否为生产环境 const isProduction = process.env.NODE_ENV !== "development"; // 本地环境是否需要使用cdn const devNeedCdn = true; module.exports = { // webpack 配置 chainWebpack: config => { // ... config.plugin("html").tap(args => { // 生产环境或者本地需要cdn时,才注入cdn if (isProduction || devNeedCdn) args[0].cdn = cdn; return args; }); }, configureWebpack: config => { // 用cdn方式引入,则构建时要忽略相关资源 if (isProduction || devNeedCdn) config.externals = cdn.externals; } }
这样
cdn
就配置好了,如果想在开发环境也使用它的话,需要在入口文件index.html
中把CSS和JS的资源加载改成:<!-- 使用CDN的CSS文件 --> <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %> <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet" /> <% } %> <!-- 使用CDN的JS文件 --> <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %> <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script> <% } %>
相当于动态加载了webpack配置里的cdn文件。
-
CompressionWebpackPlugin
CompressionWebpackPlugin
是webpack的Gzip
压缩插件,官方介绍是:提供带 Content-Encoding 编码的压缩版的资源,下面是它的配置项:配置项 类型 默认值 描述 test {RegExp} . 处理所有匹配此 {RegExp} 的资源 asset {String} [path].gz[query] 目标资源名称。[file] 会被替换成原资源。[path] 会被替换成原资源路径, [query] 替换成原查询字符串 filename {Function} false 一个 (asset) => asset 函数,接收原资源名(通过 asset 选项)返回新资源名 algorithm {String|Function} gzip 可以是 (buffer, cb) => cb(buffer) 或者是使用 zlib 里面的算法的 {String} threshold {Number} 0 只处理比这个值大的资源。按字节计算 minRatio {Number} 0.8 只有压缩率比这个值小的资源才会被处理 deleteOriginalAssets {Boolean} false 是否删除原资源 这边我用了网上大家常用的配置:
configureWebpack: config => { const productionGzipExtensions = ["html", "js", "css"]; config.plugins.push( new CompressionWebpackPlugin({ filename: "[path].gz[query]", algorithm: "gzip", test: new RegExp("\\.(" + productionGzipExtensions.join("|") + ")$"), threshold: 10240, // 只有大小大于该值的资源会被处理 10240 minRatio: 0.8, // 只有压缩率小于这个值的资源才会被处理 deleteOriginalAssets: false // 删除原文件 }) ); }
注意,如果使用
Gzip
的话,打包后会出现一个x.gz
文件,比如 index.html,打包后会多一个index.html.gz
文件,如果服务器端(nginx等)不开启gzip
功能,加载的其实还是 index.html,开启之后就会加载index.html.gz
来替代加载 index.html了。在 nginx 中可以这么配置(nginx.conf):
#gzip on; # 开启gzip gzip on; # 启用gzip压缩的最小文件,小于设置值的文件将不会压缩 gzip_min_length 1k; # gzip 压缩级别,1-9,数字越大压缩的越好,也越占用CPU时间,后面会有详细说明 gzip_comp_level 2; # 进行压缩的文件类型。javascript有多种形式,后面的图片压缩不需要的可以自行删除 gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript ; # 是否在http header中添加Vary: Accept-Encoding,建议开启 gzip_vary on; # 设置压缩所需要的缓冲区大小 gzip_buffers 4 16k;
重启之后查看请求接口的响应头的
Content-Encoding
是gzip
的话说明开启成功。 -
moment
由于用到了
moment
,所以也得把它压缩一下,它可是贼大的,因为它的npm包里加载了很多的语言版本,所以一般情况下,只需要中文版就可以了,所以在webpack的配置里,把moment的语言包给忽略掉,然后在 main.js 中加载一个语言包import "moment/locale/zh-cn"
,这样体积就会小很多。 -
splitChunks
splitChunks
可以对大包进行拆分,对小包进行合并,防止模块重复打包,从而减少请求资源的大小和此时,这个要根据实际情况去调整。 -
代码逻辑
加了以上的操作之后,可以使用插件
webpack-bundle-analyzer
来看下优化的效果,如果还有大块的,就把业务继续优化,主要从引用、封装入手,能抽出来的尽量抽出来,把工具和业务分开。以vue为例的话,可以注意以下几点:-
v-if 和 v-show
v-if 适合条件改变很少的情况,v-show 适合频繁切换条件的情况
-
computed 和 watch
computed 适合在计算和依赖场景使用,watch 适合数据变化的异步操作
-
v-for 必须添加 key
vue的 diff 算法会关联到 key,所以当状态更新时,key的作用很大,为了优化效率,建议添加key(现在开发工具已经做了提醒)
-
v-for 里不使用 v-if
v-for 的优先级要比 v-if 高,如果vue的循环节点每次都重新遍历整个数组,就需要花很多时间
-
event
在页面上使用了事件之后,离开的时候最好把事件给销毁(全局除外),可以防止内存泄漏(比如图表的加载和重绘)
-
图片懒加载
图片资源懒加载可以使用
vue-lazyload
插件,保证只加可视区域内的图片 -
路由懒加载
如果不用路由懒加载的话,页面访问就会把所有路由都加载完毕之后再加载,如果资源过多,白屏的出现几率就会大大增加,所以路由要改成只在访问的时候加载:
component: () => import("./views/Login.vue")
-
三方插件按需引入
很多三方插件包很大,所以它们大部分也都给了按需加载的使用说明
-
防抖和节流
对于触发事件的时间和时机判定,防止用户频繁点击和误操作,它们两个也算优化的一部分
-
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!