splitChunks defaults are usually right

CommonsChunkPlugin required declaring which modules were common, which meant knowing the dependency graph in advance and updating the configuration whenever it changed.

optimization: {
  splitChunks: {
    chunks: 'all',      // the one change worth making to the defaults
  },
},

// the defaults already: split node_modules, split anything shared
// by 2+ chunks, keep chunks over 30KB, cap parallel requests

chunks: 'all' lets it split synchronous imports as well as dynamic ones, which is what most applications want and is not the default for compatibility reasons. Beyond that, tuning it before measuring is guesswork — the heuristics were derived from real applications and beat an intuition about what should be shared. The one case that reliably needs manual grouping is a vendor bundle you want cached separately because it changes far less often than the application code.