webpack不仅可以优化构建速度,也可优化项目性能,是项目优化的重要一环。

构建速度优化

常见方法有:

  • 优化loader配置
  • 合理使用resolve.extensions
  • 优化resolve.modules
  • 优化resolve.alias
  • 使用DLLPlugin插件
  • 使用cache-laoder
  • terser启用多线程
  • 合理使用sourceMap
    优化loader配置
    在使用loader时通过配置include、exclude等
    如babel-loader
    1. module.exports = {
    2. module: {
    3. rules: [
    4. {
    5. // 如果项目源码中只有 js 文件就不要写成 /\.jsx?$/,提升正则表达式性能
    6. test: /\.js$/,
    7. // babel-loader 支持缓存转换出的结果,通过 cacheDirectory 选项开启
    8. use: ['babel-loader?cacheDirectory'],
    9. // 只对项目根目录下的 src 目录中的文件采用 babel-loader
    10. include: path.resolve(__dirname, 'src'),
    11. },
    12. ]
    13. },
    14. };
    合理使用resolve.extensions
    在解析无扩展名文件时指定文件扩展名
    1. module.exports = {
    2. ...
    3. extensions:[".warm",".mjs",".js",".json"]
    4. }
    :::warning 不可随意将所有扩展名写入 :::
    优化resolve.modules
    指定第三方依赖所在路径
    1. module.exports = {
    2. resolve: {
    3. // 使用绝对路径指明第三方模块存放的位置,以减少搜索步骤
    4. // 其中 __dirname 表示当前工作目录,也就是项目根目录
    5. modules: [path.resolve(__dirname, 'node_modules')]
    6. },
    7. };
    优化resolve.alias
    为常用路径添加别名
    1. module.exports = {
    2. ...
    3. resolve:{
    4. alias:{
    5. "@":path.resolve(__dirname,'./src')
    6. }
    7. }
    8. }
    使用DLLPlugin插件
    DLL全称动态链接库,旨在实现共享函数库。将不常改变的带边抽成一个共享的库。
    打包DLL库
    使用webpack内置的DllPlugin
    1. module.exports = {
    2. ...
    3. plugins:[
    4. new webpack.DllPlugin({
    5. name:'dll_[name]',
    6. path:path.resolve(__dirname,"./dll/[name].mainfest.json")
    7. })
    8. ]
    9. }
    引入DLL库
    使用内置的DLLReferencePluginmainfest.json解析,找到需要的DLL库并通过AddAssetHtmlPlugin添加到html中
    1. module.exports = {
    2. ...
    3. new webpack.DllReferencePlugin({
    4. context:path.resolve(__dirname,"./dll/dll_react.js"),
    5. mainfest:path.resolve(__dirname,"./dll/react.mainfest.json")
    6. }),
    7. new AddAssetHtmlPlugin({
    8. outputPath:"./auto",
    9. filepath:path.resolve(__dirname,"./dll/dll_react.js")
    10. })
    11. }
    使用cache-laoder
    在一些性能开销较大的loader之前使用cache-loader,提升二次构建速度。
    1. module.exports = {
    2. module: {
    3. rules: [
    4. {
    5. test: /\.ext$/,
    6. use: ['cache-loader', ...loaders],
    7. include: path.resolve('src'),
    8. },
    9. ],
    10. },
    11. };
    terser启用多线程
    1. module.exports = {
    2. optimization: {
    3. minimizer: [
    4. new TerserPlugin({
    5. parallel: true,
    6. }),
    7. ],
    8. },
    9. };
    合理使用sourceMap
    devtool配置获取的信息越详细使构建速度越慢,所以需合理配置devtool

项目性能优化

  • js、css、html代码压缩
  • 图片压缩
  • 文件大小压缩
  • TreeShaking
  • 代码分离
  • 内联chunk

    js、css、html代码压缩

    ```javascript // js // 使用terser工具集,它可以丑化、压缩js代码 // production模式下默认使用 const TerserPlugin = require(‘terser-webpack-plugin’) module.exports = { … optimization: {
    1. minimize: true,
    2. minimizer: [
    3. new TerserPlugin({
    4. parallel: true, // 开启多线程构建,默认值为电脑cpu核数-1
    5. compress: true, // 开启压缩
    6. mangle: true, // 开启代码丑化
    7. ...
    8. })
    9. ]
    } }
```javascript
// css
// yarn add css-minimizer-webpack-plugin -D 安装依赖
// css代码优化主要为去除空格等
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
module.exports = {
    // ...
    optimization: {
        minimize: true,
        minimizer: [
            new CssMinimizerPlugin({
                parallel: true
            })
        ]
    }
}
// html
// 通过HtmlWebpackPlugin设置
module.exports = {
    ...
    plugin:[
        new HtmlWebpackPlugin({
            ...
            minify:{
                minifyCSS:false, // 是否压缩css
                collapseWhitespace:false, // 是否折叠空格
                removeComments:true // 是否移除注释
            }
        })
    ]
}

图片压缩
module: {
  rules: [
    {
      test: /\.(png|jpg|gif)$/,
      use: [
        {
          loader: 'file-loader',
          options: {
            name: '[name]_[hash].[ext]',
            outputPath: 'images/',
          }
        },
        {
          loader: 'image-webpack-loader',
          options: {
            // 压缩 jpeg 的配置
            mozjpeg: {
              progressive: true,
              quality: 65
            },
            // 使用 imagemin**-optipng 压缩 png,enable: false 为关闭
            optipng: {
              enabled: false,
            },
            // 使用 imagemin-pngquant 压缩 png
            pngquant: {
              quality: '65-90',
              speed: 4
            },
            // 压缩 gif 的配置
            gifsicle: {
              interlaced: false,
            },
            // 开启 webp,会把 jpg 和 png 图片压缩为 webp 格式
            webp: {
              quality: 75
            }
          }
        }
      ]
    },
  ]
}

文件大小压缩
// yarn add compression-webpack-plugin -D 安装依赖
new ComepressionPlugin({
    test:/\.(css|js)$/,  // 哪些文件需要压缩
    threshold:500, // 设置文件多大开始压缩
    minRatio:0.7, // 至少压缩的比例
    algorithm:"gzip", // 采用的压缩算法
})

TreeShaking

依赖于ES Module的静态语法分析,消除死代码

  • usedExports:通过标记某段代码是否被使用,后使用terser优化
  • sideEffects:直接查看该文件时候存在副作用
    usedExports
    配置
    module.exports = {
      ...
      optimization:{
          usedExports
      }
    }
    
    新建app.js,添加方法并导出 ```javascript function app () { console.log(‘app’) }

function showAppName () { console.log(‘appName’) }

export { app, showAppName }

在index.js中导入
```javascript
import { app, showAppName } from './app'

window.onload = function () {
  console.log('1');
  console.log('2');
  showAppName();
}

function unusedFn () {
  console.log('ha');
}

在开发模式下即mode: development打包,可以看到未被使用的代码被添加了unused harmony export app如下:
image.png
image.png
此处index.js自身未使用的方法未被添加注释。
再使用生产模式打包,如下:
image.png
生产模式打包,未使用的代码被删除。

sideEffects

在package.json中添加sideEffects

"sideEffects": [
  "**/*.css",
  "**/*.scss",
  "./esnext/index.js",
  "./esnext/configure.js"
],

sideEffects表示这些文件内容具有副作用,在它们未被引用使用的时候也需要编译打包它们而不是舍弃。

usedExports与sideEffects

它们是两种不同的优化方法。
sideEffects更为有效,因为它允许跳过整个模块/文件;
usedExports依赖于terser插件对语句副作用的检测。

代码分离

通过splitChunksPlugin来分离代码,默认为☞针对async模块

module.exports = {
    ...
    optimization:{
        splitChunks:{
            chunks:"all"
        }
    }
}

内联chunk

使用inlineChunkHtmlPlugin内联一些必须添加的chunk模块

const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    ...
    plugin:[
        new InlineChunkHtmlPlugin(HtmlWebpackPlugin,[/runtime.+\.js/]
}