Skip to content

Commit 58a44f4

Browse files
committed
feat: 4.19.0-beta.0
1 parent a7ad609 commit 58a44f4

150 files changed

Lines changed: 2078 additions & 261 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

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

3+
## 4.19.0-beta.0
4+
5+
### BREAKING CHANGES by inlining SVG only
6+
7+
- Inline `<img src="icon.svg">`:
8+
- OLD: replaces `<img>` with `<svg>` tag
9+
- NEW: inlines SVG as escaped data URL
10+
- Encoding of data URL:
11+
- OLD: defaults, escaped URL (`#%` chars only), e.g. `data:image/svg+xml,<svg>...</svg>`
12+
- NEW: defaults, base64 encoded, e.g. `data:image/svg+xml;base64,iVBO` or full escaped URL, e.g. `data:image/svg+xml,%3Csvg%20` regards `generator.dataUrl.encoding` option
13+
14+
## 4.18.2 release (2025-02-20)
15+
16+
- fix: the output SVG should contain the changes made in generator.dataUrl()
17+
- docs: add information about preload priority to readme
18+
319
## 4.18.0 release (2025-02-03)
420

521
- chore: bump the version for release

README.md

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2705,9 +2705,11 @@ The descriptions of the properties:
27052705
- `sound.oga` as `audio/ogg`
27062706
- `sound.weba` as `audio/webm`
27072707
- etc.
2708-
- `attributes` - an object with additional custom attributes like `crossorigin` `media` etc.,\
2709-
e.g. `attributes: { crossorigin: true }`, `attributes: { media: '(max-width: 900px)' }`.\
2710-
Defaults `{}`.
2708+
- `attributes` - an object with additional custom attributes like `crossorigin` `media` etc. Defaults `{}`.\
2709+
For example:
2710+
- `attributes: { crossorigin: true }`
2711+
- `attributes: { media: '(max-width: 900px)' }`
2712+
- `attributes: { fetchpriority: 'high' }`
27112713
27122714
> [!NOTE]
27132715
>
@@ -3009,6 +3011,39 @@ The generated HTML contains the preload tags exactly in the order of `preload` o
30093011
</html>
30103012
```
30113013
3014+
#### Preload priority
3015+
3016+
The `fetchpriority` attribute helps optimize resource loading by prioritizing critical assets and deferring less important ones.
3017+
3018+
**Available values:**
3019+
3020+
- `auto` (default) – The browser determines the priority automatically.
3021+
- `high` – The resource is fetched with high priority.
3022+
- `low` – The resource is fetched with lower priority.
3023+
3024+
Using `fetchpriority` is especially beneficial for improving **Core Web Vitals**,
3025+
particularly **Largest Contentful Paint (LCP)**, by ensuring essential resources load as quickly as possible.
3026+
3027+
**Example:** Preloading an LCP image with high priority
3028+
3029+
```js
3030+
preload: [
3031+
{
3032+
test: /lcp-image\.webp/i,
3033+
attributes: {
3034+
as: 'image',
3035+
fetchpriority: 'high',
3036+
},
3037+
},
3038+
],
3039+
```
3040+
3041+
**More info:**
3042+
3043+
- [Fetch priority](https://web.dev/articles/fetch-priority)
3044+
- [Optimize Largest Contentful Paint](https://web.dev/articles/optimize-lcp)
3045+
3046+
30123047
#### [↑ back to contents](#contents)
30133048
30143049
<a id="option-minify" name="option-minify"></a>

README.npm.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<div align="center">
2+
<img height="200" src="images/plugin-logo.png">
3+
<h1 align="center">
4+
<a href="https://github.com/webdiscus/html-bundler-webpack-plugin">HTML Bundler Plugin for Webpack</a><br>
5+
<sub>All-in-one Web Bundler</sub><br>
6+
</h1>
7+
</div>
8+
9+
[![npm](https://img.shields.io/npm/v/html-bundler-webpack-plugin?logo=npm&color=brightgreen 'npm package')](https://www.npmjs.com/package/html-bundler-webpack-plugin 'download npm package')
10+
[![node](https://img.shields.io/node/v/html-bundler-webpack-plugin)](https://nodejs.org)
11+
[![node](https://img.shields.io/github/package-json/dependency-version/webdiscus/html-bundler-webpack-plugin/peer/webpack)](https://webpack.js.org)
12+
[![Test](https://github.com/webdiscus/html-bundler-webpack-plugin/actions/workflows/test.yml/badge.svg)](https://github.com/webdiscus/html-bundler-webpack-plugin/actions/workflows/test.yml)
13+
[![codecov](https://codecov.io/gh/webdiscus/html-bundler-webpack-plugin/branch/master/graph/badge.svg?token=Q6YMEN536M)](https://codecov.io/gh/webdiscus/html-bundler-webpack-plugin)
14+
[![node](https://img.shields.io/npm/dm/html-bundler-webpack-plugin)](https://www.npmjs.com/package/html-bundler-webpack-plugin)
15+
16+
> This plugin is all you need to generate a complete single- or multi-page website from your source assets.
17+
18+
The plugin automates the processing of source files such as JS/TS, SCSS, images and other assets referenced in an HTML or template file.
19+
This plugin will generate an HTML file containing all the necessary links to JS, CSS, images and other resources.
20+
21+
## Why use the HTML Bundler Plugin?
22+
23+
This plugin is a powerful alternative to [html-webpack-plugin](https://github.com/jantimon/html-webpack-plugin) and a replacement for many [plugins and loaders](#list-of-plugins).
24+
25+
The HTML Bundler Plugin works a bit differently than `html-webpack-plugin`.
26+
It doesn't just inject JavaScript and CSS into an HTML.
27+
Instead, it resolves all the source files of the assets referenced directly in the template
28+
and ensures the generated HTML contains the correct output URLs of resources after Webpack processes them.
29+
Additionally, CSS extracted from styles imported in JS can be injected into HTML as a `<link>` tag or as an inlined CSS.
30+
31+
---
32+
33+
<h3 align="center">
34+
📋 <a href="https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#contents">Table of Contents</a> 🚀<a href="https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#install">Install and Quick Start</a> 🖼 <a href="https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#usage-examples">Usage examples</a>
35+
</h3>
36+
37+
---
38+
39+
## 💡 Highlights
40+
41+
- An [entry point](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#option-entry) is any HTML template. **Start from HTML**, not from JS.
42+
- **Automatically** processes templates found in the [entry directory](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#option-entry-path).
43+
- Build-in support for [template engines](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#template-engine): [Eta](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#using-template-eta), [EJS](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#using-template-ejs), [Handlebars](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#using-template-handlebars), [Nunjucks](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#using-template-nunjucks), [Pug](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#using-template-pug), [Tempura](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#using-template-tempura), [TwigJS](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#using-template-twig), [LiquidJS](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#using-template-liquidjs).
44+
- Build-in support for **Markdown** `*.md` files in templates, see [Markdown demo](https://stackblitz.com/edit/markdown-to-html-webpack?file=webpack.config.js) in browser.
45+
- **Source files** of [`script`](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#option-js) and [`style`](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#option-css) can be specified directly in HTML:
46+
- `<link href="./style.scss" rel="stylesheet">`\
47+
No longer need to define source style files in Webpack entry or import styles in JavaScript.
48+
- `<script src="./app.ts" defer="defer"></script>`\
49+
No longer need to define source JavaScript files in Webpack entry.
50+
- **Resolves** [source files](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#loader-option-sources) of assets in [attributes](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#loader-option-sources-default) such as `href` `src` `srcset` using **relative path** or **alias**:
51+
- `<link href="../images/favicon.svg" type="image/svg" rel=icon />`
52+
- `<img src="@images/pic.png" srcset="@images/pic400.png 1x, @images/pic800.png 2x" />`\
53+
Source files will be resolved, processed and auto-replaced with correct URLs in the generated HTML.
54+
- **Resolves** [route URLs](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#option-router) in `a.href`, useful for navigation in multi-pages.
55+
- **Inlines** [JS](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#recipe-inline-js), [CSS](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#recipe-inline-css) and [Images](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#recipe-inline-image) into HTML. See [how to inline all resources](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#recipe-inline-all-assets-to-html) into single HTML file.
56+
- Supports the [HMR for CSS](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#option-css-hot) to update CSS in browser without a full reload.
57+
- Watches for changes in the [data file](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#option-entry-data) linked to the template in the plugin option.
58+
- Generates the [preload](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#option-preload) tags for fonts, images, video, scripts, styles.
59+
- Generates the [integrity](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#option-integrity) attribute in the `link` and `script` tags.
60+
- Generates the [favicons](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#favicons-bundler-plugin) of different sizes for various platforms.
61+
- You can create custom plugins using the provided [Plugin Hooks](https://github.com/webdiscus/html-bundler-webpack-plugin/blob/master/README.md#plugin-hooks-and-callbacks).
62+
- Over 700 [tests](https://github.com/webdiscus/html-bundler-webpack-plugin/tree/master/test) for various use cases.
63+
64+
---
65+
66+
📖 See [full documentation on GitHub](https://github.com/webdiscus/html-bundler-webpack-plugin).

package-lock.json

Lines changed: 18 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "html-bundler-webpack-plugin",
3-
"version": "4.18.0",
3+
"version": "4.19.0-beta.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",
@@ -62,6 +62,10 @@
6262
"test:unitQueryParser": "jest --detectOpenHandles --collectCoverage --config ./test/jest.config.js --runTestsByPath ./test/unit.queryParser.test.js",
6363
"test:verbose": "jest --detectOpenHandles --config ./test/jest.config.js --runTestsByPath ./test/verbose.test.js",
6464
"test:verbose-update": "jest --detectOpenHandles --updateSnapshot --config ./test/jest.config.js --runTestsByPath ./test/verbose.test.js",
65+
"use:npmReadme": "mv 'README.md' 'README.git.md' && mv 'README.npm.md' 'README.md'",
66+
"use:gitReadme": "mv 'README.md' 'README.npm.md' && mv 'README.git.md' 'README.md'",
67+
"prepublishOnly": "run-s use:npmReadme",
68+
"postpublish": "npm run use:gitReadme",
6569
"publish:public": "npm publish --access public",
6670
"publish:beta": "npm publish --tag beta"
6771
},
@@ -146,7 +150,7 @@
146150
},
147151
"dependencies": {
148152
"@types/html-minifier-terser": "^7.0.2",
149-
"ansis": "3.9.0",
153+
"ansis": "3.16.0",
150154
"enhanced-resolve": ">=5.7.0",
151155
"eta": "^3.5.0",
152156
"html-minifier-terser": "^7.2.0"
@@ -181,6 +185,7 @@
181185
"jest": "^29.7.0",
182186
"liquidjs": "^10.18.0",
183187
"markdown-it": "^14.1.0",
188+
"mini-svg-data-uri": "^1.4.4",
184189
"mustache": "^4.2.0",
185190
"normalize.css": "^8.0.1",
186191
"nunjucks": "^3.2.4",

src/Common/Helpers.js

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,21 @@ const getFileExtension = (resource, win = isWin) => {
7373
};
7474

7575
/**
76-
* Get the query parameter the request.
76+
* Whether the request contains the query parameter.
77+
*
78+
* @param {string} request
79+
* @param {string} name
80+
* @return {boolean}
81+
*/
82+
const hasQueryParam = (request, name) => {
83+
const [, query] = request.split('?', 2);
84+
const urlParams = new URLSearchParams(query);
85+
86+
return urlParams.get(name) != null;
87+
};
88+
89+
/**
90+
* Get the query parameter from the request.
7791
*
7892
* @param {string} request
7993
* @param {string} name
@@ -86,6 +100,19 @@ const getQueryParam = (request, name) => {
86100
return urlParams.get(name);
87101
};
88102

103+
/**
104+
* Get all query parameters from the request.
105+
*
106+
* @param {string} request
107+
* @return {URLSearchParams|null}
108+
*/
109+
const getQueryParams = (request) => {
110+
const queryString = request.split('?')[1];
111+
if (!queryString) return null;
112+
113+
return new URLSearchParams(queryString);
114+
};
115+
89116
/**
90117
* Add to the request a query parameter.
91118
*
@@ -164,10 +191,23 @@ const getFixedUrlWithParams = (request) => {
164191
const deepMerge = (a, b) => {
165192
const result = {};
166193
for (const key of new Set([...Object.keys(a), ...Object.keys(b)])) {
167-
result[key] =
168-
a[key]?.constructor === Object && b[key]?.constructor === Object
169-
? deepMerge(a[key], b[key])
170-
: structuredClone(b[key] !== undefined ? b[key] : a[key]);
194+
const aValue = a[key];
195+
const bValue = b[key];
196+
197+
if (aValue?.constructor === Object && bValue?.constructor === Object) {
198+
result[key] = deepMerge(aValue, bValue);
199+
} else if (typeof bValue === 'function') {
200+
// keep functions as-is
201+
result[key] = bValue;
202+
} else {
203+
try {
204+
result[key] = structuredClone(bValue !== undefined ? bValue : aValue);
205+
} catch (err) {
206+
console.warn(`Skipping cloning for key "${key}" due to:`, err);
207+
// use original reference
208+
result[key] = bValue !== undefined ? bValue : aValue;
209+
}
210+
}
171211
}
172212
return result;
173213
};
@@ -273,7 +313,9 @@ module.exports = {
273313
pathToPosix,
274314
getFileExtension,
275315
parseQuery: (request) => parseRequest(request).query,
316+
hasQueryParam,
276317
getQueryParam,
318+
getQueryParams,
277319
addQueryParam,
278320
splitUrl,
279321
deleteQueryParam,

src/Loader/Modes/PreprocessorModeAbstract.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ class PreprocessorModeAbstract {
3333
const preprocessor = loaderOption.getPreprocessorModule();
3434
const { esModule } = loaderOption.get();
3535

36-
//console.log('collection: ', collection);
37-
3836
this.exportCode = esModule ? 'export default ' : 'module.exports=';
3937
this.preprocessor = preprocessor || {};
4038
this.loaderOption = loaderOption;

0 commit comments

Comments
 (0)