Unpacking Webpack

2019/08/14 (Edit 2019/08/27)
webpack, profiling, plugin, optimization
Some tip for hacking Webpack.

Here's some tip for hacking Webpack

this is for webpack@4, and works better for big webpack project (compile time above 1.5 min) also, though it's not well organized, do read ALL of the webpack doc.

better understand what happened

with ProgressPlugin and some code, you can get a rough idea of that is being processed:

const createProgressPlugin = () => {
  const timeStart = Date.now()
  let timePrev = timeStart
  return new webpack.ProgressPlugin((percentage, message, ...args) => {
    const timeNow = Date.now()
    if (timeNow - timePrev <= 200) return // debounce, 200ms, drop for every progress update
    console.log(`[${Math.round(percentage * 100)}%|${timeNow - timeStart}ms|+${timeNow - timePrev}ms] ${message} - ${args.join(' ')}`)
    timePrev = timeNow
  })
}

for not-that-big project, with debug.ProfilingPlugin, a detailed timeline can be generated: (but if the output json exceeds 300MiB, Chrome Devtool may just crash loading)

new webpack.debug.ProfilingPlugin({
  // view in Chrome DevTools, should start with: `Chromium --args --js-flags="--max_old_space_size=6144"`
  // check: https://github.com/webpack/webpack/issues/7689#issuecomment-459117090
  outputPath: '__PROFILING_EVENTS__.json' // very big json
})

with process monitor like htop, check the process CPU usage, better make sure the CPU is fully utilized, especially when multi-thread is enabled.

multi-thread loader magic

use cache-loader before thread-loader, load the cache (fs+gunzip) is not that costly, reversing the order is slower

when using thread-loader, consider passing most file through it, including normally excluded node_modules js files, and consider set parallelism: 512, so enough pending module can be found, and keep all thread busy

some loader/plugin do not work well with thread-loader, make sure exclude loader/plugin with function in config from thread-loader

minimal plugin

if plugin is not needed in current build, do not pass it in the plugin array and disable it, instead consider remove it, and skip require it is much better