记一次前端优化首屏加载

本文详述了对一个Vue2旧项目的首屏加载优化过程,包括使用webpack-bundle-analyzer分析包大小,通过CDN加速外部库,路由懒加载,按需引入插件,以及压缩图片等策略。经过优化,首屏加载时间从5s降至3s,显著提升了用户体验。
摘要由CSDN通过智能技术生成

前端优化首屏加载时间

我接手vue2的一个旧项目,因为首屏加载很慢,要求我对此进行优化。我在此进行记录

一、分析加载慢的原因

推荐使用webpack-bundle-analyzer插件,可以对打包后的文件大小进行可视化分析。简单好用

  1. 安装插件

    npm install webpack-bundle-analyzer --save-dev
    
  2. vue.config.js文件中添加对应配置

    // 引入插件
    const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
    
    module.exports = {
      publicPath: '/',
      lintOnSave: true,
      productionSourceMap: false,
      filenameHashing: true,
      configureWebpack: (config) => {
        const plugins = []
        // 配置BundleAnalyzerPlugin
        plugins.push(
          new BundleAnalyzerPlugin({
            analyzerMode: 'server',
            analyzerHost: '127.0.0.1',
            analyzerPort: 8888, // 运行后的端口号
            reportFilename: 'report.html',
            defaultSizes: 'parsed',
            openAnalyzer: true,
            generateStatsFile: false,
            statsFilename: 'stats.json',
            statsOptions: null,
            logLevel: 'info',
          })
        )
        return { plugins }
        }
    }
    

配置完成后执行npm run build则自动打开页面展示文件大小。如下图:
请添加图片描述

可以看到优化前node_modules模块占据了整个页面的将近70%大小(页面中占据面积越大的,也就是打包后体积越大的),其中显眼的插件有tinymcexlsxavue.min.jstheme.jsswiper.jshtml2canvas.js后面优化只要对症下药即可。优化掉对应的插件。网上提供的思路是使用cdn进行优化。下面进行详细记录

二、使用CDN进行优化

使用cdn优化即需要使用外链引入对应插件,那么就需要在index.html文件中添加对应的引入链接。然后需要在打包的时候把通过外链引入的插件排除在外,不进行打包。这里推荐使用这个网站搜索你要的插件,进行CDN外链引入
https://www.jsdelivr.com/

  1. index.html引入外链

    index.html文件中添加如下代码:

    <!-- 使用CDN的CSS文件 -->
    <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
      <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="preload" as="style" />
      <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet" />
    <% } %>
    <!-- 使用CDN加速的JS文件,配置在vue.config.js下 -->
    <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
      <script type="text/javascript" src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
    <% } %>
    
  2. 配置不打包对应的插件

    vue.config.js文件中添加以下配置

    // 配置不打包的模块
    const externals = {
      // 左边是引入的参数,例如 import Vue from 'vue' 这里面的 'vue'
      // 右边是CDN模块的导出对象字段
      vue: 'Vue', 
      'vue-router': 'VueRouter',
      vuex: 'Vuex',
      axios: 'axios',
      '@smallwei/avue': 'AVUE',
      'element-ui': 'ELEMENT',
      xlsx: 'XLSX',
      tinymce: 'tinymce',
      html2canvas: 'html2canvas',
      echarts: 'echarts',
    }
    
    // CDN外链,会插入到index.html中
    const cdn = {
      // 开发环境
      dev: {
        css: [],
        js: [],
      },
      // 生产环境
      build: {
        css: [],
        js: [
          // cdn.jsdelivr.net域名下的cdn文件
          'https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.min.js',
          'https://cdn.jsdelivr.net/npm/vue-router@3.1.3/dist/vue-router.min.js',
          'https://cdn.jsdelivr.net/npm/vuex@3.2.0/dist/vuex.min.js',
          'https://cdn.jsdelivr.net/npm/axios@0.19.0/dist/axios.min.js',
          'https://cdn.jsdelivr.net/npm/element-ui@2.15.6/lib/index.js',
          'https://cdn.jsdelivr.net/npm/@smallwei/avue@2.6.18/lib/avue.min.js',
          'https://cdn.jsdelivr.net/npm/xlsx@0.17.5/xlsx.js',
          'https://cdn.jsdelivr.net/npm/tinymce@5.10.2/tinymce.min.js',
          'https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.js',
          'https://cdn.jsdelivr.net/npm/echarts@4.8.0/dist/echarts.min.js'
        ],
      },
    }
    
    module.exports = {
      publicPath: publicPath,
      lintOnSave: true,
      productionSourceMap: false,
      filenameHashing: true,
      configureWebpack: (config) => {
        const plugins = []
        // 配置BundleAnalyzerPlugin
        plugins.push(
          new BundleAnalyzerPlugin({
            analyzerMode: 'server',
            analyzerHost: '127.0.0.1',
            analyzerPort: 8888, // 运行后的端口号
            reportFilename: 'report.html',
            defaultSizes: 'parsed',
            openAnalyzer: true,
            generateStatsFile: false,
            statsFilename: 'stats.json',
            statsOptions: null,
            logLevel: 'info',
          })
        )
        if (process.env.NODE_ENV === 'production') {
          // externals里的模块不打包
          config.externals = externals
        }
        return { plugins }
      },
      chainWebpack: (config) => {
        // 添加自定义参数cdn
        config.plugin('html').tap((args) => {
          if (process.env.NODE_ENV === 'production') {
            args[0].cdn = cdn.build
          } else {
            args[0].cdn = cdn.dev
          }
          return args
        })
      },
    }
    

完成以上配置后,再运行npm run build得出以下结果:
请添加图片描述

可以看到优化前node_modules模块打包后占了12.48M,优化后nodee_modules模块打包后占了4.02M。

首屏加载的时间从原来的5s变成了3s,还有很多插件也可以使用cdn进行优化,只需要将上图占面积大的插件进行优化即可。另外,由于老项目,经手了很多人,太多重复性代码,所以上图左边views模块占了很大空间。漫漫优化路,无穷无尽。

/-------------------------------------------------------------- 分割线 ------------------------------------------------------------------------/

三、路由懒加载

按照上面的优化思路实现后发现还是不够快,需要更进一步优化。分析其原因,发现在加载首页的时候将打包后的所有的js文件,css文件都引入了。这就会导致花费了大量时间加载不必要的文件。欸,没错。这时就需要使用路由懒加载进行拆分,只加载当前页面需要的js和css文件,减少不必要的文件请求。

网上可以查到多种不同的懒加载方式,这里使用官方介绍的把组件按组分块来进行路由懒加载

const UserDashboard = () => import(/* webpackChunkName: "group-user" */ './UserDashboard.vue')

配置不同的webpackChunkName就可以将对应的组件打包进对应文件中,轻松实现分块打包。

原以为这就结束了,但是打包后一看index.html文件,发现事情不简单
请添加图片描述

打包确实分块了,但是入口文件还是将所有的js和css文件都引入了,这是为什么?

原因是vue-cli3 默认会把所有通过import()按需加载的javascript文件加上 prefetch,也就是上图中link标签后面的属性rel=prefetch

prefetch链接会消耗宽带,因此我们要将prefetch手动关掉,使入口文件只有必要的js和css文件。

关闭prefetch代码如下:

// vue.config.js
module.exports = {
  chainWebpack: config => {
    // 移除 prefetch 插件
    config.plugins.delete('prefetch')
    // 或者
    // 修改它的选项:
    config.plugin('prefetch').tap(options => {
      options[0].fileBlacklist = options[0].fileBlacklist || []
      options[0].fileBlacklist.push(/myasyncRoute(.)+?\.js$/)
      return options
    })
  }
}

再进行打包,观察入口文件结果如下:
请添加图片描述

完美!至此完成路由懒加载~

四、插件按需引入

这一块不用多说,像ElementUIecharts等等,体积较大的插件,如果只用到其中的几个模块但全局引入了,会导致文件过大。

  1. echarts的按需引入直接参照官网即可:
    https://echarts.apache.org/handbook/zh/basics/import

  2. elementUI按需引入过程中,配置中会存在一点小问题。
    如果脚手架比较新没有 .babelrc文件,则修改babel.config.js文件,添加配置项:

{
  "presets": [["es2015", { "modules": false }]], //如果配置后报错,把这里的数组项改成右边的即可 ["@babel/preset-env", { "modules": false }]
  "plugins": [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

还有一个小问题就是element的隐藏组件scrollBar并没有对外暴露,这个组件无法按需引入。

五、压缩图片

至此首页快了非常多,观察首页的所有请求,发现还有两张图片请求较大,便将图片进行压缩(原来的我以为图片压缩会导致像素变低,直到我在网上尝试了压缩图片,压缩前后的观感完全一样,但是文件大小直接降低了近70%。不过大部分压缩图片的网站是需要会员或者收费的)

下面是我常用的一个免费的压缩图片的网站:

https://kt.fkw.com/yasuo.html?_ta=8780

压缩完图片进行替换,请求再次变小,速度再次提升。

最后

最后如果服务器有nginx代理的话,可以配置gzip压缩传输,速度会更快,但是这里服务器没有使用nginx代理,故不能配置gzip了,不然我想这个网站肯定可以更快

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值