Skip to content

Commit d74d6cd

Browse files
authored
blog: webpack 5.106 (#8013)
* docs: add blog post for Webpack 5.106 with CSS Modules runtime style injection * docs: add section on plugin validation with compiler.hooks.validate in Webpack 5.106 blog post * blog: add section on better tree shaking for CommonJS destructuring in Webpack 5.106 blog post Signed-off-by: GitHub <noreply@github.com> * docs: add support for context option in VirtualUrlPlugin for resolving relative imports in virtual modules * blog: add experimental JavaScript parsing example with oxc-parser in Webpack 5.106 blog post * blog: add section on other improvements and bug fixes in Webpack 5.106 blog post * blog: update Webpack 5.106 blog post with new sections on ecosystem updates and other improvements * docs: improve * blog: enhance Better Tree Shaking section with examples for CommonJS destructuring * rename file with new date * blog: refine introduction and update section titles for Webpack 5.106 * blog: enhance Plugin Validation section with detailed explanation and examples * docs: improve * fixup! * blog: update version reference in Bug Fixes section from 5.104 to 5.105 * blog: add Getting Started section for create-webpack-app to guide new users * rename date * rename file * blog: add Webpack 5.106 release notes with new features and improvements * blog: update Webpack 5.106 release notes to include source-phase imports for WebAssembly * fixup! * docs: more improvents * update date of the blog * add link --------- Signed-off-by: GitHub <noreply@github.com>
1 parent 87d1880 commit d74d6cd

File tree

1 file changed

+320
-0
lines changed

1 file changed

+320
-0
lines changed
Lines changed: 320 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
---
2+
title: Webpack 5.106
3+
sort: 20260408
4+
contributors:
5+
- bjohansebas
6+
---
7+
8+
**Webpack 5.106 introduces plugin validation hooks, built-in runtime style injection for CSS Modules, smarter tree shaking for CommonJS destructuring, source-phase imports for WebAssembly modules, and an experimental integration with `oxc-parser` for faster JavaScript parsing.**
9+
10+
Explore what's new in this release:
11+
12+
- [**Plugin Validation with `compiler.hooks.validate`**](#plugin-validation-with-compilerhooksvalidate)
13+
- [**CSS Modules with Runtime Style Injection**](#css-modules-with-runtime-style-injection)
14+
- [**Better Tree Shaking for CommonJS Destructuring**](#better-tree-shaking-for-commonjs-destructuring)
15+
- [**Source Phase Imports for WebAssembly (Experimental)**](#source-phase-imports-for-webassembly-experimental)
16+
- [**Getting Started with `create-webpack-app`**](#getting-started-with-create-webpack-app)
17+
- [**Context Support for VirtualUrlPlugin**](#context-support-for-virtualurlplugin)
18+
- [**Experimental JavaScript Parsing with `oxc-parser`**](#experimental-javascript-parsing-with-oxc-parser)
19+
- [**Ecosystem Updates**](#ecosystem-updates)
20+
- [**Bug Fixes**](#bug-fixes)
21+
22+
## Plugin Validation with `compiler.hooks.validate`
23+
24+
Webpack adds a new top-level `validate` option and a [`compiler.hooks.validate`](/api/compiler-hooks/#validate) hook that standardize how schema validation works across webpack configuration, plugins, and loaders.
25+
26+
Until now, there was no unified way for plugins to integrate schema validation into the webpack build lifecycle. Each plugin handled validation on its own. The new `compiler.hooks.validate` hook gives plugin authors a standard API to register their validation logic, and `compiler.validate(...)` to run it. This means all validation from webpack's core config to every plugin that adopts the hook is controlled by a single `validate` flag and follows the same patterns:
27+
28+
```js
29+
module.exports = {
30+
// Disable schema validation (webpack config, plugins, and loaders)
31+
validate: false,
32+
};
33+
```
34+
35+
The default value depends on the build mode:
36+
37+
| Mode | `experiments.futureDefaults` | Default `validate` |
38+
| ----------- | :--------------------------: | :----------------: |
39+
| development | `false` | `true` |
40+
| development | `true` | `true` |
41+
| production | `false` | `true` |
42+
| production | `true` | `false` |
43+
44+
For plugin authors, integrating validation is straightforward. Register a tap on `compiler.hooks.validate`, and webpack takes care of the rest, including skipping validation entirely when the user sets `validate: false`:
45+
46+
```js
47+
class MyPlugin {
48+
constructor(options = {}) {
49+
this.options = options;
50+
}
51+
52+
apply(compiler) {
53+
compiler.hooks.validate.tap("MyPlugin", () => {
54+
compiler.validate(
55+
() => require("./schema/MyPlugin.json"),
56+
this.options,
57+
{ name: "My Plugin", baseDataPath: "options" },
58+
(options) => require("./schema/MyPlugin.check")(options),
59+
);
60+
});
61+
62+
// ...normal plugin logic here...
63+
}
64+
}
65+
66+
module.exports = MyPlugin;
67+
```
68+
69+
When `validate` is `true` and something is wrong, webpack throws a clear error at compile time.
70+
71+
When `validate` is `false`, that check is skipped entirely. The build may still fail later with a less obvious error, so use this option with care.
72+
73+
## CSS Modules with Runtime Style Injection
74+
75+
Webpack now supports `exportType: "style"` for CSS Modules (when `experiments.css: true` is enabled), which allows CSS to be injected into the DOM as a `<style>` (`HTMLStyleElement`) directly from the webpack runtime. This covers the typical use case of `style-loader`, so it is no longer necessary to use `style-loader` to inject styles when using this mode.
76+
77+
Additionally, the CSS Module exports are preserved (for example, the class name mapping in `*.module.css`).
78+
79+
For CSP compatibility, when a nonce has been configured in the webpack runtime (`__webpack_require__.nc`), the `<style>` injected by this mode receives the same nonce via the `nonce` attribute (webpack reuses the nonce provided by the application; it does not generate one automatically).
80+
81+
```js
82+
module.exports = {
83+
experiments: { css: true },
84+
module: {
85+
rules: [
86+
{
87+
test: /\.css$/,
88+
type: "css/module",
89+
parser: {
90+
exportType: "style",
91+
},
92+
},
93+
],
94+
},
95+
};
96+
```
97+
98+
W> CSS support has matured significantly and is expected to be fully finalized in the next minor release, as planned in the roadmap. As part of this transition, `css-loader`, `style-loader`, and `mini-css-extract-plugin` are planned for deprecation.
99+
100+
## Better Tree Shaking for CommonJS Destructuring
101+
102+
Webpack can now statically analyze **destructuring assignments directly from CommonJS `require`** (and `module.require`) and treat only the destructured properties as "referenced exports", instead of conservatively assuming the whole `exports` object is used. This improves dead-code elimination in optimized builds and can reduce bundle size in codebases that still consume CommonJS modules.
103+
104+
Consider a module that exports multiple functions, and a consumer that only destructures one of them:
105+
106+
```js
107+
// math.js
108+
exports.add = (a, b) => a + b;
109+
exports.divide = (a, b) => a / b;
110+
exports.multiply = (a, b) => a * b;
111+
exports.subtract = (a, b) => a - b;
112+
```
113+
114+
```js
115+
// app.js
116+
const { add } = require("./math");
117+
118+
console.log(add(2, 3));
119+
```
120+
121+
In previous versions, webpack treated `require("./math")` as referencing the entire exports object. All four functions were included in the bundle even though only `add` is used:
122+
123+
```js
124+
// Bundled output (5.105 — simplified)
125+
const math = {
126+
add: (a, b) => a + b,
127+
subtract: (a, b) => a - b,
128+
multiply: (a, b) => a * b,
129+
divide: (a, b) => a / b,
130+
};
131+
```
132+
133+
Starting with 5.106, webpack recognizes the destructuring pattern and marks only `add` as referenced. The unused exports are eliminated during optimization:
134+
135+
```js
136+
// Bundled output (5.106 — simplified)
137+
const math_add = (a, b) => a + b;
138+
// subtract, multiply, divide - tree-shaken away
139+
```
140+
141+
This also works with `module.require`:
142+
143+
```js
144+
const { a, b } = module.require("./module");
145+
```
146+
147+
## Source Phase Imports for WebAssembly (Experimental)
148+
149+
Webpack now includes experimental support for TC39 [Source Phase Imports](https://github.com/tc39/proposal-source-phase-imports) when importing WebAssembly modules.
150+
151+
The proposal is currently at **Stage 3** and introduces a way to import a module at the _source phase_ instead of immediately evaluating it. In practical terms for WebAssembly, this means you can obtain a compiled `WebAssembly.Module` first, and instantiate it later with your own imports.
152+
153+
In webpack 5.106, this experimental support is focused on WebAssembly source imports under `experiments.sourceImport`. In the next minor release, the focus is expected to shift toward JavaScript support.
154+
155+
Enable the feature with `experiments.sourceImport`:
156+
157+
```js
158+
module.exports = {
159+
experiments: {
160+
asyncWebAssembly: true,
161+
sourceImport: true,
162+
},
163+
};
164+
```
165+
166+
Then use either static or dynamic source-phase syntax:
167+
168+
```text
169+
// Static form
170+
import source wasmModule from "./module.wasm";
171+
172+
// Dynamic form
173+
const wasmModule2 = await import.source("./module.wasm");
174+
175+
const instance = await WebAssembly.instantiate(wasmModule);
176+
```
177+
178+
You can also see an end-to-end example in webpack's repository:
179+
[https://github.com/webpack/webpack/tree/main/examples/wasm-simple-source-phase](https://github.com/webpack/webpack/tree/main/examples/wasm-simple-source-phase)
180+
181+
## Getting Started with `create-webpack-app`
182+
183+
[`create-webpack-app`](https://www.npmjs.com/package/create-webpack-app) is now the recommended way to scaffold a new webpack project. Previously, this functionality lived inside `webpack-cli` as the `webpack init` command, but it has been extracted into its own standalone package with the release of webpack-cli 7.
184+
185+
This means you can now create a new webpack project with a single command, without needing to install `webpack-cli` first:
186+
187+
```bash
188+
npx create-webpack-app
189+
```
190+
191+
The CLI walks you through an interactive setup where you choose the pieces that fit your project:
192+
193+
```bash
194+
$ npx create-webpack-app
195+
196+
? Which of the following JS solutions do you want to use? Typescript
197+
? Do you want to use webpack-dev-server? Yes
198+
? Do you want to simplify the creation of HTML files for your bundle? Yes
199+
? Do you want to add PWA support? No
200+
? Which of the following CSS solutions do you want to use? CSS only
201+
? Will you be using PostCSS in your project? Yes
202+
? Do you want to extract CSS for every file? Only for Production
203+
? Which package manager do you want to use? npm
204+
205+
[create-webpack] ℹ️ Initializing a new Webpack project...
206+
[create-webpack] ✅ Project dependencies installed successfully!
207+
```
208+
209+
The generated project includes a working `webpack.config.js`, dev server configuration, and the loader/plugin setup for the options you selected. From there, you can start developing immediately:
210+
211+
```bash
212+
cd my-project
213+
npm start
214+
```
215+
216+
This approach follows the same pattern popularized by tools like `create-react-app` and `create-vite`: a single `npx` command that gets you from zero to a working project without manual configuration.
217+
218+
You can also use the `init` subcommand if you prefer the explicit form:
219+
220+
```bash
221+
npx create-webpack-app init
222+
```
223+
224+
Beyond project scaffolding, `create-webpack-app` can also generate the boilerplate for custom loaders and plugins:
225+
226+
```bash
227+
npx create-webpack-app loader
228+
229+
npx create-webpack-app plugin
230+
```
231+
232+
## Context Support for VirtualUrlPlugin
233+
234+
`VirtualUrlPlugin` (via `webpack.experiments.schemes.VirtualUrlPlugin`) now supports a `context` option that defines the **base directory used to resolve relative imports inside virtual modules**. This feature is currently **experimental**, as it is part of the `experiments.schemes` API.
235+
236+
This makes virtual modules behave more like real files: code such as `import "./utils"` resolves consistently instead of falling back to `compiler.context` and potentially resolving incorrectly.
237+
238+
`context` can be set per virtual module (inside the module definition) or as a plugin level default. It defaults to `"auto"`, which tries to infer the context from the virtual module id or path; otherwise it falls back to `compiler.context`. Conceptually, when you set `context` for a module, webpack treats that virtual module _as if it lived inside that directory_ for resolving relative paths.
239+
240+
For example, if you define a virtual module id `virtual/table.js` with `context: path.join(__dirname, "src/components")`, then its internal `import "./utils"` is resolved as if the file were `src/components/table.js` importing `src/components/utils.js`.
241+
242+
```js
243+
const path = require("node:path");
244+
const webpack = require("webpack");
245+
246+
module.exports = {
247+
plugins: [
248+
new webpack.experiments.schemes.VirtualUrlPlugin(
249+
{
250+
"src/components/button.js": {
251+
context: "auto",
252+
source() {
253+
return "import { trim } from './utils'; export const button = trim('button ');";
254+
},
255+
},
256+
"virtual/table.js": {
257+
context: path.join(__dirname, "src/components"),
258+
source() {
259+
return "import { trim } from './utils'; export const table = trim('table ');";
260+
},
261+
},
262+
},
263+
{ context: "auto" },
264+
),
265+
],
266+
};
267+
```
268+
269+
## Experimental JavaScript Parsing with `oxc-parser`
270+
271+
Webpack now includes an example demonstrating how to replace the default JavaScript parser with **`oxc-parser`**. This integration should be considered **purely experimental** and is **not recommended for production use**.
272+
273+
Instead, it is intended for **development environments** or **benchmark branches**, allowing the community to experiment with alternative parsing strategies in real projects. This helps evaluate potential improvements in **parse time and build performance**, as well as identify possible **compatibility issues**.
274+
275+
**Example**
276+
277+
The following configuration limits the custom parser to `.js` files:
278+
279+
```js
280+
"use strict";
281+
282+
const oxcParse = require("./internals/oxc-parse");
283+
284+
/** @type {import("webpack").Configuration} */
285+
module.exports = {
286+
mode: "production",
287+
entry: "./src/index.js",
288+
module: {
289+
rules: [
290+
{
291+
// Apply the custom parser only to JavaScript files
292+
test: /\.js$/,
293+
parser: {
294+
parse: oxcParse,
295+
},
296+
},
297+
],
298+
},
299+
};
300+
```
301+
302+
You can find the full example in the webpack repository:
303+
[https://github.com/webpack/webpack/blob/main/examples/custom-javascript-parser/webpack.config.js](https://github.com/webpack/webpack/blob/main/examples/custom-javascript-parser/webpack.config.js)
304+
305+
## Ecosystem Updates
306+
307+
- **Webpack-cli** has released a new major version, [7.0.0](https://github.com/webpack/webpack-cli/releases/tag/webpack-cli%407.0.0). The minimum supported Node.js version is now `20.9.0`, and configuration files are loaded via dynamic `import()` by default, which enables native TypeScript configuration support through Node.js type stripping without needing external loaders.
308+
The `--node-env` argument has been replaced by `--config-node-env`, and the deprecated programmatic API has been removed. Additionally, configuration freezing is now allowed, graceful shutdown has been improved when file system cache is enabled, and general performance improvements have been made. Check the [release for more information](https://github.com/webpack/webpack-cli/releases/tag/webpack-cli%407.0.0).
309+
- **Webpack-dev-middleware** has released a new major version, [8.0.0](https://github.com/webpack/webpack-dev-middleware/releases/tag/v8.0.0). The minimum supported Node.js version is now `20.9.0` and the minimum webpack version is `5.101.0`. The `getFilenameFromUrl` function is now asynchronous, immutable asset caching (`cacheImmutable`) is enabled by default, and a new `forwardError` option allows forwarding errors to the next middleware.
310+
Support for plugin usage has also been added, and general performance improvements have been made. Check the [release for more information](https://github.com/webpack/webpack-dev-middleware/releases/tag/v8.0.0).
311+
- **Compression-webpack-plugin**, **html-minimizer-webpack-plugin**, **css-minimizer-webpack-plugin**, **image-minimizer-webpack-plugin**, and other plugins have released new major versions to align their minimum supported Node.js version to `20.9.0`, keeping consistency across the webpack ecosystem alongside the recent major releases of webpack-cli 7 and webpack-dev-middleware 8.
312+
313+
## Bug Fixes
314+
315+
Several bug fixes have been resolved since version [5.105](https://github.com/webpack/webpack/releases/tag/v5.105.0). Check the [changelog](https://github.com/webpack/webpack/blob/main/CHANGELOG.md) for all the details.
316+
317+
## Thanks
318+
319+
A big thank you to all our contributors and [sponsors](https://github.com/webpack/webpack?tab=readme-ov-file#sponsoring)
320+
who made Webpack 5.106 possible. Your support, whether through code contributions, documentation, or financial sponsorship, helps keep Webpack evolving and improving for everyone.

0 commit comments

Comments
 (0)