Printable
Blog
Read here for announcements.
See recent blog posts in the side bar.
Webpack 5 release
Webpack 4 was released in February 2018. Since then we shipped a lot of features without breaking changes. We know that people dislike major changes with breaking changes. Especially with webpack, which people usually only touch twice a year, and the remaining time it "just works". But shipping features without breaking changes also has a cost: We can't do major API or architectural improvements.
So from time to time, there is a point where the difficulties pile up and we are forced to do breaking changes to not mess everything up. That's the time for a new major version. So webpack 5 contains these architectural improvements and the features that were not possible to implement without them.
The major version was also the chance to revise some of the defaults and to align with proposals and specifications that come up in the meantime.
So today (2020-10-10) webpack 5.0.0 is released, but this doesn't mean it's done, bugfree or even feature-complete. As with webpack 4 we continue development by fixing problems and adding features. In the next days there will probably be a lot bugfixes. Features will come later.
Common Questions
So what does the release mean?
It means we finished doing breaking changes. Many refactorings have been done to up-level the architecture and create a good base for future features (and current features).
So when is the time to upgrade?
It depends. There is a good chance that upgrading fails and you would need to give it a second or 3rd try. If you are open to that, try to upgrade now and provide feedback to webpack, plugins and loaders. We are eager to fix those problems. Someone has to start and you would be one of the first ones benefiting from it.
Sponsoring Update
Webpack is fully based upon sponsoring. It's not tied to (and paid by) a big company like some other Open Source projects. 99% of the earnings from sponsoring are distributed towards contributors and maintainers based on the contributions they do. We believe in investing the money towards making webpack better.
But there is a pandemic, and companies ain't that much open to sponsoring anymore. Webpack is suffering under these circumstances too (like many other companies and people).
We were never able to pay our contributors the amount we think they deserve, but now we only have half of the money available, so we need to make a more serious cut. Until the situation improves we will only pay contributors and maintainers the first 10 days of each month. The remaining days they could work voluntarily, paid by their employer, work on something else, or take some days off. This allows us to pay for their work in the first 10 days more equivalent to the invested time.
The biggest "Thank You" goes to trivago which has been sponsoring webpack a huge amount for the last 3 years. Sadly they are unable to continue their sponsorship this year, as they have been hit hard by Covid-19. I hope some other company steps up and follows these (gigantic) footsteps.
Thanks to all the sponsors.
General direction
This release focus on the following:
- Improve build performance with Persistent Caching.
- Improve Long Term Caching with better algorithms and defaults.
- Improve bundle size with better Tree Shaking and Code Generation.
- Improve compatibility with the web platform.
- Clean up internal structures that were left in a weird state while implementing features in v4 without introducing any breaking changes.
- Prepare for future features by introducing breaking changes now, allowing us to stay on v5 for as long as possible.
Migration Guide
See here for a migration guide
Major Changes: Removals
Removed Deprecated Items
All items deprecated in v4 were removed.
MIGRATION: Make sure that your webpack 4 build does not print deprecation warnings.
Here are a few things that were removed but did not have deprecation warnings in v4:
- IgnorePlugin and BannerPlugin must now be passed only one argument that can be an object, string or function.
Deprecation codes
New deprecations include a deprecation code so they are easier to reference.
Syntax deprecated
require.include has been deprecated and will emit a warning by default when used.
Behavior can be changed with Rule.parser.requireInclude to allowed, deprecated or disabled.
Automatic Node.js Polyfills Removed
In the early days, webpack's aim was to allow running most Node.js modules in the browser, but the module landscape changed and many module uses are now written mainly for frontend purposes. Webpack <= 4 ships with polyfills for many of the Node.js core modules, which are automatically applied once a module uses any of the core modules (i.e. the crypto module).
While this makes using modules written for Node.js easier, it adds these huge polyfills to the bundle. In many cases these polyfills are unnecessary.
Webpack 5 stops automatically polyfilling these core modules and focus on frontend-compatible modules. Our goal is to improve compatibility with the web platform, where Node.js core modules are not available.
MIGRATION:
- Try to use frontend-compatible modules whenever possible.
- It's possible to manually add a polyfill for a Node.js core module. An error message will give a hint on how to achieve that.
- Package authors: Use the
browserfield inpackage.jsonto make a package frontend-compatible. Provide alternative implementations/dependencies for the browser.
Major Changes: Long Term Caching
Deterministic Chunk, Module IDs and Export names
New algorithms were added for long term caching. These are enabled by default in production mode.
chunkIds: "deterministic"
moduleIds: "deterministic"
mangleExports: "deterministic"
The algorithms assign short (3 or 5 digits) numeric IDs to modules and chunks and short (2 characters) names to exports in a deterministic way. This is a trade-off between bundle size and long term caching.
moduleIds/chunkIds/mangleExports: false disables the default behavior and one can provide a custom algorithm via plugin. Note that in webpack 4 moduleIds/chunkIds: false without custom plugin resulted in a working build, while in webpack 5 you must provide a custom plugin.
MIGRATION: Best use the default values for chunkIds, moduleIds and mangleExports. You can also opt-in to the old defaults chunkIds: "size", moduleIds: "size", mangleExports: "size", this will generate smaller bundles, but invalidate them more often for caching.
Note: In webpack 4 hashed module ids yielded reduced gzip performance. This was related to changed module order and has been fixed.
Note: In webpack 5, deterministic Ids are enabled by default in production mode
Real Content Hash
Webpack 5 will use a real hash of the file content when using [contenthash] now. Before it "only" used a hash of the internal structure.
This can be positive impact on long term caching when only comments are changed or variables are renamed. These changes are not visible after minimizing.
Major Changes: Development Support
Named Chunk IDs
A new named chunk id algorithm enabled by default in development mode gives chunks (and filenames) human-readable names.
A Module ID is determined by its path, relative to the context.
A Chunk ID is determined by the chunk's content.
So you no longer need to use import(/* webpackChunkName: "name" */ "module") for debugging.
But it would still make sense if you want to control the filenames for production environments.
It's possible to use chunkIds: "named" in production, but make sure not to accidentally expose sensitive information about module names.
MIGRATION: If you dislike the filenames being changed in development, you can pass chunkIds: "natural" to use the old numeric mode.
Module Federation
Webpack 5 adds a new feature called "Module Federation", which allows multiple webpack builds to work together. From runtime perspective modules from multiple builds will behave like a huge connected module graph. From developer perspective modules can be imported from specified remote builds and used with minimal restrictions.
For more details see this separate guide.
Major Changes: New Web Platform Features
JSON modules
JSON modules now align with the proposal and emit a warning when a non-default export is used. JSON modules no longer have named exports when importing from a strict ECMAScript module.
MIGRATION: Use the default export.
Even when using the default export, unused properties are dropped by the optimization.usedExports optimization and properties are mangled by the optimization.mangleExports optimization.
It's possible to specify a custom JSON parser in Rule.parser.parse to import JSON-like files (e.g. for toml, yaml, json5, etc.).
import.meta
import.meta.webpackHotis an alias formodule.hotwhich is also available in strict ESMimport.meta.webpackis the webpack major version as numberimport.meta.urlis thefile:url of the current file (similar to__filenamebut as file url)
Asset modules
Webpack 5 has now native support for modules representing assets. These modules will either emit a file into the output folder or inject a DataURI into the javascript bundle. Either way they give a URL to work with.
They can be used via multiple ways:
import url from "./image.png"and settingtype: "asset"inmodule.ruleswhen matching such import. (old way)new URL("./image.png", import.meta.url)(new way)
The "new way" syntax was chosen to allow running code without bundler too. This syntax is also available in native ECMAScript modules in the browser.
Native Worker support
When combining new URL for assets with new Worker/new SharedWorker/navigator.serviceWorker.register webpack will automatically create a new entrypoint for a web worker.
new Worker(new URL("./worker.js", import.meta.url))
The syntax was chosen to allow running code without bundler too. This syntax is also available in native ECMAScript modules in the browser.
URIs
Webpack 5 supports handling of protocols in requests.
data:is supported. Base64 or raw encoding is supported. Mimetype can be mapped to loaders and module type inmodule.rules. Example:import x from "data:text/javascript,export default 42"file:is supported.http(s):is supported, but requires opt-in vianew webpack.experiments.schemesHttp(s)UriPlugin()- By default when targeting "web", these URIs result in requests to external resource (they are externals)
Fragments in requests are supported: Example: ./file.js#fragment
Async modules
Webpack 5 supports so called "async modules". That are modules that do not evaluate synchronously, but are async and Promise-based instead.
Importing them via import is automatically handled and no additional syntax is needed and difference is hardly notice-able.
Importing them via require() will return a Promise that resolves to the exports.
In webpack there are multiple ways to have async modules:
- async externals
- WebAssembly Modules in the new spec
- ECMAScript Modules that are using Top-Level-Await
Externals
Webpack 5 adds additional external types to cover more applications:
promise: An expression that evaluates to a Promise. The external module is an async module and the resolved value is used as module exports.
import: Native import() is used to load the specified request. The external module is an async module.
module: Not implemented yet, but planned to load modules via import x from "...".
script: Loads a url via <script> tag and gets the exports from a global variable (and optionally properties of it). The external module is an async module.
Major Changes: New Node.js Ecosystem Features
Resolving
The exports and imports field in package.json is now supported.
Yarn PnP is supported natively.
See more details in package exports.
Major Changes: Development Experience
Improved target
Webpack 5 allows to pass a list of targets and also support versions of target.
Examples: target: "node14" target: ["web", "es2020"]
This enables us to provide webpack all the information it needs to determine:
- chunk loading mechanism, and
- supported syntax like arrow functions
Stats
The Stats test format has been improved regarding readability and verbosity. The defaults have been improved to be less verbose and also suitable for large builds.
- Chunk relations are hidden by default now. This can be toggled with
stats.chunkRelations. - Stats differentiate between
filesandauxiliaryFilesnow. - Stats hide module and chunk ids by default now. This can be toggled with
stats.ids. - The list of all modules is sorted by distance to entrypoint now. This can be changed with
stats.modulesSort. - The list of chunk modules is sorted by module name now. This can be changed with
stats.chunkModulesSort. - The list of nested modules in concatenated modules is sorted topologically now. This can be changed with
stats.nestedModulesSort. - Chunks and Assets show chunk id hints now.
- Assets and modules will display in a tree instead of a list/table.
- General information is shown in a summary at the end now. It shows webpack version, config name and warnings/errors count.
- Hash is hidden by default now. This can be changed with
stats.hash. - Timestamp of build is no longer shown by default. This can be enabled with
stats.builtAt. It will show the timestamp in the summary. - Child compilations will no longer shown by default. They can be displayed with
stats.children.
Progress
A few improvements have been done to the ProgressPlugin which is used for --progress by the CLI, but can also be used manually as plugin.
It used to only count the processed modules. Now it can count entries dependencies and modules.
All of them are shown by default now.
It used to display the currently processed module. This caused much stderr output and yielded a performance problem on some consoles.
This is now disabled by default (activeModules option). This also reduces the amount of spam on the console.
Now writing to stderr during building modules is throttled to 500ms.
The profiling mode also got an upgrade and will display timings of nested progress messages. This makes it easier to figure out which plugin is causing performance problems.
A newly added percentBy-option tells ProgressPlugin how to calculate progress percentage.
new webpack.ProgressPlugin({ percentBy: "entries" });To make progress percentage more accurate ProgressPlugin caches the last known total modules count and reuses this value on the next build. The first build will warm the cache but the following builds will use and update this value.
Automatic unique naming
In webpack 4 multiple webpack runtimes could conflict on the same HTML page, because they use the same global variable for chunk loading. To fix that it was needed to provide a custom name to the output.jsonpFunction configuration.
Webpack 5 does automatically infer a unique name for the build from package.json name and uses this as default for output.uniqueName.
This value is used to make all potential conflicting globals unique.
MIGRATION: Remove output.jsonpFunction in favor of a unique name in your package.json.
Automatic public path
Webpack 5 will determine the output.publicPath automatically when possible.
Typescript typings
Webpack 5 generates typescript typings from source code and exposes them via the npm package.
MIGRATION: Remove @types/webpack. Update references when names differ.
Major Changes: Optimization
Nested tree-shaking
Webpack is now able to track access to nested properties of exports. This can improve Tree Shaking (Unused export elimination and export mangling) when reexporting namespace objects.
inner.js
export const a = 1;
export const b = 2;module.js
export * as inner from "./inner";
// or import * as inner from './inner'; export { inner };user.js
import * as module from "./module";
console.log(module.inner.a);In this example, the export b can be removed in production mode.
Inner-module tree-shaking
Webpack 4 didn't analyze dependencies between exports and imports of a module. Webpack 5 has a new option optimization.innerGraph, which is enabled by default in production mode, that runs an analysis on symbols in a module to figure out dependencies from exports to imports.
In a module like this:
import { something } from "./something";
function usingSomething() {
return something;
}
export function test() {
return usingSomething();
}The inner graph algorithm will figure out that something is only used when the test export is used. This allows to flag more exports as unused and to omit more code from the bundle.
When "sideEffects": false is set, this allows to omit even more modules. In this example ./something will be omitted when the test export is unused.
To get the information about unused exports optimization.usedExports is required. To remove side-effect-free modules optimization.sideEffects is required.
The following symbols can be analysed:
- function declarations
- class declarations
export defaultwith or variable declarations with- function expressions
- class expressions
- sequence expressions
/*#__PURE__*/expressions- local variables
- imported bindings
FEEDBACK: If you find something missing in this analysis, please report an issue and we consider adding it.
Using eval() will bail-out this optimization for a module, because evaled code could reference any symbol in scope.
This optimization is also known as Deep Scope Analysis.
CommonJs Tree Shaking
Webpack used to opt-out from used exports analysing for CommonJs exports and require() calls.
Webpack 5 adds support for some CommonJs constructs, allows to eliminate unused CommonJs exports and track referenced export names from require() calls.
The following constructs are supported:
exports|this|module.exports.xxx = ...exports|this|module.exports = require("...")(reexport)exports|this|module.exports.xxx = require("...").xxx(reexport)Object.defineProperty(exports|this|module.exports, "xxx", ...)require("abc").xxxrequire("abc").xxx()- importing from ESM
require()a ESM- flagged exportType (special handling for non-strict ESM import):
Object.defineProperty(exports|this|module.exports, "__esModule", { value: true|!0 })exports|this|module.exports.__esModule = true|!0
- It's planned to support more constructs in future
When detecting not analysable code, webpack bails out and doesn't track export information at all for these modules (for performance reasons).
Side-Effect analysis
The "sideEffects" flag in package.json allows to manually flag modules as side-effect-free, which allows to drop them when unused.
Webpack 5 can also automatically flag modules as side-effect-free according to a static analysis of the source code.
Optimization per runtime
Webpack 5 is now able (and does by default) to analyse and optimize modules per runtime (A runtime is often equal to an entrypoint). This allows to only exports in these entrypoints where they are really needed. Entrypoints doesn't affect each other (as long as using a runtime per entrypoint)
Module Concatenation
Module Concatenation also works per runtime to allow different concatenation for each runtime.
Module Concatenation has become a first class citizen and any module and dependency is now allowed to implement it. Initially webpack 5 already added support for ExternalModules and json modules, more will likely ship soonish.
General Tree Shaking improvements
export * has been improved to track more info and do no longer flag the default export as used.
export * will now show warnings when webpack is sure that there are conflicting exports.
import() allows to manually tree shake the module via /* webpackExports: ["abc", "default"] */ magic comment.
Development Production Similarity
We try to find a good trade-off between build performance in development mode and avoiding production-only problems by improving the similarity between both modes.
Webpack 5 enables the sideEffects optimization by default in both modes. In webpack 4 this optimization lead to some production-only errors because of an incorrect "sideEffects" flag in package.json. Enabling this optimization in development allows to find these problems faster and easier.
In many cases development and production happen on different OS with different case-sensitivity of filesystem, so webpack 5 adds a few more warnings/errors when there is something weird casing-wise.
Improved Code Generation
Webpack detects when ASI happens and generates shorter code when no semicolons are inserted. Object(...) -> (0, ...)
Webpack merges multiple export getters into a single runtime function call: r.d(x, "a", () => a); r.d(x, "b", () => b); -> r.d(x, {a: () => a, b: () => b});
There are additional options in output.environment now.
They allows specifying which ECMAScript feature can be used for runtime code generated by webpack.
One usually do not specify this option directly, but would use the target option instead.
Webpack 4 used to only emit ES5 code. Webpack 5 can generate both ES5 and ES6/ES2015 code now.
Supporting only modern browsers will generate shorter code using arrow functions and more spec-conform code using const declarations with TDZ for export default.
Improved target option
In webpack 4 the target was a rough choice between "web" and "node" (and a few others).
Webpack 5 gives you more options here.
The target option now influences more things about the generated code than before:
- method of chunk loading
- format of chunks
- method of wasm loading
- method of chunk and wasm loading in workers
- global object used
- if publicPath should be determined automatically
- ECMAScript features/syntax used in the generated code
externalsenabled by default- Behavior of some Node.js compat layers (
global,__filename,__dirname) - Resolving of modules (
browserfield,exportsandimportsconditions) - Some loaders might change behavior based on that
For some of these things the choice between "web" and "node" is too rough and we need more information.
Therefore we allow to specify the minimum version e.g. like "node10.13" and infer more properties about the target environment.
It's now also allowed to combined multiple targets with an array and webpack will determine the minimum properties of all targets. Using an array is also useful when using targets that doesn't give full information like "web" or "node" (without version number). E. g. ["web", "es2020"] combines these two partial targets.
There is a target "browserslist" which will use browserslist data to determine properties of the environment.
This target is also used by default when there is a browserslist config available in the project. When none such config is available, the "web" target will be used by default.
Some combinations and features are not yet implemented and will result in errors. They are preparations for future features. Examples:
["web", "node"]will lead to an universal chunk loading method, which is not implemented yet["web", "node"]+output.module: truewill lead to a module chunk loading method, which is not implemented yet"web"will lead tohttp(s):imports being treated asmoduleexternals, which are not implemented yet (Workaround:externalsPresets: { web: false, webAsync: true }, which will useimport()instead).
SplitChunks and Module Sizes
Modules now express size in a better way than a single number. There are different types of sizes now.
The SplitChunksPlugin now knows how to handle these different sizes and uses them for minSize and maxSize.
By default, only javascript size is handled, but you can now pass multiple values to manage them:
module.exports = {
optimization: {
splitChunks: {
minSize: {
javascript: 30000,
webassembly: 50000,
},
},
},
};You can still use a single number for sizes. In this case webpack will automatically use the default size types.
The mini-css-extract-plugin uses css/mini-extra as size type, and adds this size type to the default types automatically.
Major Changes: Performance
Persistent Caching
There is now a filesystem cache. It's opt-in and can be enabled with the following configuration:
module.exports = {
cache: {
// 1. Set cache type to filesystem
type: "filesystem",
buildDependencies: {
// 2. Add your config as buildDependency to get cache invalidation on config change
config: [__filename],
// 3. If you have other things the build depends on you can add them here
// Note that webpack, loaders and all modules referenced from your config are automatically added
},
},
};Important notes:
By default, webpack assumes that the node_modules directory, which webpack is inside of, is only modified by a package manager. Hashing and timestamping is skipped for node_modules.
Instead, only the package name and version is used for performance reasons.
Symlinks (i. e. npm/yarn link) are fine as long resolve.symlinks: false is not specified (avoid that anyway).
Do not edit files in node_modules directly unless you opt-out of this optimization with snapshot.managedPaths: [].
When using Yarn PnP webpack assumes that the yarn cache is immutable (which it usually is).
You can opt-out of this optimization with snapshot.immutablePaths: []
The cache will be stored into node_modules/.cache/webpack (when using node_modules) resp. .yarn/.cache/webpack (when using Yarn PnP) by default.
You probably never have to delete it manually, when all plugins handle caching correctly.
Many internal plugins will use the Persistent Cache too. Examples: SourceMapDevToolPlugin (to cache the SourceMap generation) or ProgressPlugin (to cache the number of modules)
The Persistent Cache will automatically create multiple cache files depending on usage to optimize read and write access to and from the cache.
By default timestamps will be used for snapshotting in development mode and file hashes in production mode. File hashes allow to use Persistent Caching on CI too.
Compiler Idle and Close
Compilers now need to be closed after being used. Compilers now enter and leave the idle state and have hooks for these states. Plugins may use these hooks to do unimportant work. (i. e. the Persistent cache slowly stores the cache to disk). On compiler close - All remaining work should be finished as fast as possible. A callback signals the closing as done.
Plugins and their respective authors should expect that some users may forget to close the Compiler. So, all work should eventually be finishing while in idle too. Processes should be prevented from exiting when the work is being done.
The webpack() façade automatically calls close when being passed a callback.
MIGRATION: While using the Node.js API, make sure to call Compiler.close when done.
File Emitting
Webpack used to always emit all output files during the first build but skipped writing unchanged files during incremental (watch) builds. It is assumed that nothing else changes output files while webpack is running.
With Persistent Caching added a watch-like experience should be given even when restarting the webpack process, but it would be a too strong assumption to think that nothing else changes the output directory even when webpack is not running.
So webpack will now check existing files in the output directory and compares their content with the output file in memory. It will only write the file when it has been changed. This is only done on the first build. Any incremental build will always write the file when a new asset has been generated in the running webpack process.
We assume that webpack and plugins only generate new assets when content has been changed. Caching should be used to ensure that no new asset is generated when input is equal. Not following this advice will degrade performance.
Files that are flagged as [immutable] (including a content hash), will never be written when a file with the same name already exists.
We assume that the content hash will change when file content changes.
This is true in general, but might not be always true during webpack or plugin development.
Major Changes: Long outstanding problems
Code Splitting for single-file-targets
Targets that only allow to startup a single file (like node, WebWorker, electron main) now supports loading the dependent pieces required for bootstrapping automatically by the runtime.
This allows using optimization.splitChunks for these targets with chunks: "all" and also optimization.runtimeChunk
Note that with targets where chunk loading is async, this makes initial evaluation async too. This can be an issue when using output.library, since the exported value is a Promise now.
Updated Resolver
enhanced-resolve was updated to v5. This has the following improvements:
- The resolve tracks more dependencies, like missing files
- aliasing may have multiple alternatives
- aliasing to
falseis possible now - support for features like
exportsandimportsfields - Increased performance
Chunks without JS
Chunks that contain no JS code, will no longer generate a JS file. This allows to have chunks that contain only CSS.
Major Changes: Future
Experiments
Not all features are stable from the beginning. In webpack 4 we added experimental features and noted in the changelog that they are experimental, but it was not always clear from the configuration that these features are experimental.
In webpack 5 there is a new experiments config option which allows to enable experimental features. This makes it clear which ones are enabled/used.
While webpack follows semantic versioning, it will make an exception for experimental features. Experimental features might contain breaking changes in minor webpack versions. When this happens we will add a clear note into the changelog. This will allow us to iterate faster for experimental features, while also allowing us to stay longer on a major version for stable features.
The following experiments will ship with webpack 5:
- Old WebAssembly support like in webpack 4 (
experiments.syncWebAssembly) - New WebAssembly support according to the updated spec (
experiments.asyncWebAssembly)- This makes a WebAssembly module an async module
- Top Level Await Stage 3 proposal (
experiments.topLevelAwait)- Using
awaiton top-level makes the module an async module
- Using
- Emitting bundle as module (
experiments.outputModule)- This removed the wrapper IIFE from the bundle, enforces strict mode, lazy loads via
<script type="module">and minimized in module mode
- This removed the wrapper IIFE from the bundle, enforces strict mode, lazy loads via
Note that this also means WebAssembly support is now disabled by default.
Minimum Node.js Version
The minimum supported Node.js version has increased from 6 to 10.13.0(LTS).
MIGRATION: Upgrade to the latest Node.js version available.
Changes to the Configuration
Changes to the Structure
entry: {}allows an empty object now (to allow to use plugins to add entries)targetsupports an array, versions and browserslistcache: Objectremoved: Setting to a memory-cache object is no longer possiblecache.typeadded: It's now possible to choose between"memory"and"filesystem"- New configuration options for
cache.type = "filesystem"added:cache.cacheDirectorycache.namecache.versioncache.storecache.hashAlgorithmcache.idleTimeoutcache.idleTimeoutForInitialStorecache.buildDependencies
snapshot.resolveBuildDependenciesaddedsnapshot.resolveaddedsnapshot.moduleaddedsnapshot.managedPathsaddedsnapshot.immutablePathsaddedresolve.cacheadded: Allows to disable/enable the safe resolve cacheresolve.concordremovedresolve.moduleExtensionsremovedresolve.aliasvalues can be arrays orfalsenowresolve.restrictionsadded: Allows to restrict potential resolve resultsresolve.fallbackadded: Allow to alias requests that failed to resolveresolve.preferRelativeadded: Allows to resolve modules requests are relative requests too- Automatic polyfills for native Node.js modules were removed
node.Bufferremovednode.consoleremovednode.processremovednode.*(Node.js native module) removed- MIGRATION:
resolve.aliasandProvidePlugin. Errors will give hints. (Refer to node-libs-browser for polyfills & mocks used in v4)
output.filenamecan now be a functionoutput.assetModuleFilenameaddedoutput.jsonpScriptTyperenamed tooutput.scriptTypedevtoolis more strict- Format:
false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
- Format:
optimization.chunkIds: "deterministic"addedoptimization.moduleIds: "deterministic"addedoptimization.moduleIds: "hashed"deprecatedoptimization.moduleIds: "total-size"removed- Deprecated flags for module and chunk ids were removed
optimization.hashedModuleIdsremovedoptimization.namedChunksremoved (NamedChunksPlugintoo)optimization.namedModulesremoved (NamedModulesPlugintoo)optimization.occurrenceOrderremoved- MIGRATION: Use
chunkIdsandmoduleIds
optimization.splitChunkstestno longer matches chunk name- MIGRATION: Use a test function
(module, { chunkGraph }) => chunkGraph.getModuleChunks(module).some(chunk => chunk.name === "name")
- MIGRATION: Use a test function
optimization.splitChunksminRemainingSizewas addedoptimization.splitChunksfilenamecan now be a functionoptimization.splitChunkssizes can now be objects with a size per source typeminSizeminRemainingSizemaxSizemaxAsyncSizemaxInitialSize
optimization.splitChunksmaxAsyncSizeandmaxInitialSizeadded next tomaxSize: allows to specify different max sizes for initial and async chunksoptimization.splitChunksname: trueremoved: Automatic names are no longer supported- MIGRATION: Use the default.
chunkIds: "named"will give your files useful names for debugging
- MIGRATION: Use the default.
optimization.splitChunks.cacheGroups[].idHintadded: Gives a hint how the named chunk id should be chosenoptimization.splitChunksautomaticNamePrefixremoved- MIGRATION: Use
idHintinstead
- MIGRATION: Use
optimization.splitChunksfilenameis no longer restricted to initial chunksoptimization.splitChunksusedExportsadded to include used exports when comparing modulesoptimization.splitChunks.defaultSizeTypesadded: Specified the size types when using numbers for sizesoptimization.mangleExportsaddedoptimization.minimizer"..."can be used to reference the defaultsoptimization.usedExports"global"value added to allow to disable the analysis per runtime and instead do it globally (better performance)optimization.noEmitOnErrorsrenamed tooptimization.emitOnErrorsand logic invertedoptimization.realContentHashaddedoutput.devtoolLineToLineremoved- MIGRATION: No replacement
output.chunkFilename: Functionis now allowedoutput.hotUpdateChunkFilename: Functionis now forbidden: It never worked anyway.output.hotUpdateMainFilename: Functionis now forbidden: It never worked anyway.output.importFunctionName: stringspecifies the name used as replacement forimport()to allow polyfilling for non-supported environmentsoutput.charsetadded: setting it to false omit thecharsetproperty on script tagsoutput.hotUpdateFunctionrenamed tooutput.hotUpdateGlobaloutput.jsonpFunctionrenamed tooutput.chunkLoadingGlobaloutput.chunkCallbackFunctionrenamed tooutput.chunkLoadingGlobaloutput.chunkLoadingaddedoutput.enabledChunkLoadingTypesaddedoutput.chunkFormataddedmodule.rulesresolveandparserwill merge in a different way (objects are deeply merged, array may include"..."to reference to prev value)module.rulesparser.workeradded: Allows to configure the worker supportedmodule.rulesqueryandloaderswere removedmodule.rulesoptionspassing a string is deprecated- MIGRATION: Pass an options object instead, open an issue on the loader when this is not supported
module.rulesmimetypeadded: allows to match a mimetype of a DataURImodule.rulesdescriptionDataadded: allows to match a data from package.jsonmodule.defaultRules"..."can be used to reference the defaultsstats.chunkRootModulesadded: Show root modules for chunksstats.orphanModulesadded: Show modules which are not emittedstats.runtimeadded: Show runtime modulesstats.chunkRelationsadded: Show parent/children/sibling chunksstats.errorStackadded: Show webpack-internal stack trace of errorsstats.presetadded: select a presetstats.relatedAssetsadded: show assets that are related to other assets (e.g. SourceMaps)stats.warningsFilterdeprecated in favor ofignoreWarningsBannerPlugin.bannersignature changeddata.basenameremoveddata.queryremoved- MIGRATION: extract from
filename
SourceMapDevToolPluginlineToLineremoved- MIGRATION: No replacement
[hash]as hash for the full compilation is now deprecated- MIGRATION: Use
[fullhash]instead or better use another hash option
- MIGRATION: Use
[modulehash]is deprecated- MIGRATION: Use
[hash]instead
- MIGRATION: Use
[moduleid]is deprecated- MIGRATION: Use
[id]instead
- MIGRATION: Use
[filebase]removed- MIGRATION: Use
[base]instead
- MIGRATION: Use
- New placeholders for file-based templates (i. e. SourceMapDevToolPlugin)
[name][base][path][ext]
externalswhen passing a function, it has now a different signature({ context, request }, callback)- MIGRATION: Change signature
externalsPresetsaddedexperimentsadded (see Experiments section above)watchOptions.followSymlinksaddedwatchOptions.ignoredcan now be a RegExpwebpack.util.serializationis now exposed.
Changes to the Defaults
targetis now"browserslist"by default when a browserslist config is availablemodule.unsafeCacheis now only enabled fornode_modulesby defaultoptimization.moduleIdsdefaults todeterministicin production mode, instead ofsizeoptimization.chunkIdsdefaults todeterministicin production mode, instead oftotal-sizeoptimization.nodeEnvdefaults tofalseinnonemodeoptimization.splitChunks.minSizedefaults to20kin productionoptimization.splitChunks.enforceSizeThresholddefaults to50kin productionoptimization.splitChunksminRemainingSizedefaults tominSize- This will lead to less splitted chunks created in cases where the remaining part would be too small
optimization.splitChunksmaxAsyncRequestsandmaxInitialRequestsdefaults was been increased to 30optimization.splitChunks.cacheGroups.vendorshas be renamed tooptimization.splitChunks.cacheGroups.defaultVendorsoptimization.splitChunks.cacheGroups.defaultVendors.reuseExistingChunknow defaults totrueoptimization.minimizertarget default usescompress.passes: 2in terser options nowresolve(Loader).cachedefaults totruewhencacheis usedresolve(Loader).cacheWithContextdefaults tofalseresolveLoader.extensionsremove.jsonnode.globalnode.__filenameandnode.__dirnamedefaults tofalsein node-targetsstats.errorStackdefaults tofalse
Loader related Changes
this.getOptions
This new API should simplify the usage for options in loaders. It allows to pass a JSON schema for validation. See PR for details
this.exec
This has been removed from loader context
MIGRATION: This can be implemented in the loader itself
this.getResolve
getResolve(options) in the loader API will merge options in a different way, see module.rules resolve.
As webpack 5 differs between different issuing dependencies so it might make sense to pass a dependencyType as option (e.g. "esm", "commonjs", or others).
Major Internal Changes
The following changes are only relevant for plugin authors:
New plugin order
Plugins in webpack 5 are now applies before the configuration defaults has been applied. This allows plugins to apply their own defaults, or act as configuration presets.
But this is also a breaking change as plugins can't rely on configuration values to be set when they are applied.
MIGRATION: Access configuration only in plugin hooks. Or best avoid accessing configuration at all and take options via constructor.
Runtime Modules
A large part of the runtime code was moved into the so-called "runtime modules". These special modules are in-charge of adding runtime code. They can be added into any chunk, but are currently always added to the runtime chunk. "Runtime Requirements" control which runtime modules (or core runtime parts) are added to the bundle. This ensures that only runtime code that is used is added to the bundle. In the future, runtime modules could also be added to an on-demand-loaded chunk, to load runtime code when needed.
In most cases, the core runtime allows to inline the entry module instead of calling it with __webpack_require__. If there is no other module in the bundle, no __webpack_require__ is needed at all. This combines well with Module Concatenation where multiple modules are concatenated into a single module.
In the best case, no runtime code is needed at all.
MIGRATION: If you are injecting runtime code into the webpack runtime in a plugin, consider using RuntimeModules instead.
Serialization
A serialization mechanism was added to allow serialization of complex objects in webpack. It has an opt-in semantic, so classes that should be serialized need to be explicitly flagged (and their serialization implemented). This has been done for most Modules, all Dependencies and some Errors.
MIGRATION: When using custom Modules or Dependencies, it is recommended to make them serializable to benefit from persistent caching.
Plugins for Caching
A Cache class with a plugin interface has been added. This class can be used to write and read to the cache. Depending on the configuration, different plugins can add functionality to the cache. The MemoryCachePlugin adds in-memory caching. The FileCachePlugin adds persistent (file-system) caching.
The FileCachePlugin uses the serialization mechanism to persist and restore cached items to/from the disk.
Hook Object Frozen
Classes with hooks have their hooks object frozen, so adding custom hooks is no longer possible this way.
MIGRATION: The recommended way to add custom hooks is using a WeakMap and a static getXXXHooks(XXX) (i. e. getCompilationHook(compilation)) method. Internal classes use the same mechanism used for custom hooks.
Tapable Upgrade
The compat layer for webpack 3 plugins has been removed. It had already been deprecated for webpack 4.
Some less used tapable APIs were removed or deprecated.
MIGRATION: Use the new tapable API.
Staged Hooks
For several steps in the sealing process, there had been multiple hooks for different stages. i. e. optimizeDependenciesBasic optimizeDependencies and optimizeDependenciesAdvanced. These have been removed in favor of a single hook which can be used with a stage option. See OptimizationStages for possible stage values.
MIGRATION: Hook into the remaining hook instead. You may add a stage option.
Main/Chunk/ModuleTemplate deprecation
Bundle templating has been refactored. MainTemplate/ChunkTemplate/ModuleTemplate were deprecated and the JavascriptModulesPlugin takes care of JS templating now.
Before that refactoring, JS output was handled by Main/ChunkTemplate while another output (i. e. WASM, CSS) was handled by plugins. This looks like JS is first class, while another output is second class. The refactoring changes that and all output is handled by their plugins.
It's still possible to hook into parts of the templating. The hooks are in JavascriptModulesPlugin instead of Main/ChunkTemplate now. (Yes plugins can have hooks too. I call them attached hooks.)
There is a compat-layer, so Main/Chunk/ModuleTemplate still exist, but only delegate tap calls to the new hook locations.
MIGRATION: Follow the advice in the deprecation messages. Mostly pointing to hooks at different locations.
Entry point descriptor
If an object is passed as entry point the value might be a string, array of strings or a descriptor:
module.exports = {
entry: {
catalog: {
import: "./catalog.js",
},
},
};Descriptor syntax might be used to pass additional options to an entry point.
Entry point output filename
By default, the output filename for the entry chunk is extracted from output.filename but you can specify a custom output filename for a specific entry:
module.exports = {
entry: {
about: { import: "./about.js", filename: "pages/[name][ext]" },
},
};Entry point dependency
By default, every entry chunk stores all the modules that it uses. With dependOn-option you can share the modules from one entry chunk to another:
module.exports = {
entry: {
app: { import: "./app.js", dependOn: "react-vendors" },
"react-vendors": ["react", "react-dom", "prop-types"],
},
};The app chunk will not contain the modules that react-vendors has.
Entry point library
The entry descriptor allows to pass a different library option for each entrypoint.
module.exports = {
entry: {
commonjs: {
import: "./lib.js",
library: {
type: "commonjs-module",
},
},
amd: {
import: "./lib.js",
library: {
type: "amd",
},
},
},
};Entry point runtime
The entry descriptor allows to specify a runtime per entry.
When specified a chunk with this name is created which contains only the runtime code for the entry.
When multiple entries specify the same runtime, that chunk will contain a common runtime for all these entry.
This means they could be used together on the same HTML page.
module.exports = {
entry: {
app: {
import: "./app.js",
runtime: "app-runtime",
},
},
};Entry point chunk loading
The entry descriptor allows to specify a chunkLoading per entry.
The runtime for this entry will use this to load chunks.
module.exports = {
entry: {
app: {
import: "./app.js",
},
worker: {
import: "./worker.js",
chunkLoading: "importScripts",
},
},
};Order and IDs
Webpack used to order modules and chunks in the Compilation phase, in a specific way, to assign IDs in incremental order. This is no longer the case. The order will no longer be used for id generation, instead, the full control of ID generation is in the plugin.
Hooks to optimize the order of module and chunks have been removed.
MIGRATION: You cannot rely on the order of modules and chunks in the compilation phase no more.
Arrays to Sets
- Compilation.modules is now a Set
- Compilation.chunks is now a Set
- Chunk.files is now a Set
There is a compat-layer which prints deprecation warnings.
MIGRATION: Use Set methods instead of Array methods.
Compilation.fileSystemInfo
This new class can be used to access information about the filesystem in a cached way. Currently, it allows asking for both file and directory timestamps. Information about timestamps is transferred from the watcher if possible, otherwise determined by filesystem access.
In the future, asking for file content hashes will be added and modules will be able to check validity with file contents instead of file hashes.
MIGRATION: Instead of using file/contextTimestamps use the compilation.fileSystemInfo API instead.
Timestamping for directories is possible now, which allows serialization of ContextModules.
Compiler.modifiedFiles has been added (next to Compiler.removedFiles) to make it easier to reference the changed files.
Filesystems
Next to compiler.inputFileSystem and compiler.outputFileSystem there is a new compiler.intermediateFileSystem for all fs actions that are not considered as input or output, like writing records, cache or profiling output.
The filesystems have now the fs interface and do no longer demand additional methods like join or mkdirp. But if they have methods like join or dirname they are used.
Hot Module Replacement
HMR runtime has been refactored to Runtime Modules. HotUpdateChunkTemplate has been merged into ChunkTemplate. ChunkTemplates and plugins should also handle HotUpdateChunks now.
The javascript part of HMR runtime has been separated from the core HMR runtime. Other module types can now also handle HMR in their own way. In the future, this will allow i. e. HMR for the mini-css-extract-plugin or for WASM modules.
MIGRATION: As this is a newly introduced functionality, there is nothing to migrate.
import.meta.webpackHot exposes the same API as module.hot. This is also usable from strict ESM modules (.mjs, type: "module" in package.json) which do not have access to module.
Work Queues
Webpack used to handle module processing by functions calling functions, and a semaphore which limits parallelism. The Compilation.semaphore has been removed and async queues now handle work queuing and processing. Each step has a separate queue:
Compilation.factorizeQueue: calling the module factory for a group of dependencies.Compilation.addModuleQueue: adding the module to the compilation queue (may restore module from cache).Compilation.buildQueue: building the module if necessary (may stores module to cache).Compilation.rebuildQueue: building a module again if manually triggered.Compilation.processDependenciesQueue: processing dependencies of a module.
These queues have some hooks to watch and intercept job processing.
In the future, multiple compilers may work together and job orchestration can be done by intercepting these queues.
MIGRATION: As this is a newly introduced functionality, there is nothing to migrate.
Logging
Webpack internals includes some logging now.
stats.logging and infrastructureLogging options can be used to enabled these messages.
Module and Chunk Graph
Webpack used to store a resolved module in the dependency, and store the contained modules in the chunk. This is no longer the case. All information about how modules are connected in the module graph are now stored in a ModuleGraph class. All information about how modules are connected with chunks are now stored in the ChunkGraph class. The information which depends on i. e. the chunk graph, is also stored in the related class.
That means the following information about modules has been moved:
- Module connections -> ModuleGraph
- Module issuer -> ModuleGraph
- Module optimization bailout -> ModuleGraph (TODO: check if it should ChunkGraph instead)
- Module usedExports -> ModuleGraph
- Module providedExports -> ModuleGraph
- Module pre order index -> ModuleGraph
- Module post order index -> ModuleGraph
- Module depth -> ModuleGraph
- Module profile -> ModuleGraph
- Module id -> ChunkGraph
- Module hash -> ChunkGraph
- Module runtime requirements -> ChunkGraph
- Module is in chunk -> ChunkGraph
- Module is entry in chunk -> ChunkGraph
- Module is runtime module in chunk -> ChunkGraph
- Chunk runtime requirements -> ChunkGraph
Webpack used to disconnect modules from the graph when restored from the cache. This is no longer necessary. A Module stores no info about the graph and can technically be used in multiple graphs. This makes caching easier.
There is a compat-layer for most of these changes, which prints a deprecation warning when used.
MIGRATION: Use the new APIs on ModuleGraph and ChunkGraph
Init Fragments
DependenciesBlockVariables has been removed in favor of InitFragments. DependencyTemplates can now add InitFragments to inject code to the top of the module's source. InitFragments allows deduplication.
MIGRATION: Use InitFragments instead of inserting something at a negative index into the source.
Module Source Types
Modules now have to define which source types they support via Module.getSourceTypes(). Depending on that, different plugins call source() with these types. i. e. for source type javascript the JavascriptModulesPlugin embeds the source code into the bundle. Source type webassembly will make the WebAssemblyModulesPlugin emit a wasm file. Custom source types are also supported, i. e. the mini-css-extract-plugin will probably use the source type stylesheet to embed the source code into a css file.
There is no relationship between module type and source type. i. e. module type json also uses source type javascript and module type webassembly/experimental uses source types javascript and webassembly.
MIGRATION: Custom modules need to implement these new interface methods.
Plugins for Stats
Stats preset, default, json and toString are now baked in by a plugin system. Converted the current Stats into plugins.
MIGRATION: Instead of replacing the whole Stats functionality, you can now customize it. Extra information can now be added to the stats json instead of writing a separate file.
New Watching
The watcher used by webpack was refactored. It was previously using chokidar and the native dependency fsevents (only on macOS). Now it's only based on native Node.js fs. This means there is no native dependency left in webpack.
It also captures more information about filesystem while watching. It now captures mtimes and watches event times, as well as information about missing files. For this, the WatchFileSystem API changed a little bit. While on it we also converted Arrays to Sets and Objects to Maps.
SizeOnlySource after emit
Webpack now replaces the Sources in Compilation.assets with SizeOnlySource variants to reduce memory usage.
Emitting assets multiple times
The warning Multiple assets emit different content to the same filename has been made an error.
ExportsInfo
The way how information about exports of modules is stored has been refactored. The ModuleGraph now features an ExportsInfo for each Module, which stores information per export. It also stores information about unknown exports and if the module is used in a side-effect-only way.
For each export the following information is stored:
- Is the export used? yes, no, not statically known, not determined. (see also
optimization.usedExports) - Is the export provided? yes, no, not statically known, not determined. (see also
optimization.providedExports) - Can be export name be renamed? yes, no, not determined.
- The new name, if the export has been renamed. (see also
optimization.mangleExports) - Nested ExportsInfo, if the export is an object with information attached itself
- Used for reexporting namespace objects:
import * as X from "..."; export { X }; - Used for representing structure in JSON modules
- Used for reexporting namespace objects:
Code Generation Phase
The Compilation features Code Generation as separate compilation phase now. It no longer runs hidden in Module.source() or Module.getRuntimeRequirements().
This should make the flow much cleaner. It also allows to report progress for this phase and makes Code Generation more visible when profiling.
MIGRATION: Module.source() and Module.getRuntimeRequirements() are deprecated now. Use Module.codeGeneration() instead.
DependencyReference
Webpack used to have a single method and type to represent references of dependencies (Compilation.getDependencyReference returning a DependencyReference).
This type used to include all information about this reference like the referenced Module, which exports have been imported, if it's a weak reference and also some ordering related information.
Bundling all these information together makes getting the reference expensive and it's also called often (every time somebody needs one piece of information).
In webpack 5 this part of the codebase was refactored and the method has been split up.
- The referenced module can be read from the ModuleGraphConnection
- The imported export names can be get via
Dependency.getReferencedExports() - There is a
weakflag on theDependencyclass - Ordering is only relevant to
HarmonyImportDependenciesand can be get viasourceOrderproperty
Presentational Dependencies
There is now a new type of dependency in NormalModules: Presentational Dependencies
These dependencies are only used during the Code Generation phase but are not used during Module Graph building. So they can never have referenced modules or influence exports/imports.
These dependencies are cheaper to process and webpack uses them when possible
Deprecated loaders
-
It will be deprecated. Use
module.exports = { resolve: { alias: { xyz$: false, }, }, };or use an absolute path
module.exports = { resolve: { alias: { [path.resolve(__dirname, "....")]: false, }, }, };
Minor Changes
Compiler.name: When generating a compiler name with absolute paths, make sure to separate them with|or!on both parts of the name.- Using space as a separator is now deprecated. (Paths could contain spaces)
- Hint:
|is replaced with space in Stats string output.
SystemPluginis now disabled by default.- MIGRATION: Avoid using it as the spec has been removed. You can re-enable it with
Rule.parser.system: true
- MIGRATION: Avoid using it as the spec has been removed. You can re-enable it with
ModuleConcatenationPlugin: concatenation is no longer prevented byDependencyVariablesas they have been removed- This means it can now concatenate in cases of
module,global,processor the ProvidePlugin
- This means it can now concatenate in cases of
Stats.presetToOptionsremoved- MIGRATION: Use
compilation.createStatsOptionsinstead
- MIGRATION: Use
SingleEntryPluginandSingleEntryDependencyremoved- MIGRATION: use
EntryPluginandEntryDependency
- MIGRATION: use
- Chunks can now have multiple entry modules
ExtendedAPIPluginremoved- MIGRATION: No longer needed,
__webpack_hash__and__webpack_chunkname__can always be used and runtime code is injected where needed.
- MIGRATION: No longer needed,
ProgressPluginno longer uses tapable context forreportProgress- MIGRATION: Use
ProgressPlugin.getReporter(compiler)instead
- MIGRATION: Use
ProvidePluginis now re-enabled for.mjsfilesStatsjsonerrorsandwarningsno longer contain strings but objects with information splitted into properties.- MIGRATION: Access the information on the properties. i. e.
message
- MIGRATION: Access the information on the properties. i. e.
Compilation.hooks.normalModuleLoaderis deprecated- MIGRATION: Use
NormalModule.getCompilationHooks(compilation).loaderinstead
- MIGRATION: Use
- Changed hooks in
NormalModuleFactoryfrom waterfall to bailing, changed and renamed hooks that return waterfall functions - Removed
compilationParams.compilationDependencies- Plugins can add dependencies to the compilation by adding to
compilation.file/context/missingDependencies - Compat layer will delegate
compilationDependencies.addtofileDependencies.add
- Plugins can add dependencies to the compilation by adding to
stats.assetsByChunkName[x]is now always an array__webpack_get_script_filename__function added to get the filename of a script file"sideEffects"in package.json will be handled byglob-to-regexinstead ofmicromatch- This may have changed semantics in edge-cases
checkContextwas removed fromIgnorePlugin- New
__webpack_exports_info__API allows export usage introspection - SourceMapDevToolPlugin applies to non-chunk assets too now
- EnvironmentPlugin shows an error now when referenced env variable is missing and has no fallback
- Remove
serveproperty from schema
Other Minor Changes
- removed builtin directory and replaced builtins with runtime modules
- Removed deprecated features
- BannerPlugin now only support one argument that can be an object, string or function
- removed
CachePlugin Chunk.entryModuleis deprecated, use ChunkGraph insteadChunk.hasEntryModuleis deprecatedChunk.addModuleis deprecatedChunk.removeModuleis deprecatedChunk.getNumberOfModulesis deprecatedChunk.modulesIterableis deprecatedChunk.compareTois deprecatedChunk.containsModuleis deprecatedChunk.getModulesis deprecatedChunk.removeis deprecatedChunk.moveModuleis deprecatedChunk.integrateis deprecatedChunk.canBeIntegratedis deprecatedChunk.isEmptyis deprecatedChunk.modulesSizeis deprecatedChunk.sizeis deprecatedChunk.integratedSizeis deprecatedChunk.getChunkModuleMapsis deprecatedChunk.hasModuleInGraphis deprecatedChunk.updateHashsignature changedChunk.getChildIdsByOrderssignature changed (TODO: consider moving toChunkGraph)Chunk.getChildIdsByOrdersMapsignature changed (TODO: consider moving toChunkGraph)Chunk.getChunkModuleMapsremovedChunk.setModulesremoved- deprecated Chunk methods removed
ChunkGraphaddedChunkGroup.setParentsremovedChunkGroup.containsModuleremovedCompilation.cachewas removed in favor ofCompilation.getCache()ChunkGroup.removeno longer disconnected the group from blockChunkGroup.compareTosignature changedChunkGroup.getChildrenByOrderssignature changedChunkGroupindex and index renamed to pre/post order index- old getter is deprecated
ChunkTemplate.hooks.modulessignature changedChunkTemplate.hooks.rendersignature changedChunkTemplate.updateHashForChunksignature changedCompilation.hooks.optimizeChunkOrderremovedCompilation.hooks.optimizeModuleOrderremovedCompilation.hooks.advancedOptimizeModuleOrderremovedCompilation.hooks.optimizeDependenciesBasicremovedCompilation.hooks.optimizeDependenciesAdvancedremovedCompilation.hooks.optimizeModulesBasicremovedCompilation.hooks.optimizeModulesAdvancedremovedCompilation.hooks.optimizeChunksBasicremovedCompilation.hooks.optimizeChunksAdvancedremovedCompilation.hooks.optimizeChunkModulesBasicremovedCompilation.hooks.optimizeChunkModulesAdvancedremovedCompilation.hooks.optimizeExtractedChunksBasicremovedCompilation.hooks.optimizeExtractedChunksremovedCompilation.hooks.optimizeExtractedChunksAdvancedremovedCompilation.hooks.afterOptimizeExtractedChunksremovedCompilation.hooks.stillValidModuleaddedCompilation.hooks.statsPresetaddedCompilation.hooks.statsNormalizeaddedCompilation.hooks.statsFactoryaddedCompilation.hooks.statsPrinteraddedCompilation.fileDependencies,Compilation.contextDependenciesandCompilation.missingDependenciesare now LazySetsCompilation.entriesremoved- MIGRATION: Use
Compilation.entryDependenciesinstead
- MIGRATION: Use
Compilation._preparedEntrypointsremoveddependencyTemplatesis now aDependencyTemplatesclass instead of a rawMapCompilation.fileTimestampsandcontextTimestampsremoved- MIGRATION: Use
Compilation.fileSystemInfoinstead
- MIGRATION: Use
Compilation.waitForBuildingFinishedremoved- MIGRATION: Use the new queues
Compilation.addModuleDependenciesremovedCompilation.prefetchremovedCompilation.hooks.beforeHashis now called after the hashes of modules are created- MIGRATION: Use
Compilation.hooks.beforeModuleHashinstead
- MIGRATION: Use
Compilation.applyModuleIdsremovedCompilation.applyChunkIdsremovedCompiler.rootadded, which points to the root compiler- it can be used to cache data in WeakMaps instead of statically scoped
Compiler.hooks.afterDoneaddedSource.emittedis no longer set by the Compiler- MIGRATION: Check
Compilation.emittedAssetsinstead
- MIGRATION: Check
Compiler/Compilation.compilerPathadded: It's a unique name of the compiler in the compiler tree. (Unique to the root compiler scope)Module.needRebuilddeprecated- MIGRATION: use
Module.needBuildinstead
- MIGRATION: use
Dependency.getReferencesignature changedDependency.getExportssignature changedDependency.getWarningssignature changedDependency.getErrorssignature changedDependency.updateHashsignature changedDependency.moduleremoved- There is now a base class for
DependencyTemplate MultiEntryDependencyremovedEntryDependencyaddedEntryModuleNotFoundErrorremovedSingleEntryPluginremovedEntryPluginaddedGenerator.getTypesaddedGenerator.getSizeaddedGenerator.generatesignature changedHotModuleReplacementPlugin.getParserHooksaddedParserwas moved toJavascriptParserParserHelperswas moved toJavascriptParserHelpersMainTemplate.hooks.moduleObjremovedMainTemplate.hooks.currentHashremovedMainTemplate.hooks.addModuleremovedMainTemplate.hooks.requireEnsureremovedMainTemplate.hooks.globalHashPathsremovedMainTemplate.hooks.globalHashremovedMainTemplate.hooks.hotBootstrapremovedMainTemplate.hookssome signatures changedModule.hashdeprecatedModule.renderedHashdeprecatedModule.reasonsremovedModule.iddeprecatedModule.indexdeprecatedModule.index2deprecatedModule.depthdeprecatedModule.issuerdeprecatedModule.profileremovedModule.prefetchedremovedModule.builtremovedModule.usedremoved- MIGRATION: Use
Module.getUsedExportsinstead
- MIGRATION: Use
- Module.usedExports deprecated
- MIGRATION: Use
Module.getUsedExportsinstead
- MIGRATION: Use
Module.optimizationBailoutdeprecatedModule.exportsArgumentremovedModule.optionaldeprecatedModule.disconnectremovedModule.unsealremovedModule.setChunksremovedModule.addChunkdeprecatedModule.removeChunkdeprecatedModule.isInChunkdeprecatedModule.isEntryModuledeprecatedModule.getChunksdeprecatedModule.getNumberOfChunksdeprecatedModule.chunksIterabledeprecatedModule.hasEqualsChunksremovedModule.useSourceMapmoved toNormalModuleModule.addReasonremovedModule.removeReasonremovedModule.rewriteChunkInReasonsremovedModule.isUsedremoved- MIGRATION: Use
isModuleUsed,isExportUsedandgetUsedNameinstead
- MIGRATION: Use
Module.updateHashsignature changedModule.sortItemsremovedModule.unbuildremoved- MIGRATION: Use
invalidateBuildinstead
- MIGRATION: Use
Module.getSourceTypesaddedModule.getRuntimeRequirementsaddedModule.sizesignature changedModuleFilenameHelpers.createFilenamesignature changedModuleProfileclass added with more dataModuleReasonremovedModuleTemplate.hookssignatures changedModuleTemplate.rendersignature changedCompiler.dependenciesremoved- MIGRATION: Use
MultiCompiler.setDependenciesinstead
- MIGRATION: Use
MultiModuleremovedMultiModuleFactoryremovedNormalModuleFactory.fileDependencies,NormalModuleFactory.contextDependenciesandNormalModuleFactory.missingDependenciesare now LazySetsRuntimeTemplatemethods now takeruntimeRequirementsargumentsserveproperty is removedStats.jsonToStringremovedStats.filterWarningsremovedStats.getChildOptionsremovedStatshelper methods removedStats.toJsonsignature changed (second argument removed)ExternalModule.externalremovedHarmonyInitDependencyremovedDependency.getInitFragmentsdeprecated- MIGRATION: Use
applyinitFragmentsinstead
- MIGRATION: Use
- DependencyReference now takes a function to a module instead of a Module
- HarmonyImportSpecifierDependency.redirectedId removed
- MIGRATION: Use
setIdinstead
- MIGRATION: Use
- acorn 5 -> 8
- Testing
- HotTestCases now runs for multiple targets
async-nodenodewebwebworker - TestCases now also runs for filesystem caching with
store: "instant"andstore: "pack" - TestCases now also runs for deterministic module ids
- HotTestCases now runs for multiple targets
- Tooling added to order the imports (checked in CI)
- Chunk name mapping in runtime no longer contains entries when chunk name equals chunk id
- add
resolvedModuleIdresolvedModuleIdentifierandresolvedModuleto reasons in Stats which point to the module before optimizations like scope hoisting - show
resolvedModulein Stats toString output - loader-runner was upgraded: https://github.com/webpack/loader-runner/releases/tag/v3.0.0
file/context/missingDependenciesinCompilationare no longer sorted for performance reasons- Do not rely on the order
- webpack-sources was upgraded to version 2: https://github.com/webpack/webpack-sources/releases/tag/v2.0.1
- webpack-command support was removed
- Use schema-utils@2 for schema validation
Compiler.assetEmittedhas an improved second argument with more information- BannerPlugin omits trailing whitespace
- removed
minChunkSizeoption fromLimitChunkCountPlugin - reorganize from javascript related files into sub-directory
webpack.JavascriptModulesPlugin->webpack.javascript.JavascriptModulesPlugin
- Logger.getChildLogger added
- change the default of entryOnly of the DllPlugin to true
- remove special request shortening logic and use single relative paths for readable module names
- allow webpack:// urls in SourceMaps to provided paths relative to webpack root context
- add API to generate and process CLI arguments targeting webpack configuration
- add
__system_context__as context from System.js when using System.js as libraryTarget - add bigint support for the DefinePlugin
- add bigint support for basic evaluations like maths
- remove ability to modify the compilation hash after the hash has been created
- remove HotModuleReplacementPlugin multiStep mode
assetInfofromemitAssetwill now merge when nested objects or arrays are used[query]is now a valid placeholder when for paths based on afilenamelike assets- add
Compilation.deleteAssetto correctly delete an assets and non-shared related assets - expose
require("webpack-sources")asrequire("webpack").sources - terser 5
- Webpack can be written with a capital W when at the start of a sentence
Roadmap 2021
It has been nearly 2 months since webpack 5 was officially released. Due to the sponsoring situation, we couldn't devote as much time to webpack as we would like to. Speaking only for myself (@sokra), I enjoyed the little break and have worked on a few side projects. Ironically, while I was using webpack 5 and all its bleeding-edge features (asset modules, worker support, persistent caching), I discovered a few more bugs in webpack 5 that people are likely to run into when upgrading their projects to webpack 5, which led to a lot of work going into bug fixing. Here is a little summary:
What happened so far?
A few more things have been exposed from webpack, both typings-wise and runtime-wise. A few low-handling performance improvements have been made. Code without semicolons used to generate some invalid/incorrect code in some cases, which has been corrected. The combination of side-effect-free code + concatenated modules + reexports has led to some edge cases, which have been fixed (at least the known ones).
But one bug reported by a user has led to the need for a completely new internal feature. You can skip it and go to the next chapter if you find webpack internals boring or too complex.
To trigger the bug we need three ingredients:
- Since webpack 5 the optimization in
productionmode will run the used exports analysis (Tree Shaking) against each runtime (which is often identical to the entrypoints), which means webpack can optimize each runtime (resp. entrypoint) individually. - A custom
optimization.splitChunksconfiguration allows to forcefully merge modules into a single chunk. This is done by passing thenameoption. E.g.{ test: /node_modules/, name: "vendors" }merges modules fromnode_modulesinto a single chunk. While this is not recommended in general, it's possible and probably makes sense in some cases. The whole thing is about trade-offs anyway and choosing to merge all vendors into a single chunk can be good for long term caching this chunk for repeated visits or between multiple entrypoints. - When exports of a side-effect-free module are not used, the whole module is omitted from the module graph and the
import-statement generates no runtime code at all.
A problem happens in an edge case where modules from two entrypoints are merged into a single chunk and they reference a side-effect-free module which is not in the shared chunk since only one of the entrypoints uses exports from the side-effect-free module. Modules in the shared chunk are used by both entrypoint, thus they need to include the exports that are used by any of the entrypoints.
That means it will generate code referencing the side-effect-free module that is not available at runtime for the other entrypoint in the aforementioned edge case, which leads to an undefined is not a function or cannot read property 'call' of undefined error at runtime.
A potential fix would be to include the side-effect-free module in all entrypoints, but as this module isn't really needed, that would be a waste of bundle size.
So we went another route, which required the development of a new feature: runtime-dependent code generation.
This allows to generate code which behaves differently depending on which runtime it executes.
To put it another way, we are wrapping some generated code in if-blocks, so they only execute in one runtime.
In this example, this would affect the import-statement which references the side-effect-free module.
The import is only executed for one of the entrypoints.
This avoids to include unnecessary modules, and it also avoids executing unnecessary code even if it would be available.
So even if you are merging all code into a single chunk, only the code that is really used is executed.
So far for the excurse, I hope it wasn't that boring...
Roadmap 2021
So assuming we can sort out our sponsoring situation, the following is planned for 2021:
Further stabilizing
Our top-priority stays stabilizing webpack 5. So far the situation looks pretty good. Most critical bugs reported in the last time, affect some edge cases. So I guess webpack 5 should work for the general cases. But handling edge cases is (and should stay) one of webpack strength, so we want to continue to work hard fixing these. We think that many many webpack users need custom things for their build and that's something webpack offers via configurability and its rich plugin system.
EcmaScript Modules
EcmaScript Modules (ESM) are slowly gaining wide-spread adoption. On authoring side they are already the de facto standard to write code. On browser support it also looks pretty ok (except for IE11 and a few older mobile browsers). Browsers are still a bit lacking in supporting ESM for WebWorkers.
One can also generate bundles that run in a type=module script tag, but that has few benefits currently.
There are multiple areas in webpack where ESM support can be improved:
ESM as chunk loading mechanism
When targeting the web webpack loads chunks via script tags.
When targeting node.js webpack loads chunks via require or fs + vm.
When targeting WebWorkers webpack loads chunk via importScripts.
In a not-so-far future, all these environments support ESM and more importantly the dynamic import() function.
So a chunk loading mechanism based on import() can unify all these environments, while even needing less runtime code.
Self-executed chunks
Currently on-demand-loaded chunks in webpack are always containers for module and never execute module code directly.
When writing import("./module") in modules, this will compile to something like __webpack_load_chunk__("chunk-containing-module.js").then(() => __webpack_require__("./module")).
There are many cases where this can't be changed (e.g. when loading multiple chunks or loading CSS too), but there are some cases where webpack could generate a chunk that directly executes the contained module.
This could lead to less generated code and would avoid the function wrapping in the chunk.
Currently I'm not yet sure if this is worth it, but it's at least worth looking into that.
ESM exports
Currently it's not possible to generate ESM exports for a bundle via output.library.type: "module".
This can be useful when integrating webpack bundles into ESM loading environments or inline scripts.
ESM externals (import)
Webpack allows to define externals which are modules that are not bundled but exist at runtime.
There are many types of externals ranging from globals over CommonJs/AMD/System to loading from classic script tag.
Even import() (type: "import") can be used to load an external, but import (type: "module") can't be used yet.
Interestingly even while type: "module" isn't supported yet, webpack already uses it as default when writing e.g. import x from "https://example.com/module.js".
The default has been choosing to seamlessly add support for ESM externals without introducing a breaking change.
Absolute URLs in imports can make sense e.g. when using external services that offer their API as ESM: import { event } from "https://analytics.company.com/api/v1.js" (import("https://analytics.company.com/api/v1.js") might make more sense to gracefully handle errors when depending on this external service, but errors could also be caught higher in module graph).
As usual the externals configuration allows to map any module name to externals:
export default {
externalsType: "module",
externals: {
analytics: "https://analytics.company.com/api/v1.js",
svelte: "https://jspm.dev/svelte@3",
react: "https://cdn.skypack.dev/preact@10",
"react-dom": "https://esm.sh/[react,react-dom]/react-dom",
},
};ESM library
When ESM exports and import are supported people might think bundling a library makes sense, and that's probably true in some cases, but in many cases natively bundling will result in worse results.
The biggest problem is the "sideEffects": false flag. It affects modules on per file base to skip whole modules. When concatenating multiple side-effect-free modules it's no longer possible to skip the individual modules, which leads to worse optimization when not all exports of the library are used.
When the output should be a library that will be processed by a bundler later, this needs to be considered.
I could think of a special mode, which does not apply chunking and instead, emit the raw (processed) modules connected via ESM imports and exports (or also CommonJS require).
So this means loaders, module graph, and asset optimizations run, but no chunk graph is created and each module in the module graph is emitted as a separate file.
Strict mode warnings
When generating an ESM bundle, all contained code will be forced to strict mode. For many modules, this isn't an issue, but there are a few older packages that might have trouble with the different semantic. We want to show warnings for these cases.
More first-class citizen
Webpack 4 and 5 did a lot of work to support non-JS module types, and webpack 5 already supports some module types by default: JS (ESM/CJS/AMD), JSON, WebAssembly, Asset. Since webpack 5 one of our long term goals is to become a web-app optimizer, with the goal of supporting everything the browser supports. So technically a vanilla web app should work out-of-the-box with webpack, but being optimized on the go.
The initial webpack 5 release already did some major steps in this direction: new Worker is supported natively. new URL(...) is supported natively (assets).
WebAssembly and JSON is already supported, even while the proposals are not finished yet.
But two resource types are still missing for the complete story: HTML and CSS.
CSS as modules
Currently webpack supports CSS via css-loader, style-loader or mini-css-extract-plugin.
This is working pretty well, but I think we can do more by supporting CSS as a native module type in webpack.
A major benefit would be the developer experience: The mini-css-extract-plugin configuration is not the easiest and getting rid of it would simplify a lot for the developer.
That doesn't mean you can add additional customization on top of that.
I see many developers not using raw CSS, but using preprocessors on top of that (with native CSS support this would look like that: { test: /\.sass$/, type: "stylesheet", use: "sass-loader" }).
As of State of CSS 2020 CSS Modules is a popular way of writing modular CSS and it being a native module type in webpack allows to benefit from module graph optimization like Tree Shaking (Used Exports Optimization and Side-Effects optimization). When using CSS Modules this means the resulting CSS will only contain CSS rules that are referenced from the application (as one is used to from JS Tree Shaking).
There are some potential CSS Modules specific optimizations which are possible with the global knowledge of the application webpack has: CSS rules can be split into smaller rules to avoid repeating common properties. This can result in a much smaller payload as the output CSS contains fewer repeated properties (Atomic CSS).
But there is a big "BUT" here: There is work towards a different "CSS Modules" proposal in the WebComponents community, which is planned to become natively supported by browsers. At least that's the goal of the proposal. Sadly this proposal is different from what's currently used in the Frontend ecosystem but uses similar syntax. Usually, webpack would align with proposals, so that's something to consider here. We have to check whether it's possible to avoid potential conflicts.
HTML as entrypoint
Following Parcels example, we also want to support HTML natively as entrypoints. Supporting that would be inline with the goal as web app optimizer, as web apps usually start with an HTML document. It is also a huge developer experience improvement for beginners as many things can be inferred from the HTML.
Being in control of the generated HTML does also allow to optimize more aggressively by default. Currently, we prevent renaming or splitting initial chunks by default, as this requires additional infrastructure for the HTML generation.
HTML entrypoints also benefit from CSS as modules and Asset modules, as these resources can be referenced from HTML too (e.g. <link rel=stylesheet />, <img src="..." />, <link rel=icon />).
HTML modules
There is also a proposal about native support of importing HTML in browsers, that's something we will follow, especially as there is a huge overlap with HTML entrypoints.
SourceMap performance
Using (full) SourceMaps with webpack is currently quite expensive with webpack, as performance for SourceMap processing isn't the best. This is something we want to look into for webpack, but also for terser, which is used by webpack as minimizer by default.
exports/imports package.json field
Node.js 14 has added support for the exports field in package.json to allow to define entrypoints of a package.
Webpack 5 followed this, and even added additional conditions like production/development.
Shortly after that Node.js made further additions to that, e.g. they also added an imports field for private imports.
That's something we also want to add.
Improve CommonJS analysis
While ESM is the future, there are still a lot of CommonJS packages in npm and in use. Webpack 5 added analysis for CommonJS modules to allow Tree Shaking for most of these modules.
But we can do more. While many exporting patterns are supported, only a few importing patterns are supported. We want to add support for more patterns to allow more optimizations for CommonJS modules too.
Hot Module Replacement for Module Federation
Webpack 5 added a new feature called "Module Federation" which allows integrating multiple builds together at runtime. Currently, Hot Module Replacement (HMR) supports only a single build at a time and updates can't bubble between builds. We want to improve here and allow HMR updates to bubble between different builds, which would improve developing federation applications.
Hinting system
Currently, webpack displays warnings and errors to the user. During the build, there are quite a few cases where we could tell the user something, like potential footguns or optimization opportunities, but they don't fit into warnings or errors and we don't want to spam the output with all this information. So we want to add another category: Hints. We want to collect all hints during builds (plugins could also emit some), but only display a limited number of them in the output (by default only one). This should lead to some kind of "Did you know" experience for the user.
Multi-Threading
While Persistent Caching makes cached build "blazing" fast, initial builds without Persistent Cache have still a bit of room for improvement.
Javascript execution in Node.js is single-threaded by default, but recent additions allow to use worker_threads, which is an API similar to WebWorkers.
This can be used distribute work across all CPUs. There has already been some preparations in webpack 5 for that: e.g. serializing of internal data structures is possible and the work queues support plugins. But some parts of that are still unclear and require experimentation.
This is in our voting list for a while, but not many have voted on that. Is this really something people need?
WebAssembly
Currently, WebAssembly is experimental and not enabled by default. Once the proposal reaches Stage 4 we can enable it by default.
This might also lead to a wider adoption of WebAssembly in the ecosystem. I think we might see more in this field in 2021.
Disclaimer
This list is not set in stone. The web ecosystem changes so fast that we probably end up implementing totally different things, that we might not even aware of at this time. We do not even know how much time we can invest in webpack, considering our current sponsoring situation.
Webpack 5.105
Webpack 5.105 brings several improvements, both in code generation and bug fixes.
- Two Low-Severity CVEs Fixed in Webpack
tsconfig.jsonAlias Resolution Without Requiring plugins- Automatic Module Resolution for Web Workers
- Support Import Specifier Guard
- Support
import.defer()for Context Module - Preserving Custom
import.metaProperties - Better Control of Source Maps in
devtool - Cleaner ESM output for Node.js and modern builds
- Other Improvements and Bug Fixes
Two Low-Severity CVEs Fixed in Webpack
Two new low-severity CVEs in Webpack have been fixed and published.
By default, you are safe; these issues only affect users of the experimental
experiments.buildHttp option.
Affected CVEs:
CVE-2025-68157
- For more details, see the advisory: GHSA-38r7-794h-5758
- Affected versions:
>=5.49.0 <5.104.0
CVE-2025-68458
- For more details, see the advisory: GHSA-8fgc-7cc6-rx7x
- Affected versions:
>=5.49.0 <5.104.1
Even though these are low-severity CVEs, it’s still a good idea to update if you use the affected versions.
For more information on reporting security vulnerabilities, see the Webpack Security Policy .
tsconfig.json Alias Resolution Without Requiring plugins
Module resolution can be configured to read compilerOptions.baseUrl and compilerOptions.paths from tsconfig.json and apply those aliases when resolving imports. As a result, it is no longer necessary to install and configure the external tsconfig-paths-webpack-plugin just to make TypeScript path aliases work during bundling.
In the webpack configuration, the resolve.tsconfig option is used to specify which tsconfig file should be used as the source (which is also useful in monorepos or setups with multiple tsconfig files):
// webpack.config.js
module.exports = {
resolve: {
tsconfig: "./tsconfig.json", // Can be `false` (disabled), `true` (use the default tsconfig.json), a path to a `tsconfig.json` file, or an object with configFile and references options.
},
};Example of aliases in tsconfig.json:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}And then in the code:
import Button from "@/components/Button";This way, @/components/Button can be resolved according to the rules defined in tsconfig.json, avoiding the need to duplicate aliases in resolve.alias and reducing discrepancies between what TypeScript understands and what the bundler resolves.
Automatic Module Resolution for Web Workers
When importing a package specifically to be used in a Web Worker in Webpack, module resolution can prioritize files like index.worker.js over index.js when using conditional exports defined in the exports field of package.json.
This means that if you define conditions such as "worker" in your package's exports, Webpack will automatically select the appropriate version, like index.worker.js, whenever the package is imported inside a worker context. There’s no need to modify the resolve.conditionNames option or make additional Webpack configuration changes; you just need to specify the conditions correctly in package.json.
For example, in package.json:
{
"name": "foo",
"exports": {
".": {
"worker": "./index.worker.js",
"default": "./index.js"
}
}
}Now, when importing the foo package inside a Worker, Webpack will automatically choose the index.worker.js file according to the export conditions:
// This import is inside a Worker context, so Webpack uses index.worker.js
const worker = new Worker(new URL("foo", import.meta.url), {
type: "module",
});Support Import Specifier Guard
Support for import specifier guards has been added, an improvement that helps the bundler better understand a common pattern checking whether an export exists before using it. Previously, even if the code was correctly guarded by an if, the access could be interpreted as unconditional and result in warnings like “export … was not found”.
With this change, those checks are recognized as a signal that the access is conditional, and the analysis is adjusted accordingly. In practice, this makes it possible to write code that is more compatible across different versions of the same library, where an export may or may not exist, without unnecessary noise during compilation.
import * as React from "react";
if (React.useId) {
// create guard for `React` => userId: ["", "useId"].
React.useId; // React -> "useId" is in guard.
React; // React -> "" is in guard.
}Support import.defer() for Context Module
Webpack now supports import.defer() even when the import is a context module (that is, when the import path is built dynamically and webpack needs to include a set of possible files). In practice, this makes it much easier to defer the loading of a module selected at runtime, even when that module comes from a dynamic expression pointing to a directory. This enables patterns like “choose between a.js or b.js and load it only when needed”, with webpack generating the appropriate context so that import.defer() works correctly.
const file = Math.random() > 0.5 ? "a.js" : "b.js";
import.defer("./dir/" + file);
Preserving Custom import.meta Properties
Webpack now preserves custom import.meta properties during bundling when output.module is enabled. Previously, Webpack would remove any unknown import.meta properties (such as import.meta.customProp), causing the loss of contextual or tool-specific information in the build.
With this change, any non-standard property you add to import.meta will remain intact in the generated code, allowing the use of custom meta-information or additional signals in modern applications.
if (!import.meta.UNKNOWN_PROPERTY) {
// runtime assignment
import.meta.UNKNOWN_PROPERTY = "HELLO";
}If output.module is not enabled, Webpack will continue to remove unknown properties unless you explicitly indicate otherwise. To preserve them manually, you can configure module.parser.javascript.importMeta as 'preserve-unknown' in your webpack.config.js:
// webpack.config.js
module.exports = {
module: {
parser: {
javascript: {
importMeta: "preserve-unknown",
},
},
},
};This way, even without output.module: true, any custom import.meta property, such as import.meta.customProp, will be preserved in the build.
Better Control of Source Maps in devtool
Webpack now allows the devtool option to accept both a string and an array of objects for advanced configurations.
Each object in the array can include:
type: which can be"all","css", or"javascript".use: where you define the type of source map to generate.
This enables specifying different types of source maps for different resources in your project. For example:
// webpack.config.js
module.exports = {
target: ["web", "node"],
experiments: {
css: true,
},
devtool: [
{
type: "javascript",
use: "source-map",
},
{
type: "css",
use: "inline-source-map",
},
],
};In this example, standard source maps are applied to all modules, and inline source maps are used specifically for CSS files.
This new option is especially useful if you are using Webpack’s experimental CSS compilation feature, as it gives you greater control over the debugging process and improves integration with external tools.
It’s worth noting that the classic string syntax, like devtool: "source-map", remains fully valid and supported.
Cleaner ESM Output for Node.js and Modern Builds
This improvement in Webpack optimizes the handling and representation of Node.js native modules (such as fs, path, or crypto) during bundling, especially when using the output.module option in the configuration. When output.module: true is enabled, Webpack now generates imports of native modules using ES module syntax import ... from "module" instead of CommonJS require("module"), regardless of whether the code will run in a web or Node.js environment.
Other Improvements and Bug Fixes
- Webpack-dev-server has released a new version to update dependencies that had reported transitive vulnerabilities, so updating is recommended. Additionally, the option to close the error overlay by pressing the ESC key has been added, and several bugs have been fixed. Check the release for more information.
- Webpack-bundle-analyzer has received important improvements and fixes for the user experience. Visual issues with tooltips in dark mode have been resolved, and the analysis of bundles using IIFE has been made more robust, preventing errors. Additionally, support for Zstandard compression has been added, available only on Node.js 22.15 or higher. Check the changelog for more information
- Mini-css-extract-plugin introduces new features and bug fixes. Among the main changes, the plugin now respects the
output.cssFilenameandoutput.cssChunkFilenameoptions, allowing more precise control over the names of the generated CSS files. Additionally, a bug was fixed that prevented the generation of thecontentHashfor a chunk when the CSS module set had zero size, thus avoiding unnecessary hashes in those cases. Check the release for more information
Several bug fixes have been resolved since version 5.104. Check the changelog for more details
Thanks
A big thank you to all our contributors and sponsors who made Webpack 5.105 possible. Your support, whether through code contributions, documentation, or financial sponsorship, helps keep Webpack evolving and improving for everyone.
Roadmap 2026
Hello from the webpack Technical Steering Committee member Even!
The different contributors in the organization continue to work on ensuring that webpack remains a solid and reliable tool for building web applications. While many new tools have emerged, webpack continues to be a stable and well-supported choice.
Here’s what we’re excited about for 2026
In 2026, our focus goes beyond maintaining existing features. We’re investing in improvements that make webpack easier to use and maintain, while also pushing forward ideas that prepare the project for modern runtimes, evolving development patterns, and the long-term health of the ecosystem.
Below, we’ll walk through the main areas we’re actively working on and the ideas we plan to develop throughout the year.
webpack#14893 - Support for CSS Modules without the need for plugins
There is currently an experimental.css option, which enables native CSS support without the need to add plugins to your configuration, as was previously required with plugins like mini-css-extract-plugin.
The development is already quite advanced, with the possibility of finishing the inclusion into webpack core around February/March. After that, the support would remain experimental for a while to gather bug reports, but in webpack 6 it will no longer be experimental and plugins for this task will no longer be necessary.
You can follow the discussion about experimental CSS support to stay updated and contribute ideas.
webpack#6525 - A universal target to make your code compatible across runtimes
The idea is to add a new target called universal, which will compile your code so it can run across different runtimes, including Node, the web, Bun, Deno, etc. Regardless of whether you use CommonJS modules in your application, webpack will be able to wrap them, and all the resulting code will be pure ESM, making it runtime-agnostic.
There has already been significant progress toward this goal, but ESM output is not fully finished yet. Additional fixes and improvements are still required (see webpack#17121), along with adding missing tests and completing the CommonJS wrapper functionality.
You can also join the discussion about universal target to share your ideas or follow updates on cross-runtime compatibility.
Support for building TypeScript without loaders
Recently, in version 5.105 we included support for resolving the paths defined in the TypeScript configuration, eliminating the need to use a plugin (tsconfig-paths-webpack-plugin). Now we want to further expand TypeScript support by removing the need to use a loader (the most common one being ts-loader) to transpile TypeScript directly in webpack, which would also reduce your project’s dependencies.
webpack#536 - Import HTML files and use them as entry points without the need for plugins
Currently, to import HTML files and use them as entry points, it’s necessary to use a plugin (html-webpack-plugin). The idea is to integrate that plugin into the core of webpack itself, similar to how CSS Modules are being handled, and remove the need for a plugin for such a common task. Like CSS Modules, this would be introduced as an experimental option, so that in webpack 6 you’ll be able to remove that dependency.
You can follow the idea and its progress in the related issue (#536).
Webpack Everywhere (Node, Deno, and Bun, Web)
Node.js is still the default runtime for many projects, but times have changed and it’s no longer the only JavaScript runtime. New options like Deno and Bun have gained significant popularity, and webpack should work seamlessly across all of them.
The goal is to build webpack so it can run everywhere: in Node.js, in web environments, and in alternative runtimes like Deno and Bun. Even when using modules traditionally tied to Node.js, such as node:fs, webpack will intelligently handle them, enabling code that depends on these modules to run in the browser or other environments where these modules don’t exist.
To achieve this, we need to reduce reliance on Node.js internals and Buffer usage, move toward a more runtime-agnostic architecture, and expand test coverage.
Currently, Deno support is missing proper tests, while Bun still lacks required assets and corresponding tests. In addition, this effort includes adding a site playground to validate and showcase webpack running across different environments.
Evaluating Lazy Barrel Optimization
One interesting idea to explore is lazy barrel optimization, inspired by how Rspack handles certain module patterns. In Rspack, lazy barrel is an optimization that skips building unused re-exported modules in side‑effect‑free barrel files until they’re actually needed. This can significantly reduce build time, especially in large codebases with lots of grouped exports.
Barrel files are modules that re-export other modules to create a convenient API surface. For example, a components/index.js that exports every component from a directory. While useful for organizing code, traditional bundlers often build all the re-exported modules even if only one is used, which can hurt performance. With lazy barrel optimization in Rspack, only the modules actually referenced get built, skipping the rest and improving overall build speed.
Evaluating Rspack’s approach gives us an opportunity to see whether a similar strategy could benefit webpack, improving performance around commonly used barrel patterns without requiring developers to restructure their exports manually. It’s an example of looking outward at innovations in the ecosystem to inform possible future enhancements for webpack.
Simplifying Asset Minimization in Webpack
Webpack currently relies on multiple separate minimizer plugins, such as terser-webpack-plugin, css-minimizer-webpack-plugin, html-minimizer-webpack-plugin, and json-minimizer-webpack-plugin. While each one works well on its own, managing them individually adds extra configuration and maintenance overhead.
The idea is to combine all of these into a single minimizer-webpack-plugin, providing a more unified and consistent minimization experience. This would simplify configuration, reduce duplication, and make it easier to extend and maintain minimization logic across different asset types.
Streamlining Webpack’s Dev Experience
Webpack’s development and CLI tools are being improved to enhance maintainability while also introducing new features for contributors and users alike.
Dev Tooling
Efforts in development tooling focus on improving webpack’s internal development workflow and making it easier to extend and maintain. This includes merging webpack-dev-middleware and webpack-hot-middleware, extracting the overlay from dev-server, and consolidating overlay + WebSocket/EventSource logic for reuse.
Additionally, plugin support will be added to the dev-server, enabling more flexibility and reducing duplication. These improvements streamline development for contributors while keeping webpack flexible and reliable for users.
CLI Improvements
The CLI is being refined to simplify maintenance and improve usability. Work includes consolidating packages, refactoring help and subcommand logic, and improving the overall developer experience (see webpack-cli#4619).
These changes make it easier for contributors to maintain the CLI while also providing practical enhancements for developers working with webpack in their projects.
You can follow the webpack-cli improvements discussion to stay updated.
Accurate and Reliable Documentation
The idea is to enable automatic generation of all API and configuration documentation directly from webpack’s types and schemas, ensuring the documentation always matches the actual behavior of the code (new api options, deprecations, types etc).
This approach addresses long-standing problems with incomplete, or inconsistent documentation on the webpack website, and makes it easier to maintain. The goal is to provide developers with accurate, reliable, and up-to-date references that gives users a easy way to interact with webpack.
Community Outreach and Engagement
Following improvements to documentation and active maintenance, another key focus is building and strengthening the webpack community. This year, the effort began with a new blog launched for webpack 5.105, and the idea is to continue expanding our outreach through articles, conference talks, and other public channels.
By engaging the community, webpack can grow adoption, receive valuable input, and create stronger connections between the project and its users. Outreach efforts also help ensure that improvements, tutorials, and best practices reach a wider audience, making the ecosystem more vibrant and sustainable.
Multithreading API
Webpack is exploring a Multithreading API, inspired by thread-loader, to bring better parallel processing capabilities into the core.
The goal is to allow webpack to take advantage of multi-core systems, improving build performance for large projects. This effort is still in the design and discussion phase, aiming to create a solution that is flexible, maintainable, and easy to use.
By integrating multithreading in a more formal way, webpack hopes to provide developers with faster builds while keeping the configuration and internal logic clean and scalable. This work reflects ongoing exploration rather than a finalized feature, and thread-loader remains the current community-supported solution for parallelization.
Design and Visual Identity
We want to improve webpack’s overall visual identity by creating new design assets for projects and swag. This includes things like banners, clothing merch, water bottles, coffee cups, socks, and other branded materials.
Beyond making webpack look more polished and recognizable, these assets also open the door to future merchandise sales, where purchasing swag would directly help fund and support webpack’s ongoing development.
GSoC Mentorship
A key focus is mentoring students through the Google Summer of Code (GSoC) program, a volunteer-driven effort with the goal of teaching them how to effectively maintain open source projects.
Through hands-on guidance, students learn workflows, best practices, and how to approach maintaining a codebase. At the same time, this mentorship allows the project to develop new features, as students work on functionalities that are needed while being guided by experienced contributors.
This experience equips them with the skills needed to become future maintainers, contributing not only to webpack but also to the broader open source ecosystem, which relies heavily on volunteers.
By emphasizing maintainability, knowledge transfer, and guided feature development, GSoC mentorship helps secure long-term sustainability and cultivates the next generation of contributors for open source projects.
Donations and Sponsorships
Open source projects like webpack are maintained primarily by volunteers, and there isn’t a full-time engineering team dedicated to the project.
Growing donations and sponsorships is crucial because the more funding available, the more time the core contributors can dedicate to maintaining and improving webpack, despite having other responsibilities and personal lives.
Support through donations not only helps sustain ongoing maintenance but also enables contributors to focus on new features, bug fixes, and improving the ecosystem overall. By contributing financially, the community directly helps ensure webpack remains healthy and actively developed.
Preparing for Webpack 6
All the efforts covered in this blog, from enhancing runtime support (Node, Deno, Bun, and universal targets), improving documentation and developer tooling, mentoring new contributors through GSoC, to exploring multithreading and optimizations like lazy barrel, are paving the way toward webpack 6.
Core and Loader Improvements
To prepare for webpack@6 and simplify internal logic, efforts include moving loader-runner into core to unify loader context handling. This helps reduce duplication, improves maintainability, and lays the groundwork for future enhancements.
Additionally, reducing internal TODOs across the codebase ensures a cleaner foundation and makes it easier for contributors to work efficiently.
Testing and Type Coverage
Improving test coverage and strengthening type coverage are key priorities. By reducing the use of any, unknown, and other loose types, webpack becomes more reliable and easier to maintain. Strong types and thorough tests help catch issues earlier and improve confidence for contributors making changes.
Benchmarks and Performance
To measure progress and maintain high performance standards, webpack plans to add more benchmarks. Integrating these benchmarks into CI pipelines allows comparisons across versions, ensuring that optimizations continue to deliver tangible improvements for developers.
Final remarks
I hope that you found this list useful and that you are excited for 2026, we are too! One of the most important parts of our work now, is to get enough donations to keep the project sustainable. We use our resources to pay contributors once they reach a certain threshold. In addition to that, we want to make sure that over time, the project has some left-over resources that we can save for when times are hard.
This year we will try something new, which is to have allocated sections where companies/individuals that contribute a significant amount will have a spot to showcase their product/project/promotion.
Thank you for the attention and for being interested in our roadmap for 2026. If you are curious about contributing to the organization either financially or otherwise, send us a private or public message in Discord, reach us through email or contact one of the TSC members.
~ webpack TSC 💙

