webpack's published tarball ships six paths and no examples, and its lint step regenerates code
webpack is a module bundler for JavaScript apps, packing modules into optimized bundles with code splitting for on-demand loading and loaders for CSS, images, and more.
At a glance
- What is it?
- webpack is at version 5.111.1 with a release nine days old and a push from yesterday. Reading the packaging and the scripts rather than the feature list is more informative: the npm tarball contains six paths and none of the examples directory, the built-in HTML and CSS support is labelled experimental, and the lint target runs nine code generators before it type-checks anything.
- Who is it for?
- Stay on webpack when you need the plugin surface and the loader ecosystem rather than a zero-config default, and expect to own the configuration. Four things to know before you rely on it.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The browser floor is ES5, and its own dynamic import needs a Promise polyfill
The compatibility statement is short and specific: webpack supports all browsers that are ES5-compliant, and IE8 and below are not supported. The second sentence is the one that catches people.
webpack also needs `Promise` for `import()` and `require.ensure()`. If you want to support older browsers, you have to load a polyfill before using those expressions.
So the two mechanisms behind code splitting are not available in the baseline environment the project itself states, unless something is loaded first. The page does not treat that as a contradiction, because ES5-compliant does not mean Promise exists, but the practical effect is that code splitting, which is the feature most projects adopt a bundler for, carries a documented precondition separate from the support statement.
Note also that `require.ensure()` is still documented next to `import()`. That is the older spelling of the same idea, kept for compatibility, and its presence is a fair signal about how much legacy surface the project carries. On a modern target none of this costs you anything. It matters when you support an old browser, and when you read a tutorial that uses one form while your build uses the other.
HTML generation and CSS extraction are in core, and both are labelled experimental
The plugin section states that webpack can generate HTML pages and extract CSS files itself, and puts the word experimental on both. The documentation is then split deliberately, with separate pages for CSS and HTML that each cover what is built in and what still needs a plugin.
That is a significant change in what the tool is, and it is easy to miss if you learned webpack before it. The two jobs that most projects solved with a third-party plugin are now core capabilities, and the project is telling you that the interface for them is not settled.
The consequence is practical for anyone following older guidance. If a tutorial from a few years ago tells you to install an HTML bundler plugin or a CSS extraction plugin, the first thing to check is the built-in page, because part of what that plugin did may now live in core. Installing both is where configuration fights start, since you end up with two mechanisms writing the same output.
The other consequence is about upgrade planning. Experimental inside a project sitting at version 5.111.1 means the feature has shipped and is usable, but its options may still change without a major version bump. If you adopt the built-in HTML generation, plan to read its changelog entries on upgrade rather than assuming stability.
The plugin table draws from two different GitHub organisations
The recommended plugins table has three rows, and the repositories behind them are not from one place. The compression plugin comes from the webpack-contrib organisation. The HTML bundler plugin and the Pug plugin both come from an account called webpackdiscus.
Two of the three recommended plugins therefore come from a single outside account rather than from a collection the project team curates as a unit. That is a fact about maintenance, not about quality, but it changes where you look when one of them stops working.
The table also carries two kinds of live badge per row. The npm version comes from a shields.io endpoint and the install size from packagephobia, so the numbers you see in the README are as fresh as those services' most recent lookup rather than as of the last commit to the file. A version column that looks current can still be behind, and nothing in the repository records when it was last accurate.
One clarification on the compression plugin, because the name oversells it: its job is to prepare compressed versions of assets so they can be served with Content-Encoding. That is producing precompressed files, not compressing on the fly at request time. Read it that way when you decide whether you also need a server or CDN setting.
JavaScript and assets need no loader, so the remaining loaders are preprocessors
Loaders are how webpack preprocesses files, and they are still activated two ways: with a `loadername!` prefix inline in a `require()` statement, or automatically by a regular expression in the configuration.
The inline prefix is the older mechanism and it is still documented, which means two eras of loader configuration coexist in the same tool. Configurations written years apart both work.
The more consequential line is about what no longer needs a loader. JavaScript, JSON and assets need none. CSS and HTML have experimental built-in support. What is left requiring a separate package is the preprocessor and template engine layer, and the page says so in as many words: preprocessors and template engines keep their loaders.
The consequence is that the native work has already been done and your dependency count has not dropped as much as you would expect. A typical project still assembles a preprocessor such as Sass or Less, and at least one template engine, as loaders on top of the bundler. That is where most of your install surface comes from, and it is the part of the ecosystem the core does not absorb.
If you are writing a loader yourself, the page points at the loaders API and notes you can do it in Node.js, so a custom transform is a normal thing to own rather than an escape hatch.
The published package contains six paths, and the examples directory is not one of them
The package manifest has a files allowlist, and it is short:
"files": [
"lib/",
"bin/",
"hot/",
"schemas/",
"SECURITY.md",
"module.d.ts",
"types.d.ts"
],The entry points follow from it: main is lib/index.js, types is types.d.ts, and the bin entry maps webpack to bin/webpack.js.
The repository, meanwhile, contains docs/, examples/, test/, tooling/, setup/, declarations/, assembly/ and a long list of TypeScript configuration files. None of that is in the tarball.
So the consequence is that the examples directory, which is the most concrete behaviour reference the project has, is something you read on the repository and not something you have after installing. The example tree is large and heavily weighted toward code splitting, with around ten separate directories covering different chunking mechanisms, so it is genuinely useful as a matrix of cases. It is just not available locally once the package is installed.
Shipping SECURITY.md inside the package is the deliberate exception in that list, and it is a good one. It means the security policy travels with the dependency in your node_modules rather than existing only on a website you would have to go and find.
The lint target regenerates nine kinds of code before it checks anything
The lint script is a chain of ten gates, and one of them is not a check. It runs lint:code, then lint:agents, then lint:special, then four separate type-check passes, then a format check and a spellcheck.
The interesting one is lint:special, which executes nine generators in sequence. They produce the runtime code, the WebAssembly code, the CSS data, the HTML data, the JavaScript data, the schemas, the precompiled schemas, the type definitions and the internal serializables. The type generator is invoked with a flag disabling template literals.
The consequence is that linting is not read-only. Running the project's own lint command can write files, which means a generated file that has drifted from its source shows up in continuous integration as a change rather than as a lint error, and locally it is easy to commit generated output by accident. The prelint hook, which runs a setup script before linting, adds a second step with the same character.
The WebAssembly side of this is visible in the tree as an assembly/ directory alongside the WebAssembly generator, so the same generate-then-check pattern covers a second target. It is a reasonable arrangement for a project that ships generated runtime and type output, and it is worth knowing about before you file a bug that turns out to be a stale generated file.
A lint rule enforces a size limit on AGENTS.md, and hooks install on setup
One of the ten lint gates is a single script whose name says what it does. The lint:agents step runs a file called check-agents-md-size.js, which is a size check on the repository's agent instruction file.
That is a small engineering choice with a clear philosophy behind it. The project treats its instructions for automated agents as a budgeted artefact rather than an unbounded document, and it enforces that budget in the same gate as the code style. There is an AGENTS.md at the top level, and a cspell.json driving the spellcheck gate, so the same idea of keeping generated and written text consistent runs through both.
Release notes take the other path. A .changeset/ directory sits alongside CHANGELOG.md, which is the changesets workflow, so a changelog entry is a file in a pull request rather than a commit message convention. Combined with the release schedule document in the tree, the release process is unusually visible for a project of this size.
One operational detail catches contributors out. The prepare script runs husky, and lint is preceded by a setup step, so a fresh clone has neither the git hooks nor the generated files until you install. That is normal, but it means the first lint run on a new machine does more than check.
A release schedule is a tracked file, and governance lives in three documents
The tree carries RELEASE_SCHEDULE.md, GOVERNANCE.md and WORKING_GROUP.md, and the README has its own sections for a Technical Steering Committee, core collaborators, and sponsoring with premium, gold, silver and bronze partner tiers. The package manifest declares its funding as OpenCollective.
Putting the release schedule in a tracked file is the part worth noticing, because it turns cadence into something reviewable in a diff rather than a convention people remember. The three most recent releases support it: v5.110.3 on 2026-09-01, v5.111.0 on 2026-09-14 and v5.111.1 on 2026-09-18, which is seventeen days then four.
The consequence for you as a consumer is that this is a long-lived line rather than a project in flux. It is still major version 5 at patch 111, with a published schedule, a changesets-based changelog, a security policy shipped inside the package and a documented governance structure. That combination argues for pinning an exact version and reading the changelog on upgrade, rather than tracking a range and discovering behaviour changes in a build log.
It also means the questions people usually ask a bundler, who decides, how often does it ship and where does the money go, are all answerable from files in the repository rather than from inference.
Editorial conclusion
Stay on webpack when you need the plugin surface and the loader ecosystem rather than a zero-config default, and expect to own the configuration. Four things to know before you rely on it. The features you are most likely to want from a plugin, HTML generation and CSS extraction, are now in core and marked experimental, so check the built-in documentation before installing html-webpack-plugin or a CSS extractor, and expect that interface to move. The published package contains no examples and no documentation, only lib, bin, hot, schemas and three declaration files, so the behaviour reference lives on the repository, not in your node_modules. The stated browser floor is ES5, while dynamic import and require.ensure both need a Promise polyfill on older targets. And linting is not read-only, because the lint target regenerates runtime code, WebAssembly glue, the data tables, the schemas and the type definitions before checking them. Pin an exact version rather than a range, since a major version 5 at patch 111 is a long-lived line with a published release schedule behind it.
Frequently asked questions
What exactly does webpack do?
It is a module bundler whose main purpose is to bundle JavaScript for use in a browser, and it can also transform, bundle or package other assets. It resolves dependencies at compile time, can emit a single bundle or multiple chunks loaded asynchronously at runtime, preprocess files through loaders, and extends through a plugin interface that most of its own features are built on.
Is webpack still used in 2026?
The project page does not discuss adoption figures or make any claim about it. What it does show is the state of the project: version 5.111.1 released on 2026-09-18, a last push on 2026-09-29, a release schedule kept as a tracked file, changesets driving the changelog, and governance split across a technical steering committee and two documents. It names no successor and no migration target.
How do you install webpack using npm?
The page gives `npm install --save-dev webpack`, and `yarn add webpack --dev` for yarn. Note the dev flag: webpack is installed as a development dependency, because it runs at build time rather than in the browser. The project itself is developed with yarn, and the repository carries both a yarn lockfile and yarn and npm configuration files, so a contributor clone and a consumer install use different tooling.
How do you use webpack with TypeScript?
The project page does not document a TypeScript setup specifically. What it says is that loaders preprocess files while compiling and gives TypeScript to JavaScript as the example of that, and that preprocessors keep their loaders rather than moving into the built-in support that JavaScript, JSON and assets now have. It links the loaders API and notes you can write your own in Node.js.
How do you use webpack-dev-server?
The project page does not cover webpack-dev-server, and there is nothing in what it publishes about a development server. What it documents is the bundler itself, its loaders and its plugin interface, and it points you to the Get Started guide and the other guides on the documentation site for anything beyond that.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/webpack-webpack)
Community notes