webpack的性能优化

221 阅读5分钟
  1. 常规

    1. 保持版本最新,如webpack、node.js、npm或yarn;
    2. 将loaders应用于最少数的必要模块中;
    3. 尽量少使用不同的工具,每个额外的loader/plugin都有启动时间;
    4. 尽量减少resolve.modules、resolve.extensions、resolve.mainFiles、resolve.descriptionFiles中类目的数量,因为他们会增加文件系统的调用次数;如果你使用自定义解析plugins,并且没有指定context信息,可以设置resolve.cacheWithContext:false;
    5. 使用DllPlugins将更改不频繁的代码进行单独编译;
    6. smaller = faster,减少编译的整体大小,提升构建性能
      1. 使用更小/更少的库;
      2. 在多页面应用程序中使用commonsChunksPlugin;以async模式启用commonsChunksPlugin;
      3. 移除不使用的代码;
      4. 只编译你当前正在开发部部分的代码;
    7. thread-loader或happy pack可以将非常消耗资源的loaders转存到worker pool中,但不要使用太多的workers,因为node.js的runtime和loader有一定的启动开销,进程间通讯也是很消耗资源的;
    8. 使用cache-loader 启用持久化缓存,使用package.json中的“postinstall”清除缓存目录;
    9. 自定义plugins/loaders;
    10. code split
      1. 入口起点;
      2. 懒加载
        • 在特定条件下进行动态导入(import()、require.ensure()),如点击打印时导入打印模块;
        • 使用babel时需要使用@babel/plugin-syntax-dynamic-import来允许babel解析动态导入;
        • 使用babel-plugin-import按需导入模块,与antd、antd-mobile、antd-vue、lodash等兼容;
        • 在react中配合import使用React.lazy或loadable-components实现按需导入和加载组件;
        • 在vue中注册组件时使用import()代替默认组件书写形式;
      3. 防止重复(splitChuunks、commonChunksPlugin、ExtractTextPlugin、bundle-loader、promise-loader);
    11. tree shaking
    12. webpack cache,布尔值或对象,属于webpack顶层配置,用来缓存生成的模块和chunk,默认在观察模式启用。
    13. 使用浏览器缓存的相关配置
      1. 输出文件名带有相关hash,如hash、chunkHash;
      2. 提取boilerplate(即样板,webpack 运行时的引导代码),webpack的入口chunk包含了某些样板,特别是runtime和manifest,可以使用CommonsChunkPlugin进行提取(name="manifest")或optimization.runtimeChunk;
      3. 锁定模块标识符,当模块内容未更新时,使用HashedmoduleIdsPlugin(根据模块的相对路径生成一个四位数的hash作为模块id, 建议用于生产环境)或NamedModulesPlugin(使用该插件会显示模块的相对路径,建议用于开发环境);
    14. optimization优化(webpack 4会根据mode值自动执行不同优化)
      1. optimization.minimize,告知webpack使用TerserPlugin或其他在optimization.minimizer定义的插件压缩bundle,mode=production时为true。
      2. optimization.minimizer,允许你通过提供一个或多个定制过的TerserPlugin实例,覆盖默认的压缩工具(minimizer)。
      3. optimization.runtimeChunk,设为true时会为仅含有样板(见上文)的每个入口起点添加一个额外的chunk;
      4. optimization.splitChunks(webpack在V4版本之前是可以使用commonsChunksPlugin进行避免重复模块的依赖,但进一步优化貌似不可行,V4后丢弃了commonsChunksPlugin转而使用optimization.splitChunks和optimization.runtimeChunk)
        1. optimization.splitChunks是开箱即用的,默认情况下只会影响按需加载的模块;
        2. 具体属性:
          1. name(设置被拆分出来的chunk的名称,默认为true);
          2. chunks(设置chunks拆分的范围,initial:只在作为entry 的模块中应用拆分规则;async:默认值,只在异步加载的模块中应用拆分规则,all:以上两者均包括);
          3. miniSize 待生成块的最小体积(字节),默认为20000bytes;
          4. minReaminingSize 当前待拆分块的保留最小体积,防止体积为0的模块;
          5. minChunks 模块被共同引用到chunk的最小chunk数量。
          6. maxAsyncRequests(异步加载模块内的最大并行请求chunk的数量,异步加载模块本身对应的chunk也算其内请求)
          7. maxInitialRequsts(入口模块内的最大并行请求chunk的数量,入口模块本身对应的chunk也算其内请求)
          8. automaticNameDelimiter(chunk命名分隔符,默认为“~”);
          9. enforceSizeThreshold 强制执行拆分的体积阈值和其他限制将被忽略;
          10. cacheGroups,用来分组式地配置chunk拆分规则,继承optimization.splitChunks上的拆分规则。存在default和defaultVendors两个自带的缓存组。可以禁用默认default缓存组(default:false)和自定义缓存组,cacheGroups配置如下:
            1. test 路径匹配
            2. priority 缓存组的优先级,值越大优先级越高,高优先级的缓存组优先被匹配。
            3. reuseExistingChunk 是否复用已经被打包的chunk
            4. …optimization.splitChunks配置项
          11. splitChunks 默认配置如下(webpack v5): image.png
  2. development

    1. 最小化入口chunk,可以使用commonsChunksPlugin提取boilerplate来减少入口chunk体积;
    2. 增量编译(热更新);
    3. 在内存中编译;
      • webpack-dev-server
      • webpack-hot-middleware
      • webpack-dev-middleware
    4. devtool设为eval-source-map;
    5. 避免在生产环境下才会用到的工具(压缩代码、提取文件、hash\chunkhash、拆分bundle等);
      • UglifyJsPlugin
      • ExtractTextPlugin
      • [hash]/[chunkhash]
      • AggressiveSplittingPlugin
      • AggressiveMergingPlugin
      • ModuleConcatenationPlugin
  3. production

    1. 多个编译时:
      1. parallel-webpack: 它允许编译工作在 worker 池中进行并行构建多个配置;
      2. cache-loader: 缓存可以在多个编译时之间共享;
    2. devtool设为nosources-source-map;
    3. mode设为production;

注释

terser-webpack-plugin的作用?答:

terser-webpack-plugin 内部使用了terser来压缩javaScript,terser 是适用于ES6及ES6+的javaScript解析器和压缩器,它是一个借助于uglify-es 和uglify-js@3的拥有兼容性API和CLI的uglify-es的分支(uglify-es 不再维护并且 uglify-js 不支持ES6及ES6+,常规的js压缩基本都是基于此两者,如webpack.optimize.UglifyJsPlugin)。