You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(experiments): document experiments.html and its HTML behaviors
Webpack 5.107 introduces experiments.html, the html-loader side of
native HTML module support. With the flag on, importing an HTML file
from JavaScript runs its tag references through the webpack pipeline.
What this PR documents:
- The experiments.html flag and its TOC entry.
- The JS-import-HTML usage pattern (no entry-point support yet).
- Inline <style> tags routed through the CSS pipeline as virtual
exportType: "text" modules, so url() and @import resolve relative to
the HTML file.
- Inline <script> tags routed through the same entry pipeline as
<script src>: classic bodies bundle as CommonJS, type="module"
bodies as ESM, tags rewritten to <script src="...">, auto-upgrade to
type="module" under output.module.
- <script src> and <link rel="modulepreload"> references becoming real
webpack entries with shared runtime via dependOn, independent
modulepreload chunks, and type="module" auto-upgrade.
- webpackIgnore magic comment for HTML (cross-references the existing
magic comments docs in api/module-methods).
What is explicitly NOT supported in 5.107 (called out in the warning
admonition): HTML entry points (the html-webpack-plugin part). That is
planned for the next minor release. The full story is tracked in
issue #536.
Refs:
- webpack/webpack#20902 (experiments.html flag)
- webpack/webpack#20962 (inline <style>)
- webpack/webpack#20967 (inline <script>)
- webpack/webpack#20949 (<script src> / modulepreload)
- webpack/webpack#20950 (webpackIgnore in HTML)
Copy file name to clipboardExpand all lines: src/content/configuration/experiments.mdx
+113Lines changed: 113 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -27,6 +27,7 @@ Available options:
27
27
-[`css`](#experimentscss)
28
28
-[`deferImport`](#experimentsdeferimport)
29
29
-[`futureDefaults`](#experimentsfuturedefaults)
30
+
-[`html`](#experimentshtml)
30
31
-[`lazyCompilation`](#experimentslazycompilation)
31
32
-[`outputModule`](#experimentsoutputmodule)
32
33
-`syncWebAssembly`: Support the old WebAssembly like in webpack 4.
@@ -310,6 +311,118 @@ export default {
310
311
};
311
312
```
312
313
314
+
### experiments.html
315
+
316
+
<Badgetext="5.107.0+" />
317
+
318
+
Enable native HTML module support. Importing a `.html` file from JavaScript runs its tag references through the normal webpack pipeline, replacing the role `html-loader` has played for years. The flag registers the `html` module type on `NormalModuleFactory` and unlocks the HTML behaviors described below.
319
+
320
+
- Type: `boolean`
321
+
- Default: `false`
322
+
323
+
**webpack.config.js**
324
+
325
+
```js
326
+
exportdefault {
327
+
// ...
328
+
experiments: {
329
+
html:true,
330
+
},
331
+
};
332
+
```
333
+
334
+
Then import the HTML file from JavaScript. The default export is the processed HTML as a string, with all asset references resolved through webpack:
335
+
336
+
```js
337
+
// src/index.js
338
+
importpagefrom"./page.html";
339
+
340
+
document.documentElement.innerHTML= page;
341
+
```
342
+
343
+
W> **This feature is experimental and partial.** Webpack 5.107 only implements the `html-loader` side: importing an HTML file from JS runs its tag references through the webpack pipeline. **HTML entry points** (using a `.html` file directly as `entry`, the `html-webpack-plugin` part) are **not supported yet** and are planned for the next minor release. The full story is tracked in issue [#536](https://github.com/webpack/webpack/issues/536).
344
+
345
+
#### Inline `<style>` tags
346
+
347
+
Inline `<style>` blocks inside an HTML module are routed through webpack's CSS pipeline as virtual CSS modules with `exportType: "text"`. `url()` and `@import` references are resolved relative to the HTML file, and the processed CSS text is written back into the original `<style>` tag in the emitted HTML string.
348
+
349
+
```html
350
+
<!-- src/page.html -->
351
+
<!doctype html>
352
+
<html>
353
+
<head>
354
+
<style>
355
+
@import"./reset.css";
356
+
357
+
body {
358
+
background: url("./bg.png");
359
+
}
360
+
</style>
361
+
</head>
362
+
<body>
363
+
...
364
+
</body>
365
+
</html>
366
+
```
367
+
368
+
`<style type="text/css">` and `<style>` with no `type` attribute are processed. Anything with a non-CSS `type` is passed through unchanged.
369
+
370
+
#### Inline `<script>` tags
371
+
372
+
Inline `<script>` bodies are routed through the same entry pipeline used for [`<script src>`](#script-src-and-link-relmodulepreload). Each `<script>` body becomes its own webpack entry: classic inline scripts are bundled as CommonJS, and `<script type="module">` bodies are bundled as ESM. The tag in the emitted HTML is rewritten to `<script src="…">` pointing at the generated chunk, with the body cleared.
373
+
374
+
```html
375
+
<!-- src/page.html -->
376
+
<!doctype html>
377
+
<html>
378
+
<body>
379
+
<scripttype="module">
380
+
import { greet } from"./lib.js";
381
+
greet("world");
382
+
</script>
383
+
384
+
<script>
385
+
console.log("classic inline script");
386
+
</script>
387
+
</body>
388
+
</html>
389
+
```
390
+
391
+
The same behaviors that apply to external `<script src>` apply here too:
392
+
393
+
- When [`output.module`](/configuration/output/#outputmodule) is enabled, classic inline `<script>` tags are auto-upgraded to `type="module"`, matching the auto-upgrade for `<script src>`.
394
+
-`webpackIgnore` works on inline `<script>` tags as well, leaving the original body untouched.
395
+
- Non-JS `type` values such as `application/ld+json` and `importmap` pass through unchanged.
396
+
397
+
#### `<script src>` and `<link rel="modulepreload">`
398
+
399
+
`<script src>` and `<link rel="modulepreload">` references inside an HTML module become real webpack entries. The emitted chunk URL is rewritten back into the HTML string, so hashed filenames work the same way they do for JavaScript imports.
400
+
401
+
```html
402
+
<!-- src/page.html -->
403
+
<!doctype html>
404
+
<html>
405
+
<head>
406
+
<linkrel="modulepreload"href="./preloaded.js" />
407
+
</head>
408
+
<body>
409
+
<scriptsrc="./entry.js"></script>
410
+
<scriptsrc="./second.js"></script>
411
+
</body>
412
+
</html>
413
+
```
414
+
415
+
A few behaviors to keep in mind:
416
+
417
+
- Multiple `<script src>` tags on the same page share a single runtime. Within each group (classic or `type="module"`), the leader holds the runtime and the rest declare `dependOn` on it.
418
+
-`<link rel="modulepreload">` entries stay independent and are never imported by sibling scripts, preserving "preload without execute" semantics.
419
+
- When [`output.module`](/configuration/output/#outputmodule) is enabled, classic `<script src>` tags are auto-upgraded to `<script type="module" src>` so the emitted ES-module chunks load in the correct mode.
420
+
- Non-JS script types (`application/ld+json`, `importmap`, …) and data URIs flow through unchanged and are not bundled as JS.
421
+
422
+
#### `webpackIgnore` magic comment
423
+
424
+
Placing an HTML `<!-- webpackIgnore: true -->` comment immediately before a tag tells webpack to skip URL resolution for that tag's `src`, `href`, `srcset`, and similar attributes. See the full description under [magic comments](/api/module-methods/#webpackignore).
425
+
313
426
### experiments.lazyCompilation
314
427
315
428
Compile entrypoints and dynamic `import`s only when they are in use. It can be used for either Web or Node.js.
0 commit comments