Skip to content

Commit c0e30a8

Browse files
committed
feat: add support for preloading of dynamic imported modules, #138
1 parent fef1fa4 commit c0e30a8

34 files changed

Lines changed: 228 additions & 33 deletions

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 4.13.0 (2025-01-18)
4+
5+
- feat: add support for preloading of dynamic imported modules, #138
6+
37
## 4.12.3 (2025-01-18)
48

59
- fix: output URL for preloaded resources if publicPath is a URL or root path, #141

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "html-bundler-webpack-plugin",
3-
"version": "4.12.3",
3+
"version": "4.13.0",
44
"description": "Generates complete single-page or multi-page website from source assets. Build-in support for Markdown, Eta, EJS, Handlebars, Nunjucks, Pug. Alternative to html-webpack-plugin.",
55
"keywords": [
66
"html",

src/Plugin/Collection.js

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ const Preload = require('./Preload');
77
const { noHeadException } = require('./Messages/Exception');
88

99
/** @typedef {import('webpack').Compilation} Compilation */
10+
/** @typedef {import("webpack/lib/Entrypoint")} Entrypoint */
11+
/** @typedef {import("webpack/lib/ChunkGroup")} ChunkGroup */
1012

1113
/**
1214
* @typedef {Object} CollectionData
@@ -288,11 +290,13 @@ class Collection {
288290
for (let [resource, { type, name, entries }] of this.assets) {
289291
if (type !== Collection.type.script) continue;
290292

293+
/** @type {Entrypoint} entrypoint */
291294
const entrypoint = namedChunkGroups.get(name);
292295

293296
// prevent error when in watch mode after removing a script in the template
294297
if (!entrypoint) continue;
295298

299+
const childrenFiles = this.#getChildrenFiles(entrypoint);
296300
const chunkFiles = new Set();
297301

298302
for (const { id, files, auxiliaryFiles } of entrypoint.chunks) {
@@ -310,7 +314,7 @@ class Collection {
310314
splitChunkIds.add(id);
311315
}
312316

313-
const hasSplitChunks = chunkFiles.size > 1;
317+
const hasChunks = chunkFiles.size > 1;
314318

315319
// do flat the Map<string, Set>
316320
const entryFilenames = new Set();
@@ -322,16 +326,17 @@ class Collection {
322326
// let's show an original error
323327
if (!assets.hasOwnProperty(entryFile)) continue;
324328

325-
const data = { type, resource, chunks: [] };
329+
const data = { type, resource, chunks: [], children: [] };
326330
let injectedChunks;
327331

328-
if (hasSplitChunks) {
332+
if (hasChunks) {
329333
if (!chunkCache.has(entryFile)) chunkCache.set(entryFile, new Set());
330334
injectedChunks = chunkCache.get(entryFile);
331335
}
332336

337+
// split chunks
333338
for (let chunkFile of chunkFiles) {
334-
if (hasSplitChunks) {
339+
if (hasChunks) {
335340
if (injectedChunks.has(chunkFile)) continue;
336341
injectedChunks.add(chunkFile);
337342
}
@@ -343,6 +348,20 @@ class Collection {
343348
data.chunks.push({ inline, chunkFile, assetFile });
344349
}
345350

351+
// dynamic imported chunks
352+
for (let chunkFile of childrenFiles) {
353+
if (hasChunks) {
354+
if (injectedChunks.has(chunkFile)) continue;
355+
injectedChunks.add(chunkFile);
356+
}
357+
358+
const assetFile = this.pluginOption.getAssetOutputFile(chunkFile, entryFile);
359+
const inline = this.pluginOption.isInlineJs(resource, chunkFile);
360+
361+
splitChunkFiles.add(chunkFile);
362+
data.children.push({ inline, chunkFile, assetFile });
363+
}
364+
346365
const entryData = this.data.get(entryFile);
347366

348367
if (entryData) {
@@ -369,6 +388,24 @@ class Collection {
369388
}
370389
}
371390

391+
/**
392+
* @param {Entrypoint} entrypoint
393+
* @return {Array<string>}
394+
*/
395+
#getChildrenFiles(entrypoint) {
396+
let files = [];
397+
const children = entrypoint.getChildren();
398+
399+
for (const chunkGroup of children) {
400+
let chunkFiles = chunkGroup.getFiles();
401+
if (chunkFiles) {
402+
files.push(...chunkFiles);
403+
}
404+
}
405+
406+
return files;
407+
}
408+
372409
/**
373410
* Whether the output filename is a template entrypoint.
374411
*

src/Plugin/Messages/Info.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,10 @@ const renderAssets = (item, pad = padLevel2) => {
6969
}
7070

7171
if (type === Collection.type.script) {
72-
const isSingleChunk = item.chunks.length === 1;
72+
const chunks = item.chunks || [];
73+
const children = item.children || [];
74+
const files = [...chunks, ...children];
75+
const isSingleChunk = files.length === 1;
7376
let li;
7477
let padLen;
7578

@@ -80,7 +83,7 @@ const renderAssets = (item, pad = padLevel2) => {
8083
str += `${'->'.padStart(padLevel1)} ${fg(120)`chunks:`}` + '\n';
8184
}
8285

83-
for (let { inline, chunkFile, assetFile } of item.chunks) {
86+
for (let { inline, chunkFile, assetFile } of files) {
8487
li = isSingleChunk ? '->' : '';
8588
if (inline) {
8689
str += `${li.padStart(padLen)} ${gray(path.basename(chunkFile))} ${yellow`(inline)`}\n`;

src/Plugin/Preload.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,13 @@ class Preload {
154154
// css
155155
preloadAssets.set(item.assetFile, conf._opts);
156156
}
157+
158+
// dynamic imported modules
159+
if (Array.isArray(item.children)) {
160+
for (let { chunkFile, assetFile } of item.children) {
161+
preloadAssets.set(assetFile, conf._opts);
162+
}
163+
}
157164
}
158165

159166
// assets in css
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@font-face {
2+
font-family: 'OpenSans';
3+
src: url(../fonts/open-sans-regular.woff2) format('woff2');
4+
font-style: normal;
5+
}
6+
7+
h1 {
8+
color: orangered;
9+
}
Binary file not shown.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Test</title>
5+
<link rel="preload" href="../js/main.8d41dc3e.js" as="script">
6+
<link rel="preload" href="../js/module1.chunk.js" as="script">
7+
<link rel="preload" href="../js/module2.chunk.js" as="script">
8+
<link rel="preload" href="../css/style.0d25913e.css" as="style">
9+
<link rel="preload" href="../fonts/open-sans-regular.woff2" as="font" type="font/woff2" crossorigin>
10+
<link href="../css/style.0d25913e.css" rel="stylesheet">
11+
<script src="../js/main.8d41dc3e.js" defer="defer"></script>
12+
</head>
13+
<body>
14+
<h1>Hello World!</h1>
15+
</body>
16+
</html>

test/cases/option-preload-dynamic-import/expected/js/main.8d41dc3e.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
(self.webpackChunk=self.webpackChunk||[]).push([[364],{972:()=>{console.log(">> module-a")}}]);

0 commit comments

Comments
 (0)