webpack优化策略

日常开发中经常使用使用webpack对我们的代码进行打包编译。平时这方面我都是直接cv大法伺候,没怎么去理解。这篇文章主要是记录我对webpack的学习理解。

打包构建速度

HotModuleReplacement

每次我们改动了代码时,webpack会对整个模块进行重新打包编译,这导致速度很慢,而HotModuleReplacement(HMR) 也称热模块替换,能在程序运行中,对模块删除,替换,而不是重新加载整个模块。在webpack 5是默认开启的

  devServer: {
    // 端口号
    port: 3000,
    // 域名
    host: "localhost",
    // 自动打开浏览器
    open: true,
    // 热更新
    hot:false, 
  },

当我们hot改成false时候,对代码修改会导致整个页面重新加载(在webpack5中默认开启)
我们在入口文件main.js写上这样一句

if(module.hot){ //判断是否支持热模块替换
 module.hot.accept("./js/cout")
}

这里就表示在cout文件下单js改动就只会触发cout的更新(需要那个文件热更新就将路径放入accept函数即可),这样就会让打包更快。当然在当下,有vue-loader,react-hot-loader这些loader帮我们处理相关的模块,我们不用一个个文件写入accept中。accept提供第二个可选参数,可以传一个函数,如果该文件改变就会执行这个函数,

 module.hot.accept("./js/cout",function(){
     console.log("qwe")
 })

这样每次更改cout.js就会触发函数;

oneOf

在webpack中 配置加载其module.rules,会一个个的匹配文件是否命中,无论命中与否,他都会把所有规则匹配完毕。有的时候这是没必要的`,比如一个a.css文件在下面匹配规则中第一个命中了不会停下来,会继续匹配所有规则。但是这是没必要的,我们想要他在第一个命中后就停止匹配,这样打包的效率就会高一点,这时候我们就可以去配置oneOf

module: {
    rules: [
      {
        test: /\.css$/i,
        use: ["style-loader", "css-loader"], //从右到左,从下到上的加载
      },
      {
        test: /\.s[ac]ss$/i,
        use: [
          // 将 JS 字符串生成为 style 节点
          "style-loader",
          // 将 CSS 转化成 CommonJS 模块
          "css-loader",
          // 将 Sass 编译成 CSS
          "sass-loader",
        ],
      },
      {
        test: /\.(png|gif)$/,
        type: "asset",
        parser: {
          dataUrlCondition: {
            //小于4kb 的图片转base64
            maxSize: 4 * 1024, // 4kb
          },
        },
        generator: {
          //输出图片名称
          filename: "static/image/[hash:10][ext][query]",
        },
      },
      {
        test: /\.m?js$/,
        exclude: /(node_modules)/, //排除node_modules文件不处理
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env"],
          },
        },
      },
    ],

在以上配置代码中,把配置放入oneOf里面即可,当命中一个的时候就不会继续向下匹配,当项目庞大的时候可以缩减一定的打包时间

  //加载器
  module: {
    rules: [
      {
        oneOf: [ //命中一个之后就不会继续匹配
          {
            test: /\.css$/i,
            use: ["style-loader", "css-loader"], //从右到左,从下到上的加载
          },
          {
            test: /\.s[ac]ss$/i,
            use: [
              // 将 JS 字符串生成为 style 节点
              "style-loader",
              // 将 CSS 转化成 CommonJS 模块
              "css-loader",
              // 将 Sass 编译成 CSS
              "sass-loader",
            ],
          },
          {
            test: /\.(png|gif)$/,
            type: "asset",
            parser: {
              dataUrlCondition: {
                //小于4kb 的图片转base64
                maxSize: 4 * 1024, // 4kb
              },
            },
            generator: {
              //输出图片名称
              filename: "static/image/[hash:10][ext][query]",
            },
          },
          {
            test: /\.m?js$/,
            exclude: /(node_modules)/, //排除node_modules文件不处理
            use: {
              loader: "babel-loader",
              options: {
                presets: ["@babel/preset-env"],
              },
            },
          },
        ],
      },
    ],
  },
include/exclude

在项目中,如果我们不想要某些文件不接受特定处理或者只接受某些文件处理,就可以使用exclude(排除)/include(只接受) 字段,比如当我们使用第三方库的时候,基本上文件都下载到了node_modules文件中去了。有时候这是完全没有不要的,这时候就需要用到exclude来过滤了 比如

          {
            test: /\.m?js$/,
            exclude: /(node_modules)/, //排除node_modules文件不处理
            use: {
              loader: "babel-loader",
              options: {
                presets: ["@babel/preset-env"],
              },
            },
          },
          这里就排除node_modules下的匹配babel
  //插件
  plugins: [
    new ESLintPlugin({
      context: path.resolve(__dirname, "../src"),
      exclude: "node_modules" //这里不写默认也是会排除node_modules的
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "../public/index.html"),
    }),
  ],
          	
cache

每次打包的时候,如果我们配置了eslint和Bable编译,那每次打包都会走一遍这个编译流程,速度比较慢。这时候就可以利用cache来缓存第一次的编译结果,让下一次编译的更快了,cacheDirectory 设置为true 即可开启缓存,cacheCompression 默认为true 表示压缩缓存,但是会有解压压缩过程,让打包变慢,这里缓存的体积占用没多大关系,所以把他关闭了,看需求设置。

          {
            test: /\.m?js$/,
            exclude: /(node_modules)/, //排除node_modules文件不处理
            loader: "babel-loader",
            options: {
              presets: ["@babel/preset-env"],
              cacheDirectory:true,//开启babel缓存
              cacheCompression:true,//关闭缓存文件压缩,这样可以跳过压缩和解压的过程,从而提高速度
            },
          },

在eslint也能开启缓存,将cache设置true,并且cacheLocation设置缓存路径

  //插件
  plugins: [
    new ESLintPlugin({
      context: path.resolve(__dirname, "../src"),
      exclude: "node_modules", //这里不写默认也是会排除node_modules的
      cache:true,//开启缓存
      cacheLocation:path.resolve(__dirname,"../node_modules/.cache/eslint") //设置缓存路径
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "../public/index.html"),
    }),
  ],
多线程打包

当项目特别大的时候,打包会变得越来越慢,这时候我们可以开启多线程同时来处理js的打包,一般是eslint,babel, terser对js处理是比较多的,所以可以开启多线程处理他们的打包速度

eslint多线程配置
    new ESLintPlugin({
      context: path.resolve(__dirname, "../src"),
      exclude: "node_modules", //这里不写默认也是会排除node_modules的
      cache: true, //开启缓存
      cacheLocation: path.resolve(__dirname, "../node_modules/.cache/eslint"), //设置缓存路径
      threads //开启多线程和设置进程数量
    }),

babel-loader配置

         {
            test: /\.m?js$/,
            exclude: /(node_modules)/, //排除node_modules文件不处理
            use: [
              {
                loader: "thread-loader",
                options: {
                  works: threads,//进程数量
                },
              },
              {
                loader: "babel-loader",
                options: {
                  presets: ["@babel/preset-env"],
                  cacheDirectory: true, //开启babel缓存
                  cacheCompression: true, //关闭缓存文件压缩,这样可以跳过压缩和解压的过程,从而提高速度
                },
              },
            ],
          },

TerserWebpackPlugin 开启多线程

 //插件
  plugins: [
    new ESLintPlugin({
      context: path.resolve(__dirname, "../src"),
      exclude: "node_modules", //这里不写默认也是会排除node_modules的
      cache: true, //开启缓存
      cacheLocation: path.resolve(__dirname, "../node_modules/.cache/eslint"), //设置缓存路径
      threads //开启多线程和设置进程数量
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "../public/index.html"),
    }),
    new TerserWebpackPlugin({
      parallel:threads //开启多线程和设置进程数量压缩js
    })
  ],

需要注意的是开启线程也是需要时间的,如果项目体积不大,使用多线程打包可能会反让打包时间变成,这里要注意以下,不能盲目开启多线程打包

减少代码体积

three Shaking

开发中我们经常引入第三方的函数库,但是可能一个函数库中我们仅仅需要部分函数,其他的不需要,如果不处理的话,就会把全部都打包,体积就会特别大,webpack默认的配置好了 只有我们引用的函数才会被打包,不需要我们做配置。

babel

balel默认会为每个文件插入辅助代码,是的代码体积过大,
babel对一些公共方法都是用了辅助代码,默认情况下也会被添加到每一个需要他的文件。 可以将这些辅助代码作为一个独立的模块,来避免重复的注入;
我们可以引入@babel/plugin-transform-runtime 插件,禁止对每个文件的注入,而是引入@babel/plugin-transform-runtime,并且使所有辅助代码从这里引用。这样就可以减少打包的体积。

              {
                loader: "babel-loader",
                options: {
                  presets: ["@babel/preset-env"],
                  cacheDirectory: true, //开启babel缓存
                  cacheCompression: true, //关闭缓存文件压缩,这样可以跳过压缩和解压的过程,从而提高速度
                  plugins: ['@babel/plugin-transform-runtime'] //减少代码体积
                },
              },
图片压缩

如果项目中引入过多的图片,那么图片体积如果过大,会导致请求变慢。这时候可以使用压缩的方式来压缩图片体积,达到更快的加载速度。
这里可以引用一个插件image-minimizer-webpack-plugin
可以选用无损压缩 imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo 配置方式按照官网就可以了

  plugins: [
    new ImageMinimizerPlugin({
      minimizerOptions: {
        // Lossless optimization with custom option
        // Feel free to experiment with options for better result for you
        plugins: [
          ["gifsicle", { interlaced: true }],
          ["jpegtran", { progressive: true }],
          ["optipng", { optimizationLevel: 5 }],
          // Svgo configuration here https://github.com/svg/svgo#configuration
          [
            "svgo",
            {
              plugins: extendDefaultPlugins([
                {
                  name: "removeViewBox",
                  active: false,
                },
                {
                  name: "addAttributesToSVGElement",
                  params: {
                    attributes: [{ xmlns: "http://www.w3.org/2000/svg" }],
                  },
                },
              ]),
            },
          ],
        ],
      },
    }),
  ],

优化运行性能

按需加载

在开发中,如果我们在一个页面有很多功能模块,webpack会在开始就默认全部加载,这回导致页面白屏时间过长,但是我们未必会使用到这些功能,比如你首页有一个按钮,点击后会触发一个函数,但是在进入首页的时候我们不需要去加载这个函数的文件,只有当我们点击他的时候才去真正的加载模块,这时候我们就需要动态加载了。
动态加载我们需要用到动态加载的语法,以下
我们在首页定义一个按钮`

<button id="button">点击我</button>

再绑定man.js中绑定这个函数

document.getElementById("button").onclick = function(){
    import("./js/out").then(res=>{
        let {out} = res
        out();
    })
}

在out.js中定义函数

export function out() {
  console.log("qqqqqq");
}

那么每次点击按钮的时候,才回去引入out.js文件,而不会在进入页面的时候就直接引入
在这里插入图片描述

preload/prefetch

preload和prefetch是提示浏览器加载以后可能会需要的资源,也就是对资源进行预加载不执行,这样在真正需要的时候就可以直接使用,速度更快。preload只能加载的当前页面的资源,如果到下一个页面则会失效,而prefetch则可以保留到下一个页面。prefetch的加载优先度低,是在浏览器空闲的时候去加载,而preload会立即加载,preload/prefetch的兼容性不是特别好,所以使用的时候要注意。

const PreloadWebpackPlugin = require('@vue/preload-webpack-plugin');

    new PreloadWebpackPlugin({
      rel: 'preload',//preload或者prefetch
      as: 'script'
    })

使用魔法注释

document.getElementById("button").onclick = function(){
    import(
        /* webpackPrefetch: true */ "./js/out").then(res=>{
        let {out} = res
        out();
    })
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值