Webpack5 学习 - 优化篇

Webpack5 学习 - 优化篇

接上一篇 👉 :Webpack5 学习 - 基础篇

优化篇

更新至最新版本

使用最新的 webpack 版本。将 Node.js 更新到最新版本,也有助于提高性能。除此之外,将 package 管理工具(例如 npm 或者 yarn)更新到最新版本,也有助于提高性能。较新的版本能够建立更高效的模块树以及提高解析速度。

减少 loader 应用范围

配置 loader ,通过使用 includeexclude 指定 loader 的作用目录或者需要排除的目录, exclude 优先级更高

  • include:符合条件的模块进行解析
  • exclude:排除符合条件的模块,不解析

例如在配置 babel 的时候

const path = require('path');
module.exports = {
    module: {
        rules: [
            //babel
            {
                test: /\.js$/,
                include: path.resolve(__dirname, '../src'),
                exclude: /(node_modules|bower_components)/, //不转换的文件
                use: {
                  loader: 'babel-loader',
                  options: {
                    presets: ['@babel/preset-react','@babel/preset-env']
                  }
                }
            }
        ],
    },
} 
复制代码

优化 resolve 配置

1. alias 配置别名

const path = require('path')
module.exports = {
    resolve: {
        // 配置别名
        alias: {
            '~': path.resolve(__dirname, '../src'),
            '@': path.resolve(__dirname, '../src'),
            'components': path.resolve(__dirname,'../src/components'),
        }
    },
} 
复制代码

配置完成之后,引入文件可以这样写

import '~/style.css'
import icon from '@/assets/icon.png'
import Hello from "components/Hello";
复制代码

2. extensions 解析文件

extensions 表示需要解析的文件类型列表。如果用户引入模块时不带扩展名,那么 webpack 就会按照 extensions 配置的数组从左到右的顺序去尝试解析模块

  1. 高频文件后缀名放前面;
  2. 手动配置后,默认配置会被覆盖

webpack.common.js

const config = { 
    //... 
    resolve: { 
        //extensions: ['.js', '.json', '.wasm'], //默认配置
        extensions: ['.ts', '...'], //保留默认配置
    }, 
};
复制代码

3. modules

告诉 webpack 解析模块时应该搜索的目录,指定目录可缩小 webpack 解析范围,加快构建速度。

webpack.common.js

module.exports = {
    modules: [
      path.resolve(__dirname, '../src'), 
      'node_modules'
    ]
}
复制代码

4. module.noParse

精准过滤不需要解析的文件,防止 webpack 解析那些任何与给定正则表达式相匹配的文件。忽略的文件中 不应该含有 importrequiredefine 的调用,或任何其他导入机制。忽略大型的 library 可以提高构建性能。

module.exports = {
  //...
  module: {
    noParse: /jquery|lodash/,
  },
};
复制代码

5. resolveLoader

resolve 对象的属性集合相同, 但仅用于解析 webpack 的 loader 包。

module.exports = {
  //...
  resolveLoader: {
    modules: ['node_modules'],
    extensions: ['.js', '.json'],
    mainFields: ['loader', 'main'],
  },
};
复制代码

6. symlinks

如果项目不使用 symlinks(例如 npm link 或者 yarn link),可以设置 resolve.symlinks: false,减少解析工作量。

webpack.common.js 配置方式如下:

module.exports = {
    resolve: {
        //是否将符号链接(symlink)解析到它们的符号链接位置(symlink location)。
        //启用时,符号链接(symlink)的资源,将解析为其 *真实* 路径,而不是其符号链接(symlink)的位置。
        //注意,当使用创建符号链接包的工具(如 `npm link`)时,这种方式可能会导致模块解析失败。
        symlinks: false,
    },
}
复制代码

外部扩展(Externals)

防止将某些 import 的包(package)打包到 bundle 中,而是在运行时(runtime)再去从外部获取这些扩展依赖(external dependencies)

该方法可以在打包时不将外链引用的第三方模块不打包到最终文件中,可以减少打包文件的体积

例如,从 CDN 引入 jQuery,而不是把它打包:

index.html

<script
  src="https://code.jquery.com/jquery-3.1.0.js"
  integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
  crossorigin="anonymous"
></script>
复制代码

webpack.config.js

module.exports = {
  //...
  externals: {
    jquery: 'jQuery',
  },
};
复制代码

这样就剥离了那些不需要改动的依赖模块,换句话,下面展示的代码还可以正常运行:

import $ from 'jquery';

$('.my-element').animate(/* ... */);
复制代码

IgnorePlugin

防止在 import 或 require 调用时,生成以下正则表达式匹配的模块:

  • requestRegExp 匹配(test)资源请求路径的正则表达式。
  • contextRegExp 匹配(test)资源上下文(目录)的正则表达式。

避免一些模块引入,从而节省打包的体积

例如:moment会支持多语言,如何只引入中文模块?

$ npm i moment -S  //安装
复制代码

配置 IgnorePlugin:

// 引入 webpack
const webpack = require('webpack')

const config = {
  ...
  plugins:[ // 配置插件
    ...
    // 忽略 moment 下的全部 /locale目录 
    new webpack.IgnorePlugin({
      resourceRegExp: /^\.\/locale$/,
      contextRegExp: /moment$/,
    }),
  ]  
};
复制代码

按需引入

// 业务代码中动态引入语言包 
import 'moment/locale/zh-cn' 
复制代码

缓存 cache

webpack cache 来缓存生成的 webpack 模块和 chunk,改善构建速度

//内存缓存
//dev模式下默认。编译缓存将保存在内存中。
module.exports = {
  cache: true, // 等价于cache: { type: 'memory' },
}

//文件缓存
//每次编译的结果都会序列化保存到 node_modules/.cache 目录下,
//当下次编译启动时会从 cache 反序列化加载,减少对机器内存的压力
module.exports = {
  cache: {
    type: 'filesystem', 
  },
}
复制代码

压缩 CSS

$ npm i css-minimizer-webpack-plugin -D
复制代码

修改 webapck.config.js 配置

// 压缩css
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const config = { 
    // ... 
    optimization: {
        // 默认仅生产环境开启 CSS 优化,minimize 设置为 true 开发环境下也启用
        minimize: true, 
        minimizer: [
          // 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释
          // `...`,
          new CssMinimizerPlugin(),
        ],
    },
    // ... 
}
复制代码

清除无用的 CSS

purgecss-webpack-plugin 会单独提取 CSS 并清除用不到的 CSS

$ npm i purgecss-webpack-plugin -D
复制代码

添加配置

const PurgecssWebpackPlugin = require('purgecss-webpack-plugin') 
const glob = require('glob'); // 文件匹配模式
复制代码

压缩 JS

👉 传送门

webpack v5 开箱即带有最新版本的 terser-webpack-plugin。如果你使用的是 webpack v5 或更高版本,同时希望自定义配置,那么仍需要安装 terser-webpack-plugin。如果使用 webpack v4,则必须安装 terser-webpack-plugin v4 的版本。

$ npm i terser-webpack-plugin -D //安装
复制代码

配置

const TerserPlugin = require("terser-webpack-plugin");
module.exports = {
  optimization: {
    minimize: true,
    minimizer: [new TerserPlugin()],
  },
};
复制代码

工具插件

查看编译进度

插件:progress-bar-webpack-plugin

$ npm i progress-bar-webpack-plugin -D //安装插件
复制代码

配置 webpack.common.js

const chalk = require('chalk')
const ProgressBarPlugin = require('progress-bar-webpack-plugin')
module.exports = {
  plugins: [
    // 编译进度条
    new ProgressBarPlugin({
        format: `:msg [:bar] ${chalk.green.bold(':percent')} (:elapsed s)`
      })
  ],
}
复制代码

编译即可看到效果

查看编译速度

插件: speed-measure-webpack-plugin

通过插件,可以看到各个 loader、plugin 的构建时长,后续可针对耗时 loader、plugin 进行优化。

$ npm i speed-measure-webpack-plugin -D //安装插件
复制代码

配置 webpack.dev.js

const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
module.exports =smp.wrap(merge(common, {
    mode: 'development', // 开发模式
    // ...webpack config...
}));
复制代码

不兼容,需要进行降级处理

查看打包体积

插件:webpack-bundle-analyzer

通过插件,查看打包后生成的 bundle 体积分析,将 bundle 内容展示为一个便捷的、交互式、可缩放的树状图形式。帮助我们分析输出结果来检查模块在何处结束。

$ npm i webpack-bundle-analyzer -D //插件安装
复制代码

配置 webpack.prod.js :

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = merge(common, {
    mode: 'production',// 生产模式
    plugins: [
        new BundleAnalyzerPlugin() // 打包体积分析
    ],
}) 
复制代码
分类:
前端
标签: