前言Vue框架通过双向数据绑定和虚拟DOM技术帮助我们处理前端开发中DOM操作中最脏最累的部分。我们不再需要考虑如何操作DOM,如何做到最高效,但是Vue项目中还存在项目首屏优化、Webpack编译配置优化等问题,所以还是需要关注的性能优化Vue项目使项目具有更高效的性能和更好的用户体验。本文是笔者通过实际项目的优化实践总结出来的。希望读者看完这篇文章后,能有所启发和思考,从而有助于优化自己的项目。本文内容分为以下三个部分:Vue代码层面的优化;webpack配置级别的优化;在基本网络技术层面进行优化。辛苦了好久,还是希望手动点赞鼓励一下~github地址:https://github.com/fengshi123/blog,汇总了作者所有的博客,欢迎关注和star~1.代码层面的优化1.1,v-if和v-show区分使用场景v-if是true条件渲染,因为它会保证条件块内的事件监听器和子组件在切换的过程中被适当的销毁和重新创建;也很懒惰:如果在初始渲染时如果条件为假,则什么也不做-条件块在条件第一次变为真之前不会开始渲染。v-show更简单,无论初始条件如何,元素始终呈现,并且根据CSS显示属性简单地切换。因此,v-if适用于运行时很少改变条件,不需要频繁切换条件的场景;v-show适用于需要非常频繁切换条件的场景。1.2、computed和watch区分使用场景computed:是一个computed属性,依赖于其他属性值,并且computed的值被缓存起来,只有当它所依赖的属性的值发生变化时,computed的值才会被重新计算下一次获得计算值的时间;watch:更多的是一个“观察”的功能,类似于一些数据的监听回调。每当监控到的数据发生变化时,都会执行回调,进行后续操作;应用场景:当我们需要进行数值计算,依赖其他数据时,使用computed时,应该使用computed,因为可以利用computed的缓存特性,避免每次取到值都重新计算;当您需要在数据更改时执行异步或昂贵的操作时,您应该使用watch,使用watch选项允许我们执行异步操作(访问API),限制我们执行该操作的频率,并设置中间状态直到我们得到最后的结果。这些是计算属性不能做的事情。1.3.v-for遍历必须给item加key,避免同时使用v-if(1)v-for遍历必须给item加key。在遍历和渲染列表数据时,需要为每一项设置一个唯一的键值。方便Vue.js内部机制准确查找列表数据。状态更新时,将新状态值与旧状态值进行比较,快速定位差异。(2)v-for遍历避免同时使用v-if。v-for比v-if有更高的优先级。如果每次都需要遍历整个数组,会影响速度,尤其是需要渲染一小部分的时候。case应替换为计算属性。推荐:
计算:{activeUsers:function(){returnthis.users.filter(function(user){returnuser.isActive})}}不推荐复制代码:
复制代码1.4,长列表性能优化Vue会通过Object.defineProperty劫持数据,实现视图响应数据的变化,但是有时候我们的组件是纯数据展示,会有没有变化,我们不需要Vue来劫持我们的数据,在大量数据展示的情况下,这样可以显着减少组件的初始化时间,那么如何防止Vue劫持我们的数据呢?可以通过Object.freeze方法冻结对象。一旦对象被冻结,它就不能再被修改。exportdefault{data:()=>({users:{}}),asynccreated(){constusers=awaitaxios.get("/api/users");this.users=Object.freeze(users);}};复制代码1.5、事件销毁当一个Vue组件被销毁时,会自动清理它与其他实例的连接,解绑它所有的指令和事件监听器,但仅限于组件本身的事件。如果在js中使用addEventListene等方法,是不会自动销毁的。我们需要在组件销毁时手动移除这些事件的监听器,以免造成内存泄漏,如:created(){addEventListener('click',this.click,false)},beforeDestroy(){removeEventListener('click',this.click,false)}复制代码1.6。图片资源的延迟加载对于图片过多的页面,为了加快页面加载速度,我们往往需要添加不在可见区域的图片先不加载,滚动到可见区域后才加载.这将大大提高页面加载性能,改善用户体验。我们在项目中使用Vue的vue-lazyload插件:(1)安装插件npminstallvue-lazyload--save-dev复制代码(2)在入口文件man.js中引入,使用importVueLazyloadfrom'vue-lazyload'复制代码然后在vue中直接使用Vue.use(VueLazyload)复制代码或者添加自定义选项Vue.use(VueLazyload,{preLoad:1.3,error:'dist/error.png',loading:'dist/loading.gif',attempt:1})复制代码(3)在vue文件中直接将img标签的src属性改为v-lazy,从而将图片显示方式改为懒加载显示:
复制代码以上就是vue-lazyload插件的简单使用。如果想查看插件的更多参数选项,可以查看vue-lazyload的github地址。1.7.路由的延迟加载Vue是一个单页面应用,引入的路由可能很多。这样用webpcak打包出来的文件就很大了。进入首页时加载过多资源,页面会出现白屏,不利于用户体验。如果我们能把不同路由对应的组件分成不同的代码块,然后在路由访问时加载相应的组件,效率会更高。这样会大大提高首屏显示的速度,但其他页面的速度可能会变慢。路由懒加载:constFoo=()=>import('./Foo.vue')constrouter=newVueRouter({routes:[{path:'/foo',component:Foo}]})复制代码1.8,第三方插件按需引入我们在项目中经常需要引入第三方插件。如果我们直接导入整个插件,工程量会太大。我们可以使用babel-plugin-component,然后只引入需要的组件就可以达到降低项目体积的目的。下面是在项目中引入element-ui组件库的例子:(1)首先安装babel-plugin-component:npminstallbabel-plugin-component-D复制代码(2)然后,修改.babelrc为:{“预设”:[[“es2015”,{“模块”:false}]],“插件”:[[“组件”,{“libraryName”:“element-ui”,“styleLibraryName”:“主题粉笔”}]]}复制代码(3)在main.js中引入一些组件:importVuefrom'vue';import{Button,Select}from'element-ui';Vue.use(Button)Vue.use(Select)复制代码1.9、无限优化列表性能如果你的应用程序有一个很长或无限滚动的列表,你需要使用窗口技??术来优化性能。只需要渲染一小部分区域的内容,减少重新渲染组件和创建dom节点的时间。可以参考以下开源项目vue-virtual-scroll-list和vue-virtual-scroller来优化这种无限列表场景。1.10.服务端渲染SSR或预渲染服务端渲染是指Vue在客户端将标签渲染成整个html片段,在服务端完成工作。服务器端形成的html片段直接返回给客户端。这个过程称为服务器端渲染。(1)服务端渲染的优点:更好的SEO:因为SPA页面的内容是通过Ajax获取的,而搜索引擎爬取工具不会等待Ajax异步完成后再爬取页面内容,所以在SPA中是的无法获取页面通过Ajax获取的内容;而SSR直接从服务器返回渲染后的页面(数据已经包含在页面中),所以搜索引擎爬虫工具可以爬取渲染后的页面;内容到达时间更快(首屏加载速度更快):SPA会等待所有Vue编译的js文件下载完毕,然后才开始渲染页面。文件下载需要一定的时间,所以首屏渲染需要一定的时间;SSR由服务器直接渲染返回直接显示,无需等待下载js文件再次渲染,所以SSR有一个更快的内容到达时间;(2)服务端渲染的缺点:更多的开发条件限制:比如服务端渲染只支持beforCreate和created两个钩子函数,这会导致一些外部扩展库需要特殊处理才能在服务端渲染中运行申请;而它是完全静态的单页,可以部署在任何静态文件服务器上,与应用SPA不同。服务端渲染应用需要在Node.js服务端运行环境;更高的服务器负载:在Node.js中渲染一个完整的应用程序显然会比仅提供静态文件资源的服务器消耗大量的CPU,因此如果您预计高流量使用,请准备相应的服务器负载并明智地使用缓存策略。如果你的项目的SEO和首屏渲染是评估项目的关键指标,那么你的项目就需要服务端渲染来帮助你达到最佳的初始加载性能和SEO。具体如何实现VueSSR,可以参考作者的另一篇文章《Vue SSR 踩坑之旅》。如果你的Vue项目只需要改进几个营销页面(例如/、/about、/contact等)的SEO,那么你可能想要预渲染,它只是在构建时为特定路由生成静态HTML文件。优点是更容易设置预呈现,并且您可以将前端用作完全静态的站点。具体来说,您可以使用prerender-spa-plugin轻松添加预渲染。2.Webpack层面的优化2.1.Webpack压缩图像。在vue项目中,除了在webpack.base.conf.js中的url-loader中设置limitsize来处理图片外,将小于limit的图片转成base64格式。其余的什么都不做。所以对于一些比较大的图片资源,在请求资源的时候,加载会很慢,我们可以使用image-webpack-loader来压缩图片:(1)首先,安装image-webpack-loader:npminstallimage-webpack-loader--save-dev复制代码(2)然后,在webpack.base.conf.js中配置:{test:/\.(png|jpe?g|gif|svg)(\?.*)?$/,使用:[{loader:'url-loader',options:{limit:10000,name:utils.assetsPath('img/[name].[hash:7].[ext]')}},{loader:'image-webpack-loader',options:{bypassOnDebug:true,}}]}复制代码2.2,减少ES6到ES5的冗余代码Babel插件在ES6代码转ES5代码时会注入一些辅助函数,比如下面的ES6代码:classHelloWebpackextendsComponent{...}复制代码这段代码在转换成可以正常运行的ES5代码时需要以下两个辅助函数:babel-runtime/helpers/createClass//用于实现类语法babel-runtime/helpers/inherits//用于实现extends语法复制代码。默认情况下,Babel会在每个输出文件中嵌入这些依赖的辅助函数代码。如果多个源代码文件都依赖这些辅助函数,那么这些辅助函数的代码就会出现很多次,造成代码冗余。为了防止这些辅助功能的代码重复出现,可以在依赖的时候通过require('babel-runtime/helpers/createClass')导入,让它们只出现一次。babel-plugin-transform-runtime插件就是用来实现这个功能的,将相关的辅助功能替换成import语句,从而减少babel编译后代码的文件大小。(1)首先,安装babel-plugin-transform-runtime:npminstallbabel-plugin-transform-runtime--save-dev复制代码(2)然后,修改.babelrc配置文件为:"plugins":["transform-runtime"]复制代码如果想查看插件的更多详细信息,可以查看babel-plugin-transform-runtime的详细介绍。2.3.提取公共代码如果项目中没有提取第三方库和各个页面的公共模块,项目会存在以下问题:重复加载相同的资源,浪费用户流量和服务器成本。每个页面需要加载的资源过多,导致网页首屏加载缓慢,影响用户体验。所以我们需要将多个页面的公共代码分离到单独的文件中来优化上述问题。Webpack内置了一个CommonsChunkPlugin插件,专门用于提取多个Chunk的公共部分。我们在项目中对CommonsChunkPlugin的配置如下://所有依赖package.json的包都会被打包到文件vendor.js中。newwebpack.optimize.CommonsChunkPlugin({name:'vendor',minChunks:function(module,count){return(module.resource&&/\.js$/.test(module.resource)&&module.resource.indexOf(path.join(__dirname,'../node_modules'))===0);}}),//提取代码模块的映射关系newwebpack.optimize.CommonsChunkPlugin({name:'manifest',chunks:['vendor']})复制代码如果想查看插件的更多详细信息,可以查看CommonsChunkPlugin的详细介绍。2.4.模板预编译当在DOM中使用模板或在JavaScript中使用字符串模板时,模板会在运行时被编译成渲染函数。通常这个过程足够快,但最好避免对性能敏感的应用程序使用这种方法。预编译模板最简单的方法是使用单文件组件-相关的构建设置将自动处理预编译,因此构建的代码已经包含编译后的渲染函数而不是原始模板字符串。如果你使用webpack并且喜欢将JavaScript和模板文件分开,你可以使用vue-template-loader,它也会在构建过程中将模板文件转换为JavaScript渲染函数。2.5.ExtractcomponentCSS在使用单文件组件时,组件中的CSS会通过JavaScript以style标签的形式动态注入。这有一个小的运行时开销,如果您使用服务器端渲染,这可能会导致“无样式内容闪烁(fouc)”。将所有组件的CSS提取到同一个文件中可以避免这个问题,还可以更好地压缩和缓存CSS。参考这个构建工具各自的文档了解更多:webpack+vue-loader(已经预配置了vue-cli的webpack模板)Browserify+vueifyRollup+rollup-plugin-vue2.6,优化SourceMap后项目package,将开发中的多个文件的代码打包成一个文件,经过压缩,去掉多余的空格,用babel编译,编译后的代码用于线上环境,然后处理后的代码和源码非常不一样。当出现bug时,我们只能定位到压缩代码所在的位置,而无法定位到开发环境中的代码。定位问题开发不好调试,所以sourceMap的出现,就是为了解决代码调试不好的问题。SourceMap的可选值如下(+号越多速度越快,-号越多速度越慢,o代表中等速度)1.png开发环境推荐:cheap-module-eval-source-map生产环境推荐:cheap-module-source-map原因如下:cheap:源代码中的column信息没有作用,所以我们不想在打包文件中包含column相关的信息,只有行信息才能建立打包前后的依赖关系。因此,无论是开发环境还是生产环境,我们都希望添加廉价的基本类型来忽略打包前后的列信息;module:无论是开发环境还是正式环境,我们都希望定位到bug源码的具体位置,比如说某个vue文件报错,我们希望定位到具体的vue文件,所以我们还需要模块配置;soure-map:source-map会为每个打包的模块生成一个独立的sourcemap文件,所以我们需要添加source-map属性;eval-source-map:eval打包代码非常快,因为它不生成map文件,但是可以结合eval使用eval-source-map,将js文件打包后的map文件以DataURL的形式存储。生产环境中不要使用eval-source-map,因为会增加文件大小,但是在开发环境中,可以试试,因为它们打包的速度非常快。2.7.构建结果输出分析Webpack输出的代码可读性非常差,文件非常大,让我们很头疼。为了更简单直观地分析输出结果,社区中出现了很多可视化分析工具。这些工具以图形化的方式更直观地展示结果,让我们能够快速了解??问题所在。下面就来讲解下我们在Vue项目中使用的分析工具:webpack-bundle-analyzer。我们在项目中配置webpack.prod.conf.js:if(config.build.bundleAnalyzerReport){varBundleAnalyzerPlugin=require('webpack-bundle-analyzer').BundleAnalyzerPlugin;webpackConfig.plugins.push(newBundleAnalyzerPlugin());}复制代码并执行$npmrunbuild\--report生成分析报告如下:1.png2.8、Vue项目的编译优化如果你的Vue项目是用Webpack编译的,喝杯咖啡的时间很花,那么也许你需要对项目的Webpack配置进行优化,提高Webpack的构建效率。关于如何优化Vue项目的Webpack构建,可以参考作者的另一篇文章《 Vue 项目 Webpack 优化实践》3。基础Web技术优化3.1.启用gzip压缩Gzip是GNUzip的缩写,最早用于UNIX系统的文件压缩。HTTP协议上的gzip编码是一种用来提高web应用性能的技术,web服务器和客户端(浏览器)都必须支持gzip。目前主流的浏览器,如Chrome、firefox、IE都支持该协议。Apache、Nginx、IIS等常见服务器也支持。Gzip压缩效率非常高,通常可以达到70%的压缩率。也就是说,如果你的网页有30K,压缩后会变成9K左右以客户端熟悉的express为例,启用gzip非常简单,相关步骤如下:安装:npminstallcompression--保存复制代码,添加代码逻辑:varcompression=require('compression');varapp=express();app.use(compression())复制代码重启服务,观察网络面板中的响应头,如果你看到下面红圈中的字段,就说明gzip启用成功:1.png3.2、浏览器缓存为了提高用户加载页面的速度,静态缓存资源是非常有必要的。根据是否需要向服务器重新发起请求来分类,HTTP缓存规则分为两类(强制缓存、对比缓存)。如果对缓存机制还不是很清楚,可以参考作者本人写的一篇关于HTTP缓存的文章《深入理解HTTP缓存机制及原理》,这里不再赘述。3.3.使用CDN时,浏览器从服务器下载CSS、js、图片等文件时,必须连接到服务器,而大多数服务器的带宽是有限的。如果超过限制,网页将长时间无法响应。并且CDN可以通过不同的域名来加载文件,这样下载文件的并发连接数大大增加,CDN的可用性更好,网络延迟和丢包率更低。3.4.使用ChromePerformance寻找性能瓶颈Chrome的Performance面板可以记录一段时间内的js执行细节和时间。使用Chrome开发者工具分析页面性能的步骤如下。打开Chrome开发者工具,切换到Performance面板点击Record开始录制刷新页面或展开节点点击Stop停止录制1.png有关Performance的更多信息,请单击此处。总结本文由以下三部分组成:Vue代码层面的优化、webpack配置层面的优化、Web基础技术层面的优化;介绍如何优化Vue项目的性能。希望阅读本文后对您有所帮助和启发。