Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

你应该知道的几个webpack优化方法 #16

Open
JCHappytime opened this issue Feb 24, 2021 · 0 comments
Open

你应该知道的几个webpack优化方法 #16

JCHappytime opened this issue Feb 24, 2021 · 0 comments
Labels
webpack webpack工程化常见问题

Comments

@JCHappytime
Copy link
Owner

JCHappytime commented Feb 24, 2021

参考文章

  1. webpack-bundle-analyzer插件快速入门
  2. 使用 happypack 提升 Webpack 项目构建速度
  3. 更多优化方法(如动态dll等等)请参考Cosen95大神的文章,小弟也是一枚搬运工

前言

本文主要介绍几个在前端工程构建过程中非常显著的一些插件,帮助提升webpack的构建速度以及深入分析影响速度的原因。但在继续下面的内容之前,也需要充分的了解一下webpack的实现原理,这篇文章已经叙述得非常仔细,我也先去膜拜一下再来继续了。

1. 速度分析

webpack有时候打包很慢,因为我们在项目中可能使用了非常多的plugin和loader,想知道具体是哪个环节慢,下面这个插件就可以计算plugin和loader的耗时。

yarn add -D speed-measure-webpack-plugin

配置也很简单,将webpack配置对象包裹起来即可:

const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");

const smp = new SpeedMeasurePlugin();

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

在项目中华引入speed-measure-webpack-plugin后,它完成的主要工作是:

  • 计算整体打包总耗时;
  • 分析每个插件和loader的耗时情况;
    知道了具体plugin和loader的耗时情况,就可以对症下药了。

2. 体积分析

打包后的体积优化是一个可以着重优化的方向,比如引入的一些第三方组件库体积过大,这个时候就要考虑是否寻求替代品了。
这里采用的是webpack-bundle-analyzer,它可以用交互式可缩放树形图来显示webpack输出文件的大小,用起来非常方便。
安装插件:

yarn add -D webpack-bundle-analyzer

安装完成之后再在webpack.config.js中简单的配置一下:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  plugins: [
    // 可以是server, static或者disabled
    // 在server模式下:分析器会启动HTTP服务器来显示软件报告;
    // 在static模式下:会生成带有报告的单个HTML文件;
    // 在disabled模式下:可以使用这个插件将generateStatsFile设置为true来生成Webpack Stats JSON文件;
    analyaerMode: 'server',
    //  将在“服务器”模式下使用的主机启动HTTP服务器。
    analyzerHost: "127.0.0.1",
    //  将在“服务器”模式下使用的端口启动HTTP服务器。
    analyzerPort: 8866,
    //  路径捆绑,将在`static`模式下生成的报告文件。
    //  相对于捆绑输出目录。
    reportFilename: "report.html",
    //  模块大小默认显示在报告中。
    //  应该是`stat`,`parsed`或者`gzip`中的一个。
    //  有关更多信息,请参见“定义”一节。
    defaultSizes: "parsed",
    //  在默认浏览器中自动打开报告
    openAnalyzer: true,
    //  如果为true,则Webpack Stats JSON文件将在bundle输出目录中生成
    generateStatsFile: false,
    //  如果`generateStatsFile`为`true`,将会生成Webpack Stats JSON文件的名字。
    //  相对于捆绑输出目录。
    statsFilename: "stats.json",
    //  stats.toJson()方法的选项。
    //  例如,您可以使用`source:false`选项排除统计文件中模块的来源。
    statsOptions: null,
    logLevel: "info"
 ],
};

如果想要查看更多选项,请参照官方文档
然后,我们在控制台中输入: npm run dev / yarn dev,它就会默认起一个端口号为8888的本地服务器,图中的每一块都清晰的展示了组件、第三方库的代码体积。有了它之后,我们就能针对体积偏大的模块进行相关的优化了。

3. HappyPack

安装:

yarn add -D hapyppack

HappyPack可以让webpack同一时间处理多个任务,发挥多核CPU的能力,将任务分解给多个子进程去并发的执行,子进程处理完后,再把结果发送给主进程。通过多进程模型,来达到加速构建代码的目的。
示例:

// webpack.config.js
const HappyPack = require('happypack');

exports.module = {
  rules: [
    {
      test: /.js$/,
      // 1) replace your original list of loaders with "happypack/loader":
      // loaders: [ 'babel-loader?presets[]=es2015' ],
      use: 'happypack/loader',
      include: [ /* ... */ ],
      exclude: [ /* ... */ ]
    }
  ]
};

exports.plugins = [
  // 2) create the plugin:
  new HappyPack({
    // 3) re-add the loaders you replaced above in #1:
    loaders: [ 'babel-loader?presets[]=es2015' ]
  })
];

遗憾的是,HappyPack作者表示不再维护此项目了,同时他也推荐使用webpack官方提供的thread-loader,但thread-loader 和 happypack 对于小型项目来说打包速度几乎没有影响,甚至可能会增加开销,所以建议尽量在大项目中采用。

4. 多进程并行压缩代码

一般而言,在我们的开发环境中,代码构建时间比较快,而构建用于发布到线上的代码时会添加压缩这个流程,则会导致计算量大、耗时多。
webpack提供了UglifyJS插件来压缩JS代码,但是它使用的是单线程压缩代码,也就是说多个js文件需要被压缩,它需要一个个文件进行压缩。所以说在正式环境打包压缩代码的速度非常慢(因为压缩JS代码需要先把代码解析成用Object抽象表示的AST语法树,在应用各种规则分析和处理AST,导致这个过程耗时非常大。)
所以要对压缩代码这一块做优化,常用的方法就是多进程并行压缩。目前有三种压缩方案:

  • parallel-uglify-plugin
  • uglifyjs-webpack-plugin
  • terser-webpack-plugin

4.1 parallel-uglify-plugin

上面介绍的HappyPack的思想是使用多个子进程去解析和编译JS,CSS等,这样就可以并行处理多个子任务,多个子任务完成后,再将结果发到主进程中,有了这个思想后,ParallelUglifyPlugin 插件就产生了。

当webpack有多个JS文件需要输出和压缩时,原来会使用UglifyJS去一个个压缩并且输出,而ParallelUglifyPlugin插件则会开启多个子进程,把对多个文件压缩的工作分给多个子进程去完成,但是每个子进程还是通过UglifyJS去压缩代码。并行压缩可以显著的提升效率。
安装:

yarn add -D webpack-parallel-uglify-plugin

使用示例:

import ParallelUglifyPlugin from 'webpack-parallel-uglify-plugin';

module.exports = {
  plugins: [
    new ParallelUglifyPlugin({
      // Optional regex, or array of regex to match file against. Only matching files get minified.
      // Defaults to /.js$/, any file ending in .js.
      test,
      include, // Optional regex, or array of regex to include in minification. Only matching files get minified.
      exclude, // Optional regex, or array of regex to exclude from minification. Matching files are not minified.
      cacheDir, // Optional absolute path to use as a cache. If not provided, caching will not be used.
      workerCount, // Optional int. Number of workers to run uglify. Defaults to num of cpus - 1 or asset count (whichever is smaller)
      sourceMap, // Optional Boolean. This slows down the compilation. Defaults to false.
      uglifyJS: {
        // These pass straight through to uglify-js@3.
        // Cannot be used with uglifyES.
        // Defaults to {} if not neither uglifyJS or uglifyES are provided.
        // You should use this option if you need to ensure es5 support. uglify-js will produce an error message
        // if it comes across any es6 code that it can't parse.
      },
      uglifyES: {
        // These pass straight through to uglify-es.
        // Cannot be used with uglifyJS.
        // uglify-es is a version of uglify that understands newer es6 syntax. You should use this option if the
        // files that you're minifying do not need to run in older browsers/versions of node.
      }
    }),
  ],
};

注意: webpack-parallel-uglify-plugin已不再维护,不推荐再继续使用。

4.2 uglifyjs-webpack-plugin

安装:

yarn add -D uglifyjs-webpack-plugin

示例:

const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
  plugins: [
    new UglifyJsPlugin({
      uglifyOptions: {
        warnings: false,
        parse: {},
        compress: {},
        ie8: false
      },
      parallel: true
    })
  ]
};

其实它和上面的parallel-uglify-plugin类似,也可通过设置parallel: true开启多进程压缩。

4.3 terser-webpack-plugin

其实webpack4已经默认支持es6语法的压缩,这离不开terser-webpack-plugin。
安装:

yarn add -D terser-webpack-plugin

示例:

const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        parallel: 4,
      }),
    ],
  },
};
@JCHappytime JCHappytime added the webpack webpack工程化常见问题 label Feb 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
webpack webpack工程化常见问题
Projects
None yet
Development

No branches or pull requests

1 participant