likes
comments
collection
share

前端性能优化之页面加载

作者站长头像
站长
· 阅读数 13

前言

在日常项目中,我们都会遇到页面加载速度较慢的问题,影响了用户的体验,在这边记录一下处理的一些方式。

一.代码压缩和资源优化

对于 CSS 和 JavaScript 文件,使用压缩工具进行压缩和合并,减小文件的体积,提高加载速度。同时,对图片进行压缩和懒加载,减少页面的资源请求和加载时间。

1. 按需加载:splitChunks代码进行分割,提高加载速度和性能,vite是在rollupOptions 中配置

//webpack配置:
 optimization: {
      // 对代码进行压缩相关的操作
      // natural: 使用自然数(不推荐),
      // named: 使用包所在目录作为name(在开发环境推荐)
      // deterministic: 生成id, 针对相同文件生成的id是不变
      // chunkIds: "deterministic",
      splitChunks: {
        // async异步导入
        // initial同步导入
        // all 异步/同步导入
        chunks: "all",
        // 最小尺寸: 如果拆分出来一个, 那么拆分出来的这个包的大小最小为minSize
        minSize: 20000,
        // 将大于maxSize的包, 拆分成不小于minSize的包
        maxSize: 20000,
        // minChunks表示引入的包, 至少被导入了几次
        minChunks: 1,
        cacheGroups: {
          vendor: {
            test: /[\\/]node_modules[\\/]/,
            filename: "js/[id]_vendors.js",
            // name: "vendor-chunks.js",
            priority: -10
          },
          // bar: {
          //   test: /bar_/,
          //   filename: "[id]_bar.js"
          // }
          default: {
            minChunks: 2,
            filename: "common_[id].js",
            priority: -20
          }
        }
      },

解释acheGroups个配置选项的含义如下:

vendor:这是一个缓存组的名称,用于将来自node_modules目录下的模块打包到一个单独的文件中。

test: /[\/]node_modules[\/]/:使用正则表达式指定需要被匹配到的模块路径。在这个示例中,表示匹配node_modules目录下的模块。

filename: "js/[id]_vendors.js":设置生成的文件名。[id]将会被替换为模块的标识符,生成的文件将放置在js/目录下。

priority: -10:用于指定缓存组的优先级,数值越小优先级越高。在这个示例中,vendor的优先级设置为-10。

default:这是另一个缓存组的名称,用于将满足特定条件但没有被其他缓存组匹配到的模块打包到一个单独的文件中。

minChunks: 2:设置模块被引用的最小次数。在这个示例中,只有被至少两个模块引用的模块才会被打包到common_[id].js文件中。

filename: "common_[id].js":设置生成的文件名。[id]将会被替换为模块的标识符。

通过这样的配置,Webpack会根据指定的规则将模块进行代码分割,并生成对应的文件。这样可以实现将公共的第三方库打包到单独的vendors.js文件中,将满足特定条件的模块打包到common_[id].js文件中。

// vite.config.js
export default {
  // 其他配置...
  build: {
    rollupOptions: {
      output: {
        manualChunks(id) {
          if (id.includes('node_modules')) {
            return 'vendor';
          }
        },
      },
    },
  },
};

2. 对代码进行压缩和资源优化:webpack 中Terser进行js代码压缩,去除无用代码console.log。代码分割缓存的规则

const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
  // ...其他配置
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        // 配置TerserPlugin选项
        terserOptions: {
          compress: {
            drop_console: true, // 移除console语句
          },
          mangle: true, // 变量名混淆
        },
      }),
    ],
  },
};

   build: {
      outDir: "dist",
      minify: "esbuild",
      // esbuild 打包更快,但是不能去除 console.log,terser打包慢,但能去除 console.log
      // minify: "terser",
      // terserOptions: {
      // 	compress: {
                        //生产环境时移除console
      // 		drop_console: viteEnv.VITE_DROP_CONSOLE,
      // 		drop_debugger: true
      // 	}
      // },
      // 禁用 gzip 压缩大小报告,可略微减少打包时间
      reportCompressedSize: false,
      // 规定触发警告的 chunk 大小
      chunkSizeWarningLimit: 2000,
      rollupOptions: {
        output: {
          // Static resource classification and packaging
          chunkFileNames: "assets/js/[name]-[hash].js",
          entryFileNames: "assets/js/[name]-[hash].js",
          assetFileNames: "assets/[ext]/[name]-[hash].[ext]"
        }
      }
    }

3. tree shaking:剔除不使用的代码,viteesmodule默认开启, webpack : usedExports: true(必须在production下)

// webpack.config.js module.exports = { // 其他配置... optimization: { usedExports: true, }, };

4. 模块化打包:通过将应用程序分解为小模块,提高代码的可维护性和可复用性。在Webpack中,可以使用CommonJS或ESM模块化方式进行打包;在Vite中,默认使用ESM模块。

  module: {
    rules: [
      {
        test: /\.jsx?$/i,
        use: "babel-loader"
      },
      {
        test: /\.vue$/i,
        use: "vue-loader"
      },
      {
        test: /\.css/i,
        use: [
          "style-loader",
          "css-loader"
        ]
      }
    ]
  },

5. 图片优化:对图片资源进行压缩和优化,减小文件大小。可以使用插件如imagemin-webpack-plugin或Vite的内置优化来进行图片压缩。(vite自带不需要配置)

module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif|svg)$/i,
        use: [
          {
            loader: 'file-loader',
            options: {
              outputPath: 'images',
            },
          },
          {
            loader: 'image-webpack-loader',
            options: {
              mozjpeg: {
                progressive: true,
                quality: 65,
              },
              optipng: {
                enabled: false,
              },
              pngquant: {
                quality: [0.65, 0.9],
                speed: 4,
              },
              gifsicle: {
                interlaced: false,
              },
            },
          },
        ],
      },
    ],
  },
};

二.按需加载和懒加载

对于较大的组件或页面,采用按需加载和懒加载的方式,只在需要时才加载对应的组件或页面。这样可以减少初始加载的内容,提高页面的响应速度。

懒加载和预加载:根据页面或组件的需要,通过懒加载和预加载来优化页面的加载。可以使用Webpack的import()或Vue的异步组件来实现懒加载和预加载。

在 Webpack 中配置懒加载和预加载 :

// 使用动态 import 实现懒加载
import('./module').then((module) => {
  // 使用模块
});

// 在 webpack.config.js 中进行预加载配置
module.exports = {
  // 其他配置...
  optimization: {
    splitChunks: {
      chunks: 'async',
      minSize: 0,
      minChunks: 1,
      maxAsyncRequests: 5,
      maxInitialRequests: 3,
      name: false,
      cacheGroups: {
        // 预加载配置
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendor',
          chunks: 'all',
          priority: -10,
          enforce: true,
        },
      },
    },
  },
};

使用Vue的异步组件和路由配置实现了懒加载和预加载:

// 使用异步组件实现懒加载
const Foo = () => import('./Foo.vue');

// 在路由配置中进行预加载配置
const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/page',
      component: () => import('./Page.vue'),
      meta: { preload: true }, // 预加载配置
    },
  ],
});

// 在 main.js 中执行预加载
router.beforeEach((to, from, next) => {
  if (to.meta.preload) {
    import(to.path);
  }
  next();
});

三. 静态资源缓存

对于不经常变动的静态资源(如图片、CSS、JavaScript 文件),通过设置缓存策略,使客户端可以缓存这些资源,减少重复的请求,提高页面加载速度。 要处理静态资源的缓存,你可以通过设置适当的缓存策略,让客户端缓存这些资源。下面我将为你介绍一些常用的方法来处理静态资源的缓存:

  1. 设置静态资源的过期时间: 在服务器端配置响应头,设置静态资源的Cache-ControlExpires字段来指定资源的过期时间。这样,浏览器会在过期时间内缓存资源,避免重复的请求。
// 设置 Cache-Control
response.setHeader('Cache-Control', 'max-age=3600'); // 缓存时间为1小时

// 设置 Expires
response.setHeader('Expires', new Date(Date.now() + 3600000).toUTCString()); // 缓存时间为1小时

  1. 使用文件版本号: 在每次静态资源文件更新时,修改文件名或添加版本号,例如在文件名后面添加一个版本号或哈希值。这样,当文件内容发生变化时,文件名也会变化,浏览器会重新下载最新的文件。
<link rel="stylesheet" href="styles.css?v=1.0.0"> <script src="script.js?v=1.0.0"></script>
  1. 文件指纹策略: 使用构建工具或打包工具,在构建过程中为静态资源生成唯一的文件指纹(通常是哈希值),并将文件名与文件指纹关联。这样,每次文件内容发生变化时,文件名也会随之改变,浏览器会重新下载最新的文件。
// webpack.config.js module.exports = { // 其他配置... output: { filename: 'bundle.[contenthash].js', }, };

> vite 配置看上方第二点的output配置

四. 代码性能优化

通过对代码进行优化,例如减少重复的计算、减少不必要的 DOM 操作和避免过多的数据绑定,提高代码的执行效率,减少页面的渲染时间。