猿创征文|Vue前端性能优化方案

目录

1. 概述

2. 性能优化切入点分析

2.1 vue-router

2.2 打包优化

2.3 压缩技术

3. 性能优化实践

3.1 vue-router优化

3.1.1. 异步加载

3.1.2. 按需加载

3.2 打包优化

3.3 前端工程压缩


1. 概述

Web应用的优化方案一般分为两类:第一类是基于硬件的优化,第二类是基于软件的优化。基于硬件的优化主要包括扩大带宽、负载均衡、服务集群等方式,而这些依托于硬件的提升都需要公司去承担巨额的支付成本。较之而言,对软件的优化以及技术的革新更加具有实际意义。一般来说,一个Web网页,不止包含必要的HTML文件,还包含很多其他的相关资源文件,比如CSS文件、JavaScript文件、图像等等,这些文件一起构成了页面组件。通过Web前端构成元素以及请求响应机制的分析,本方案从vue-router优化、打包优化、压缩技术三个方面给出Vue前端性能的优化方案。

2. 性能优化切入点分析

2.1 vue-router

vue-router是Vue官方提供的路由管理器,又称路由懒加载,是指将不同路由所对应的组件划分为不同的代码块,然后只有在访问路由时才会加载相应的组件。这样既可以提高Web项目的加载速度也可以提高页面响应效率。本方案分别从Vue的异步组件和Webpack的代码分割功能两方面对vue-router路由懒加载进行实现。

1. Vue异步组件

在Web应用中,可以将应用分割成比较小的代码块,只在需要的时候从服务器端加载所需模块。Vue为了对代码进行精简,可以让开发者以工厂函数的方式定义组件,而该工厂函数可以异步地对组件定义进行解析。Vue只会在该组件被渲染的时候才去触发该工厂函数,并将结果进行缓存以便将来重新进行渲染。该工厂函数会收到一个resolve回调函数,这个回调函数会在得到服务器命令的时候被调用,也可以调用reject(reason) 方法来表示加载失败。在获取组件的时候,也可以将异步组件和webpack的code-splitting功能一起配合使用,将效果达到最优化。

2. Webpack代码分割

Webpack是当下非常流行的一款代码编译工具,其代码分割功能可以将代码分离到不同的模块中,以便能够并行或按需加载这些模块。进行代码分割不仅可以控制资源加载的优先级,而且还能够获得更小的模块。常见的代码分割方式主要有以下三种:

  1. 入口起点法:即使用Entry配置手动分离代码,这种方式虽然比较直观,但用法不够灵活,而且不能动态地将核心应用程序逻辑中的代码拆分出来。
  2. 防止重复法:使用SplitChunkPlugin插件可以去重合分离chunk,即将公共的依赖模块提取到已有的entry chunk中,或者提取到一个新生成的chunk中。
  3. 动态导入法:通过模块中的内联函数调用分离代码。涉及到动态代码拆分时,Webpack提供了两种方法。第一种是使用通过ECMAScript提案的import()方法来实现动态导入,第二种则是使用Webpack特定的require.ensure()方法。

2.2 打包优化

Web应用打包优化可以优化项目启动速度和性能,进行必要的数据清理,减少打包后的体积。本方案的打包优化思路有以下三点:

  1. 减少预加载、忽略调试代码。
  2. 降低打包后的资源总体积:避免将用不到的资源打包,如三方组件(moment 等)的语言包中用不到的语言资源。
  3. 分包:将公共组件、较大的资源单独打包,减少首屏加载的资源数量。

2.3 压缩技术

Web页面的第一次加载,是在浏览器没有缓存的情况下的,也就是从服务器端通过网络下载到客户端的过程。影响网页加载速度的因素有很多,从硬件上来讲,有服务器端、客户端和网速(带宽)三个方面。硬件因素的改进都是无法简单做到的,可控的因素是减少HTTP请求和减少页面大小。为了减小页面大小,压缩源文件就成了最为重要的一步。几乎所有的Web站点,都会用到JavaScript脚本表和CSS样式表,页面在首次加载的时候,缓存为空,页面中每一个资源文件都要单独进行一次HTTP请求。因此在Web前端开发过程中,为了符合模块化的开发原则,通常会把JavaScript文件和CSS文件各自汇总保存在独立的文件中。除了对相关资源文件进行整合,还应该分别对CSS与JavaScript文件进行压缩,尽量使整个前端页面中的相关文件体积最小化。

3. 性能优化实践

3.1 vue-router优化

3.1.1. 异步加载

vue-router配置访问路由时,组件采用异步加载的方式引入。

推荐的用法:

{
  path: '/flowPublicDetail/:id', 
  name: "flowEformDetail", 
  component:() => import('../pages/system/flowPublicDetail/index.vue'), 
  hidden: true,
  meta: { title: "flowEformDetail" },
},

× 不推荐的用法:

home: { path: '/', component: Home, hidden: true },
login: { path: '/user/login', component: Login, hidden: true },

3.1.2. 按需加载

1. 按需加载非全局使用的组件库,须组件库支持。

推荐的用法:

import { Row, Col } from 'ant-design-vue';
import { AvicLayout } from "avic-foundation/es/layout";

× 不推荐的用法:

import Antd from 'ant-design-vue'

2. 避免在入口文件 main.js 中全局注册三方组件、组件库,需要的组件、组件库应在具体业务模块引入。

推荐的用法:

// 业务模块
import Button from 'ant-design-vue/lib/button'; 
import 'ant-design-vue/lib/button/style';
// 或者 ant-design-vue/lib/button/style/css  // 加载 css 文件

× 不推荐的用法:

// main.js 入口文件
import Antd from 'ant-design-vue' 
Vue.use(Antd)

3. 避免引用应用中不使用的组件。

3.2 打包优化

1. 减少预加载、忽略调试代码。

移除预加载:

chainWebpack: (config) => {
  // 移除预加载
  config.plugins.delete('prefetch')
}

忽略调试代码,使用UglifyJsPlugin去掉console 可以略微降低文件大小:

config.plugins.push(
  // 使用UglifyJsPlugin去掉console 可以略微降低文件大小
  new UglifyJsPlugin({
    uglifyOptions: {
      compress: { drop_console: true, drop_debugger: true },
    },
  })
);

2. 降低打包后的资源总体积。

使用externals避免将通用三方组件打包到每个应用组件中:

externals: {
    "ant-design-vue": "ant-design-vue",
    "moment": "moment",
    "../moment": "moment",
    lodash: "lodash",
    "lodash.isequal": "lodash.isequal",
    "lodash.differencewith": "lodash.differencewith",
    "vue-grid-layout": "vue-grid-layout",
    "awe-dnd": "awe-dnd",
    "core-js": "core-js",
    "element-resize-detector": "element-resize-detector",
    sortablejs: "sortablejs",
    "v-viewer": "v-viewer",
    vue: {
        root: "Vue",
        commonjs: "vue",
        commonjs2: "vue",
        amd: "vue"
    },
    "vue-draggable-resizable": "vue-draggable-resizable",
    "vue-upload-component": "vue-upload-component",
    vuedraggable: "vuedraggable",
    vuescroll: "vuescroll",
    xlsx: "xlsx",
    vuex: "vuex"
},

Less 文件处理:

{
  test: /\.css$/,
  use: ["style-loader", "css-loader"],
},
{
  test: /\.less$/,
  use: [
    {
      loader: "style-loader",
    },
    {
      loader: "css-loader",
    },
    {
      loader: "less-loader",
      options: {
        javascriptEnabled:true,//允许链式调用的换行
        sourceMap: true,
        lessOptions: {
          strictMath: true,
        },
      },
    },
  ],
},

图片文件处理:url-loader能将小于某个大小的图片进行base64格式的转化处理。

{
  test: /\.(png|svg|jpg|gif)$/,
  loader: "url-loader?limit=1048576&name=images/[hash:8].[name].[ext]"
},

按需打包moment.js:moment.js 占用空间大的原因在于,moment中包含了大量语言资源文件,我们并不需要这些。通过webpack自身的功能即可在打包时丢弃这些无用的内容:

// 配置需要保留的 moment 插件语言包
config.plugins.push( new MomentLocalesPlugin({
    localesToKeep: ['zh-cn'],
}))

3. 分包:将公共组件、较大的资源单独打包,减少首屏加载的资源数量。

使用SplitChunkPlugin插件将公共模块代码提取出来,防止代码被重复打包,拆分过大的js文件,合并零散的js文件。

config.when(true, config => {
  config.optimization.splitChunks({
    chunks: 'all',
    cacheGroups: {
      vender: {
        name: 'chunk-vender',
        test: /[\\/]node_modules[\\/]/,
        priority: 10,
        chunks: 'initial',
        reuseExistingChunk: true
      },
      libs: {
        name: 'chunk-libs',
        test: /[\\/]node_modules[\\/]/,
        priority: 20,
        minChunks: 3,
        chunks: 'async',
        reuseExistingChunk: true
      },
      xlsx: {
        name: 'chunk-xlsx',
        priority: 100,
        test: /[\\/]node_modules[\\/]_?xlsx(.*)/,
      },
      moment: {
        name: 'chunk-moment',
        priority: 110,
        test: /[\\/]node_modules[\\/]_?moment(.*)/,
      },
      antd: {
        name: 'chunk-antd',
        priority: 120,
        test: /[\\/]node_modules[\\/]_?ant-design-vue(.*)/,
      },
    }
  });
})

3.3 前端工程压缩

使用compression-webpack-plugin插件对前端工程进行Gzip压缩。修改vue.config.js文件:

const CompressionWebpackPlugin = require('compression-webpack-plugin')
const productionGzipExtensions = ['js', 'css']
// const isProduction = process.env.NODE_ENV === 'production'
module.exports = {
  configureWebpack:{
    resolve:{
      alias:{
        '@':path.resolve(__dirname, './src'),
      }
    },
    plugins: [
      // 下面是压缩插件的配置
      new CompressionWebpackPlugin({
        algorithm: 'gzip',
        test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
        threshold: 10240,
        minRatio: 0.8
      }),
      new webpack.optimize.LimitChunkCountPlugin({
        maxChunks: 5,
        minChunkSize: 100
      })
    ]
  }
}

Gzip还需要服务端支持,一般在nginx上做配置。修改nginx配置,在server里添加以下代码,与listen同级:

gzip  on;
gzip_comp_level  5;
gzip_min_length  10;
gzip_static  on;
gzip_buffers  16 64k;
gzip_types  text/plain application/javascript application/x-javascript text/javascript text/css application/xml font/ttf font/otf image/svg+xml;
gzip_vary  on;

你可能感兴趣的:(前端,前端,vue.js,javascript,性能优化)