Our shared internal webpack configuration had grown, plugin by plugin and project by project, into something nobody fully understood anymore. Webpack 4's improved defaults — automatic mode-based optimization, no more mandatory `CommonsChunkPlugin` juggling — gave us a good reason to rewrite it from scratch instead of patching the old one further, treating this version bump as a deliberate excuse for a cleanup rather than just another routine dependency update.
The new version is meaningfully shorter, relies on webpack's own sensible defaults wherever we do not have a specific reason to override them, and documents every remaining custom plugin with a comment explaining why it exists. That last part mattered more than we expected going in — several plugins in the old configuration had no clear justification anyone on the current team could reconstruct, and a couple turned out to be entirely unnecessary once we actually tried removing them and nothing broke.
What we specifically removed and why
- A manually configured `CommonsChunkPlugin` setup, replaced entirely by webpack 4's automatic `SplitChunksPlugin` defaults, which produced comparable or better code-splitting results with zero custom configuration
- Two separate loader configurations for handling the same file type slightly differently across projects, consolidated into a single, well-documented configuration once we traced the divergence back to a one-off requirement from a single old project that no longer applied
- A custom environment-variable injection plugin, replaced by webpack's own built-in `DefinePlugin`, which did the same job with less custom code to maintain
It has already been forked into three new client projects without a single "wait, why is this here" question from the team, which the old config could not say. We are treating this rewrite as a reset point going forward, with a stated intention to review and prune the shared configuration at least once a year rather than letting it accumulate undocumented additions the way the previous version quietly did over roughly two years of incremental changes.
Measuring the actual build-time improvement
We timed a full production build of our largest active client project against both the old configuration and the new one, on the same machine under the same conditions, specifically to have a real number rather than a vague impression to back up the rewrite. The new configuration's build finished meaningfully faster, most of the improvement coming from webpack 4's smarter default caching behavior rather than anything we specifically tuned ourselves, which was a pleasant surprise given how much of the old configuration's complexity had been aimed at manually solving problems the new defaults already handle.
Documenting the decision, not just the configuration
Alongside the configuration file itself, we wrote a short internal document explaining why each remaining custom plugin exists and what would break if it were removed, specifically so a future cleanup effort does not have to rediscover that context by trial and error the way we just did with the old configuration. A comment in the config file itself covers the immediate "why is this here," but the longer document covers the more important "what happens if someone removes this later," which is the exact question the old configuration left completely unanswered for the plugins nobody could confidently explain.
A rollback plan we insisted on before shipping this everywhere
Before forking the new configuration into every active project, we kept the old configuration available in a tagged branch for each project it replaced, purely as a safety net in case a subtle behavioral difference surfaced on a project with unusual requirements the three initial forks did not happen to exercise. We have not needed it yet, but treating a shared-infrastructure change like this with the same rollback discipline we would apply to a production deploy felt like the right level of caution given how many projects now depend on this same file.