likes
comments
collection
share

webpack优化思路(学习笔记)

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

高频面试题:webpack了解多少,如何通过webpack做优化?

一、速度指标

1.webpack的stats

颗粒度比较粗的分析构建速度

"build:stats": "webpack --profile --json=compilation-stats.json"

2.webpack的speed-measure-webpack-plugin

  • 分析整个打包总耗时
  • 每个插件和loader的耗时情况
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");

const smp = new SpeedMeasurePlugin();

const webpackConfig = smp.wrap({
  plugins: [new MyPlugin(), new MyOtherPlugin()],
});

3.webpack的webpack-bundle-analyzer

  • 依赖的第三方模块文件大小
  • 业务里面的组件代码大小
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin()
  ]
}

二、构建速度

1.多进程/多实例解析资源:thread-loader

  • 作用:提升构建速度
  • 原理:webpack每次解析一个模块时,thread-loader会将它的依赖分配给worker线程中
{
    test: /.js$/,
    use: [
        {
            loader: 'thread-loader',
            options: {
                workers: 2
            }
        },
        'babel-loader'
    ]
},

2.多进程/多实例压缩:terser-webpack-plugin

  • 作用:提升构建速度
const TerserPlugin = require("terser-webpack-plugin");
optimization: {
    minimizer: [
        new TerserPlugin({
            parallel: true,
        })
    ],
},

三、打包体积

1.SplitChunksPlugin

可以用来分离公共的资源或者公共的方法,减少代码体积,例如:

module.exports = {
  //...
  optimization: {
    splitChunks: {
        cacheGroups: {
          commons: {
            test: /(react|react-dom)/,
            name: 'vendors',
            chunks: 'all',
          }
        },
    }
  },
};

2.three-shaking

作用:擦除以下代码

  • 代码不会被执行,不可到达
  • 代码执行的结果不会被用到
  • 代码只会影响死变量(只写不读)

原理:利用ES6模块的特点,对代码在ast阶段进行今天分析

  • 只能作为模块顶层的语句出现
  • import的模块名只能是字符串常量
  • import binding是immutable的 触发:只需要打开mode:'production'

3.Scope Hoisting

作用:webpack打包后的代码会以闭包的形式存在,通过scope hoisting可以减少函数声明开销和内存开销

原理:将所有模块的代码按照引用顺序放在一个函数作用域里,然后适当的重命名一些变量以防止变量名冲突 触发:

  • 自动:只需要打开mode:'production'
  • 手动: 在plugins中增加以下代码
new webpack.optimize.ModuleConcatenationPlugin();

4.代码分割和动态import

webpack可以将代码分割成chunks,当代码运行到需要它们的时候再进行加载,适用场景是:

  • 抽离相同的代码到一个共享块
  • 脚本懒加载,使得初始下载的代码更小 启动:
  • 如果再.babelrc中的preset中有@babel/preset-env,那么就已经默认支持了dynamic import
{
    "presets": [
        "@babel/preset-env"
    ],
    "plugins": []
}
  • 如果仅仅只是转译import,那么,只需要在.babelrc的plugins中加入 @babel/plugin-syntax-dynamic-import
{
    "presets": [],
    "plugins": [
        "@babel/plugin-syntax-dynamic-import"
    ]
}

这个包即可

5.CSS的擦除:purgecss-webpack-plugin

const PurgeCSSPlugin = require('purgecss-webpack-plugin')
const PATHS = {
    src: path.join(__dirname, 'src')
}
// ...
plugins: [
    new PurgeCSSPlugin({
        paths: glob.sync(`${PATHS.src}/**/*`,  { nodir: true }),
    }),
]

6.图片压缩:image-webpack-loader

rules: [{
  test: /\.(gif|png|jpe?g|svg)$/i,
  use: [
    'file-loader',
    {
      loader: 'image-webpack-loader',
      options: {
        mozjpeg: {
          progressive: true,
        },
        // optipng.enabled: false will disable optipng
        optipng: {
          enabled: false,
        },
        pngquant: {
          quality: [0.65, 0.90],
          speed: 4
        },
        gifsicle: {
          interlaced: false,
        },
        // the webp option will enable WEBP
        webp: {
          quality: 75
        }
      }
    },
  ],
}]

7.动态babel-pollyfill

每一个设备终端可能对于babel-pollyfill的需求不一样,甚至不需要,那么,动态babel-pollyfill需要通过User Agent的判断,进行按需加载。 比如:

<script scr="http://cdn.polyfill.io/v2/polyfill.min.js"></script>

总结:当前构建体积方案的方式有

  • 1.SplitChunksPlugin
  • 2.three-shaking
  • 3.Scope Hoisting
  • 4.动态import按需加载
  • 5.CSS的擦除:purgecss-webpack-plugin
  • 6.图片压缩:image-webpack-loader
  • 7.动态babel-pollyfill