webpack 3 just shipped with a feature called "scope hoisting" that makes bundles smaller and faster. The technical improvement is modest—5-15% bundle size reduction in practice—but the symbolism is significant. webpack is acknowledging that bundle size matters, and the ecosystem is finally taking performance seriously.
What Is Scope Hoisting?
Scope hoisting (via the ModuleConcatenationPlugin) changes how webpack wraps modules. Previously, webpack wrapped each module in a function:
// webpack 2 output (simplified)
[
function(module, exports) {
// your module code
var foo = require('./other');
},
function(module, exports) {
// other module
module.exports = 'bar';
}
]
Each module gets its own scope. This is safe but bloated—lots of function wrappers and runtime overhead.
Scope hoisting flattens modules into a single scope when possible:
// webpack 3 with scope hoisting (simplified)
(function() {
var foo = 'bar'; // inlined from other module
// your module code
})();
Fewer function wrappers, smaller bundle, faster runtime. This is what Rollup has been doing for years.
The Rollup Influence
Rollup pioneered this technique (called "tree shaking" and "scope hoisting"). Rollup's selling point was always smaller bundles than webpack because it could eliminate dead code more aggressively.
webpack 2 added tree shaking, but it wasn't as effective as Rollup's. webpack 3's scope hoisting closes the gap. webpack is borrowing Rollup's best ideas while maintaining webpack's flexibility for complex applications.
This is healthy competition. Rollup pushed the ecosystem to care about bundle size. webpack responded.
How to Use It
Enable scope hoisting with the plugin:
// webpack.config.js
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.optimize.ModuleConcatenationPlugin()
]
};
It only works with ES2015 modules (import/export). If your code uses CommonJS (require/module.exports), scope hoisting can't optimize it. This incentivizes writing modern module syntax.
The Bundle Size Awakening
For years, JavaScript developers didn't think much about bundle size. Ship the code, let users deal with the download. But reality is catching up:
- Mobile users on slow networks suffer with large bundles
- Parse/compile time matters as much as download time
- Performance budgets are becoming standard
- User abandonment correlates with slow page load
The pendulum is swinging from "ship features fast" to "ship performant code."
webpack 3's scope hoisting is part of this trend. So is code splitting, lazy loading, and tree shaking. The ecosystem is realizing that bundle size is a feature.
Diminishing Returns
Scope hoisting's 5-15% size reduction is nice but not transformative. If your bundle is 2MB, you're not fixing it with scope hoisting. You need architectural changes:
- Code splitting by route
- Lazy loading non-critical features
- Removing dependencies (do you really need that 100KB library?)
- Tree shaking unused code
Scope hoisting is optimization. If you haven't done the big stuff (splitting, lazy loading), don't expect magic.
The Real Problem: Dependencies
The biggest bundle size problem isn't webpack's module wrapping—it's dependencies. Import one library and transitively pull in 500KB of code. Import moment.js and get every locale (160KB). Import lodash without tree shaking and get the entire library (70KB).
Tools like webpack-bundle-analyzer reveal the truth:
npm install --save-dev webpack-bundle-analyzer
Run it and see where your bundle bloat comes from. Usually it's a few giant dependencies.
The CommonJS Problem
Scope hoisting only works with ES modules. But huge swaths of npm are still CommonJS. Until the ecosystem migrates, scope hoisting's impact is limited.
This creates pressure: library authors need to ship ES modules alongside CommonJS. Some do (Lodash ships lodash-es). Most don't. Migration will take years.
webpack vs Rollup vs Parcel
The bundler landscape in mid-2017:
webpack: The incumbent. Powerful, flexible, complex. Massive ecosystem. Now with scope hoisting.
Rollup: Smaller bundles, simpler configs, less flexibility. Best for libraries. Growing but still niche.
Parcel: The new entrant. Zero config, fast, good defaults. Worth watching but too new to trust for production.
For most applications, webpack is still the answer. But Rollup and Parcel are pushing webpack to be better, and that benefits everyone.
Practical Recommendations
To actually reduce bundle size:
- Measure first – use webpack-bundle-analyzer
- Split code – per route, per feature
- Lazy load – defer non-critical code
- Tree shake – use ES modules, import only what you need
- Audit dependencies – remove unused libraries
- Enable scope hoisting – easy wins
Scope hoisting is step 6, not step 1. Do the big stuff first.
The Performance Budget Movement
More teams are adopting performance budgets:
- "Our JavaScript bundle can't exceed 200KB gzipped"
- "Page load must be under 3 seconds on 3G"
- "Time to interactive must be under 5 seconds"
These constraints force architectural discipline. You can't ship bloated bundles if you have a budget.
webpack 3 helps stay under budget, but it won't fix a fundamentally bloated architecture.
Looking Forward
webpack 4 is already in development with more ambitious performance goals. The trend is clear: bundlers are competing on output size and build speed.
This is good. For years, JavaScript tooling optimized for developer experience (DX) at the expense of user experience (UX). Now both matter.
Should You Upgrade?
webpack 3 is a minor version bump from webpack 2. Upgrading should be straightforward:
npm install --save-dev webpack@3
Enable scope hoisting, test your build, deploy. For most projects, it's a few minutes of work for a 5-15% bundle size reduction.
Is it worth it? Depends:
- Small bundles (< 100KB): Don't bother, the wins are tiny
- Medium bundles (100-500KB): Worth it for the easy wins
- Large bundles (> 500KB): Do it, but also address the architectural issues
The real value of webpack 3 is symbolic: the ecosystem is taking performance seriously. Scope hoisting is just one step in that direction.
For detailed documentation, see the webpack 3 release notes and Module Concatenation Plugin docs.