likes
comments
collection
share

webpack5高级

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

高级也就是相对于基础的优化。从以下角度进行优化: 提升开发体验; 提升打包构建速度 减少代码体积 优化代码运行性能

提升开发体验

SourceMap

为什么

SourceMap用来生成源代码与与构建后的代码--映射的文件的方案。 Source map可以理解为一个地图, 通过它可以获知编译后的代码 对应编译前的代码位置。这样当代码遇到异常, 我们就可以通过报错信息定位至准确的位置。 同时在浏览器 sources 也可以查看到源码。

是什么

开发模式

  • cheap-module-source-map

优点:打包编译速度快,只包含行映射 缺点:无列映射

怎么用

在开发模式下配置

devtool:"cheap-module-source-map"

生产模式

  • source-map

优点:包含行列映射 缺点:打包编译速度慢

在生产模式下配置

devtool:"source-map"

提升打包构建速度

Hot Module Replacement 热模块替换

为什么

我们在修改代码的时候,只修改了一个模块,webpack会默认把所有模块重新打包一遍。但是我们只想把修改的模块重新打包,提升速度。

是什么

Hot Module Replacement 热模块替换

怎么用

通过在devServer设置hot:true

 devServer:{
    host:"localhost", //启动服务器的域名
    port:"3000", //启动服务器端口号
    open:true, //是否自动打开浏览器
    hot:true, //打开hmr
  },

js使用hml,在main.js中设置

if(module.hot){
  //判断是否支持热模块功能
  module.hot.accept("./js/count")
  module.hot.accept("./js/sum")
}

oneOf

每个文件只能被一个loader处理

 rules: [
      {
        oneOf: [ //每个文件只能被其中一个loader处理
          { test: /\.css$/, use: ["style-loader", "css-loader"] },
          // { test: /\.less$/, use: ["style-loader", "css-loader", "less-loader"] },
          {
            test: /\.s[ac]ss$/,
            use: ["style-loader", "css-loader", "sass-loader"],
          },
          // { test: /\.styl$/, use: ["style-loader", "css-loader", "less-loader"] },
          {
            test: /\.(png|jpe?g|gif|webp)$/,
            type: "asset",
            parser: {
              dataUrlCondition: {
                maxSize: 10 * 1024, // 小于10kb的图片会被base64处理
              },
            },
            generator: {
              //输出文件名称,10代表hash值只取前10
              filename: "static/images/[hash:10][ext][query]",
            },
          },
          {
            test: /\.(ttf|woff?2|)$/,
            type: "asset/resource",
            generator: {
              //输出名称,10代表hash值只取前10
              filename: "static/media/[hash:10][ext][query]",
            },
          },
          {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: "babel-loader",
          },
        ],
      },
    ],

Include和Exclude

为什么

开发时我们需要使用第三方库和插件,所有文件都下载到node_modules中了,而这些文件是不需要编译直接使用的。所以我们在对js文件进行处理时,要排除node_modules中的文件。

是什么

include:包含,只处理xxx文件 exclude:排除,排除xxx文件以外的文件都处理

怎么用

exclude和include只使用一个

{
    test: /\.js$/,
    exclude: /node_modules/, //排除node_modules,其他都处理
    // include:path.resolve(__dirname,"./src"), //只处理src下的文件,其他不处理
    loader: "babel-loader",
},

Cache

为什么

每次打包都需要经过eslint检查和babel编译,速度比较慢 我们可以缓存之前的eslint检查和babel编译结果,这样二次打包的速度就更快了

是什么

对eslint检查和babel编译进行缓存

怎么做

{
    test: /\.js$/,
    exclude: /node_modules/, //排除node_modules,其他都处理
    // include:path.resolve(__dirname,"./src"), //只处理src下的文件,其他不处理
    loader: "babel-loader",
    options:{
      cacheDirectory:true, //开启babel缓存
      cacheCompression:false,//关闭缓存文件压缩
    }
},

测试:打包完成后在node_modules中增加了cache的文件

Thead多进程

为什么

当项目越来越庞大时,打包速度越来越慢,甚至于需要一个下午才能打包出来代码。这个速度是比较慢的。 我们想要继续提升打包速度,其实就是要提升 js 的打包速度,因为其他文件都比较少。 我们可以开启多进程同时处理 js 文件,这样速度就比之前的单进程打包更快了。

是什么

多进程打包:开启电脑的多个进程同时干一件事,速度更快。 需要注意:请仅在特别耗时的操作中使用,因为每个进程启动就有大约为 600ms 左右开销。

怎么用

下载包

npm i thread-loader -D

在webpack.prod.js获取cpu核数

// nodejs核心模块,直接使用
const os = require("os");
// cpu核数
const threads = os.cpus().length;

//TerserPlugin  webpack自带压缩js
const TerserPlugin = require("terser-webpack-plugin");

配置生产环境

use: [
  {
    loader:"thread-loader", //开启多进程
    options: {
      workers: threads, //开启个进程数量
    },
  },
  {
    loader: "babel-loader",
    options: {
      cacheDirectory: true, //开启babel缓存
      cacheCompression: false, //关闭缓存文件压缩
    },
  },
],
plugins: [
    // 压缩js  当生产模式会默认开启TerserPlugin,但是我们需要进行其他配置,就要重新写了
    new TerserPlugin({
      parallel: threads // 开启多进程
    })
  ],

optimization

对打包结果进行优化,放置压缩操作

 const TerserWebpackPlugin = require("terser-webpack-plugin");
 optimization: {
    minimizer: [
      new TerserPlugin({
        parallel: threads, // 开启多进程
      }),
      //压缩css
      new CssMinimizerPlugin(),
    ],
  },

开发环境配置同上

减少代码体积

tree-shaking

为什么

开发时我们引用一些工具库或第三方组件库,如果没有特殊处理,我们打包时会引入整个库,体积太大。

是什么

tree-shaking用于描述移除js中的没有用到的代码。 注意:依赖es module

怎么用

webpack生产环境默认开启,无需配置

babel

为什么

babel为编译的每个文件都插入了辅助代码,使体积过大。所以需要将重复的辅助代码作为一个独立的模块,避免重复使用。

是什么

@babel/plugin-transform-runtime 禁用babel自动对每个文件的runtime注入,而是引入。并且使所有代码从这里引入。

怎么用

安装包

npm i @babel/plugin-transform-runtime -D

配置(测试环境和生产环境都要配置)

{
    loader: "babel-loader",
    options: {
      cacheDirectory: true, //开启babel缓存
      cacheCompression: false, //关闭缓存文件压缩
      plugins:["@babel/plugin-transform-runtime"]
    },
  },

Image Minimizer

为什么

如果开发中引入了较多图片,那么图片体积会比较大,将来请求速度比较慢。我们可以对图片进行压缩,减少体积 注意:如果图片是在线链接则不需要,本地图片则需要打包

是什么

image-minimizer-webpack-plugin用来压缩图片的插件

怎么用

下载 npm i image-minimizer-webpack-plugin imagemin -D

无损压缩 npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo -D 有损压缩 npm install imagemin-gifsicle imagemin-mozjpeg imagemin-pngquant, imagemin-svgo -D 配置(生产模式)

const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
new ImageMinimizerPlugin({
        minimizer: {
          implementation: ImageMinimizerPlugin.imageminGenerate,
          options: {
            plugins: [
              ["gifsicle", { interlaced: true }],
              ["jpegtran", { progressive: true }],
              ["optipng", { optimizationLevel: 5 }],
              [                "svgo",                {                  plugins: [                    "preset-default",                    "prefixIds",                    {                      name: "sortAttrs",                      params: {                        xmlnsOrder: "alphabetical",                      },                    },                  ],
                },
              ],
            ],
          },
        },
      }),

打包时会报错,安装两个文件(jpegtran.exe,optipng.exe官网下载)到 node_modules 中才能解决。 需要复制到 node_modules\jpegtran-bin\vendor 下面

优化代码运行性能

code split

为什么

打包代码的时候会把所有js文件打包到一个文件下。体积太大,如果只想渲染首页,只需要加载首页的js。其他的js文件不加载。 所以我们需要将打包的代码进行分割,生成多个js文件,按需加载。

是什么

1.分割文件。将打包的文件进行分割,生成多个js文件。 2.按需加载。需要哪个文件加载哪个文件

怎么做

参考链接blog.csdn.net/goudexingwu…

实际开发时多为单页面应用,在生产环境的optimization中配置

//代码分割操作
splitChunks:{
  chunks:"all",
  //其他使用默认值
}

测试 将main.js中引入的文件注释,在点击按钮时才加载此文件。在html文件中写点击按钮 main.js按需引入测试如下

document.getElementById("btn").onclick = function () {
  import("./js/count").then(({ count }) => {
    console.log(count(2, 9));
  });
};

count文件在一进入页面时不加载,只有点击按钮时才加载。

给模块命名

// webpack特殊的命名方式/*webpackChunkName:  "count"*/
document.getElementById("btn").onclick = function () {
  import(/*webpackChunkName:  "count"*/  "./js/count").then(({ count }) => {
    console.log(count(2, 9));
  });
};

生产环境在output中配置

 //给打包输出的其他文件命名
chunkFilename:"static/js/[name].js",

统一命名配置

//入口文件打包输出的文件名
filename: "static/js/[name].js",
chunkFilename:"static/js/[name].chunk.js",
//对其他文件命名资源处理
assetModuleFilename: 'static/media/[hash:10][ext][query]',


对css统一命名做处理
new MiniCssExtractPlugin({ filename: "static/css/[name].css",
chunkFilename:"static/css/[name].chulk.css" }),

preload/prefetch(兼容性不太好)

为什么

虽然我们前面已经做了代码分割,按需加载,但是有些资源需要我们点击或者触发时才加载,如果文件体积过大,加载慢,用户体验极其不好。我们需要在浏览器的空闲时间加载后续的资源,需要用到preload和prefetch。

是什么

preload:告诉浏览器立即加载的资源 prefetch:告诉浏览器在空闲时间才可以加载资源 共同点: 只加载不执行,有缓存 区别 preload加载优先级高,只可以加载当前页面的资源 prefetch既可以加载当前页面要使用的资源,也可以加载下一个页面要使用的资源。

怎么用

下载包

npm i --save-dev @vue/preload-webpack-plugin
本来使用的是 preload-webpack-plugin,但其与webpack5不兼容所以采用其替代品

配置

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

new PreloadWebpackPlugin({
  rel:"preload",
  as:"script",
  // rel:"prefetch",
})
//有一个文件发生变化,只当前文件的缓存变化,其他文件的换成不受影响
runtimeChunk:{
  name:(entrypoint) => `runtime-${entrypoint.name}.js`,
}

core-js

为什么

babel对js的处理无法处理async函数,promise对象等,存在一定的兼容性问题。

是什么

专门做es6及以上api的polyfill(补丁)

怎么用

修改main.js

安装包
npm i core-js

完整引入 在main.js中引入:import "core-js" 按需加载 import "core-js/es/promise" 按需自动引入

修改babel.config.js
module.exports = {
  presets: [
    [
      "@babel/preset-env",
      {
        useBuiltIns: "usage", //按需加载自动引入
        corejs: 3,
      },
    ],
  ], //预设,babel插件。扩展babel功能,编译es6语法
};

PWA

为什么

用户可以离线访问

是什么

渐进式网络应用程序,在离线时应用程序能够正常运行。内部通过service workers实现。

怎么用

安装包npm i workbox-webpack-plugin -D 在生产环境配置

const WorkboxWebpackPlugin = require('workbox-webpack-plugin');


new WorkboxWebpackPlugin.GenerateSW({ 
  clientsClaim: true,//这些选项帮助快速启用
  skipWaiting: true//不允许遗留任何“旧的”
})


在main.js
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/service-worker.js').then(registration => {
      console.log('sw注册成功了 ', registration);
    }).catch(registrationError => {
      console.log('SW注册失败 ', registrationError);
    });
  });
}

此时sw注册失败,需要npm i serve -g后serve dist访问,即可在无网络时访问页面。