Skip to content

Commit 6332827

Browse files
committed
experimental 4.18.0-beta.1, #147
1 parent 5e9ebdf commit 6332827

185 files changed

Lines changed: 2261 additions & 315 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.

.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Ignore all HTML files in test directory:
22
test/cases/**/*.html
33
test/cases/**/*.hbs
4+
test/cases/**/*.eta
45
*.md

CHANGELOG.md

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
# Changelog
22

3+
## 4.18.0-beta.1 (2025-02-03)
4+
5+
- feat: revert improvement of the `sources[].filter()` function introduced in beta.0, it returns a boolean or void only
6+
- feat: remove the the `sources[].postprocess()` function, introduced in beta.0
7+
- feat: add the experimental `router` plugin option.
8+
9+
## 4.18.0-beta.0 (2025-02-01)
10+
11+
- feat: the loader option `loaderOptions.sources` in now available directly in plugin options.
12+
- feat: auto resolve source path in a.href and replaces it with output filename regards the publicPath
13+
- feat: improve the `sources[].filter()` function, it can now return a string to modify the original value
14+
- feat: add the `sources[].postprocess()` function, called after resolving output filenames\
15+
**NOTE:** `postprocess` works only for `a.href` contained any `*.html` file
16+
- fix: does not resolve an attribute containing a specific link, e.g. `whatsapp://send?abid=1234567890&text=Hello`
17+
318
## 4.17.0 (2025-01-29)
419

520
- feat: pick up the `srcset` and `sizes` attributes for image preload, #149
@@ -61,7 +76,7 @@
6176

6277
## 4.12.1 (2025-01-12)
6378

64-
- fix: incorrect output of preload tag if "crossorigin: true", #139
79+
- fix: incorrect output of preload tag if `crossorigin: true`, #139
6580
- fix: if `as=font` is used in preload and the `crossorigin` is not defined,
6681
it will be added automatically, because the `crossorigin` is mandatory for `font` type
6782

@@ -110,7 +125,7 @@
110125

111126
## 4.10.4 (2024-12-18)
112127

113-
fix: fail rebuild after changed css file if no html entry defined, #132
128+
- fix: fail rebuild after changed css file if no html entry defined, #132
114129

115130
## 4.10.3 (2024-12-13)
116131

@@ -140,7 +155,7 @@ fix: fail rebuild after changed css file if no html entry defined, #132
140155

141156
## 4.9.0 (2024-12-07)
142157

143-
- feat: using serve/watch, after a partial file is modified all entry point templates will be rebuilt, #127.\
158+
- feat: rebuilt all entry point templates by serve/watch, after a partial file is modified, #127.\
144159
**The problem:**
145160
Webpack doesn't know which partials are used in which templates, so Webpack can't rebuild the main template (entrypoint) where a partial has changed.
146161

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ Additionally, CSS extracted from styles imported in JS can be injected into HTML
6464
- Generates the [integrity](#option-integrity) attribute in the `link` and `script` tags.
6565
- Generates the [favicons](#favicons-bundler-plugin) of different sizes for various platforms.
6666
- You can create custom plugins using the provided [Plugin Hooks](#plugin-hooks-and-callbacks).
67-
- Over 600 [tests](https://github.com/webdiscus/html-bundler-webpack-plugin/tree/master/test) for various use cases.
67+
- Over 700 [tests](https://github.com/webdiscus/html-bundler-webpack-plugin/tree/master/test) for various use cases.
6868

6969
See [full list of features](#features).
7070

@@ -3275,7 +3275,7 @@ type Sources =
32753275
parsedValue: Array<string>;
32763276
attributes: { [attributeName: string]: string };
32773277
resourcePath: string;
3278-
}) => boolean | undefined;
3278+
}) => boolean | void;
32793279
}>;
32803280
```
32813281
@@ -3362,7 +3362,7 @@ Examples of using argument properties:
33623362
if (attribute === 'src') return false;
33633363
if (value.endsWith('.webp')) return false;
33643364
if ('srcset' in attributes && attributes['srcset'] === '') return false;
3365-
if (resourcePath.indexOf('example')) return false;
3365+
if (resourcePath.includes('example')) return false;
33663366
// otherwise return 'true' or nothing (undefined) to allow the processing
33673367
},
33683368
}

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.17.0",
3+
"version": "4.18.0-beta.1",
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/Common/Helpers.js

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,23 @@ const pathToPosix = (value) => value.replace(/\\/g, '/');
1919
const isFunction = (value) => typeof value === 'function';
2020

2121
/**
22+
* Whether the request is a URL.
23+
*
24+
* Matches:
25+
* - https://example.com/img.png
26+
* - http://example.com/img.png
27+
* - ftp://example.com/img.png
28+
* - whatsapp://send?abid=1234567890&text=Hello
29+
* - something://example.com/img.png
30+
* - //img.png
31+
*
32+
* But not matches:
33+
* - /img.png
34+
*
2235
* @param {string} request
2336
* @return {boolean}
2437
*/
25-
const isUrl = (request) => {
26-
return (
27-
request.startsWith('//') ||
28-
request.startsWith('https://') ||
29-
request.startsWith('http://') ||
30-
request.startsWith('ftp://')
31-
);
32-
};
38+
const isUrl = (request) => /^(?:[a-z]+:)?\/\//.test(request);
3339

3440
/**
3541
* Find a webpack plugin by instance name.
@@ -97,6 +103,22 @@ const addQueryParam = (request, name, value) => {
97103
return file + '?' + urlParams.toString();
98104
};
99105

106+
/**
107+
* Split an URL to two parts, keeping ? or # in the second part.
108+
*
109+
* @param {string} url
110+
* @return {[string, string]}
111+
*/
112+
const splitUrl = (url) => {
113+
const match = url.match(/[\?#]/);
114+
115+
if (!match) return [url, ''];
116+
117+
const index = match.index;
118+
119+
return [url.slice(0, index), url.slice(index)];
120+
};
121+
100122
/**
101123
* Delete form the request a query parameter.
102124
*
@@ -150,6 +172,22 @@ const deepMerge = (a, b) => {
150172
return result;
151173
};
152174

175+
/**
176+
* Whether at least one regular expression in a giving array matches the value.
177+
*
178+
* @param {string} value
179+
* @param {Array<RegExp>} expressions
180+
* @return {boolean}
181+
*/
182+
const testRegExpArray = (value, expressions) => {
183+
if (value == null) return false;
184+
185+
// if is an URL, get it w/o a query
186+
const [file] = value.split(/[\?#]/, 1);
187+
188+
return expressions.some((regexp) => regexp.test(file));
189+
};
190+
153191
/**
154192
* Returns an indent detected in the content.
155193
*
@@ -237,10 +275,12 @@ module.exports = {
237275
parseQuery: (request) => parseRequest(request).query,
238276
getQueryParam,
239277
addQueryParam,
278+
splitUrl,
240279
deleteQueryParam,
241280
getFixedUrlWithParams,
242281
deepMerge,
243282
detectIndent,
283+
testRegExpArray,
244284
outToConsole,
245285
parseVersion,
246286
compareVersions,

src/Common/HtmlParser.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -173,21 +173,30 @@ class HtmlParser {
173173
const attrValue = attrs[attrName];
174174
const attrData = attrsData[attrName];
175175
const parsedAttr = this.parseAttributeValue(attrName, attrValue, attrData);
176-
let res = true;
176+
let resolvedValue = true;
177177

178178
if (filter) {
179179
const { parsedValue } = parsedAttr;
180-
res =
181-
filter({ tag, attribute: attrName, value: attrValue, parsedValue, attributes: attrs, resourcePath }) !==
182-
false;
180+
resolvedValue = filter({
181+
tag,
182+
attribute: attrName,
183+
value: attrValue,
184+
parsedValue,
185+
attributes: attrs,
186+
resourcePath,
187+
});
183188
}
184189

185-
if (res === true) {
190+
if (resolvedValue !== false) {
186191
if (parsedAttr.attrs) {
187192
parsedAttrs.push(...parsedAttr.attrs);
188193
} else {
189194
parsedAttrs.push(parsedAttr);
190195
}
196+
197+
if (typeof resolvedValue === 'string') {
198+
parsedAttr.resolvedValue = resolvedValue;
199+
}
191200
}
192201
}
193202

src/Loader/Loader.js

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const Render = require('./Modes/Render');
44
class Loader {
55
/** @type {Render|Compile} */
66
compiler = null;
7+
loaderOption = null;
78

89
constructor() {}
910

@@ -16,17 +17,14 @@ class Loader {
1617
*/
1718
init(loaderContext, { pluginCompiler, loaderOption, resolver, collection }) {
1819
const { hot } = loaderContext;
19-
const { preprocessorMode, esModule, self: useSelf } = loaderOption.get();
2020

21+
this.loaderOption = loaderOption;
2122
this.compiler = this.factory({
22-
preprocessor: loaderOption.getPreprocessorModule(),
23-
preprocessorMode,
24-
esModule,
25-
useSelf,
26-
hot,
2723
pluginCompiler,
28-
collection,
24+
loaderOption,
2925
resolver,
26+
collection,
27+
hot,
3028
});
3129
}
3230

@@ -35,23 +33,24 @@ class Loader {
3533
*
3634
* Note: default mode is `render`
3735
*
36+
* @param {Option} loaderOption The loader option instance.
3837
* @param {{}} preprocessor The preprocessor option.
39-
* @param {string} preprocessorMode The loader mode: compile or render.
40-
* @param {boolean} esModule
41-
* @param {boolean} useSelf Whether the `self` option is true.
42-
* @param {boolean} hot Whether the `hot` option of the `devServer` is enabled to page live reload.
4338
* @param {Compiler} pluginCompiler
44-
* @param {Collection} collection
4539
* @param {Resolver} resolver
40+
* @param {Collection} collection
41+
* @param {boolean} hot Whether the `hot` option of the `devServer` is enabled to page live reload.
42+
*
4643
* @return {Render|Compile}
4744
*/
48-
factory({ preprocessor, preprocessorMode, esModule, useSelf, hot, pluginCompiler, collection, resolver }) {
45+
factory({ pluginCompiler, loaderOption, resolver, collection, hot }) {
46+
const { preprocessorMode } = loaderOption.get();
47+
4948
switch (preprocessorMode) {
5049
case 'compile':
51-
return new Compile({ preprocessor, esModule, hot, pluginCompiler, collection, resolver });
50+
return new Compile({ loaderOption, pluginCompiler, collection, resolver, hot });
5251
case 'render':
5352
default:
54-
return new Render({ preprocessor, esModule, hot, pluginCompiler, collection, resolver });
53+
return new Render({ loaderOption, pluginCompiler, collection, resolver, hot });
5554
}
5655
}
5756

src/Loader/Modes/Compile.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,14 @@ const { errorToHtml } = require('../Messages/Exeptions');
99
class Compile extends PreprocessorModeAbstract {
1010
enclosingQuotes = `'`;
1111
isExport = false;
12-
collection = null;
13-
pluginCompiler = null;
1412

1513
/**
1614
* @param {PreprocessorModeProperties} props
1715
*/
1816
constructor(props) {
1917
super(props);
2018

21-
this.isExport = typeof props.preprocessor.export === 'function';
22-
this.collection = props.collection;
23-
this.pluginCompiler = props.pluginCompiler;
19+
this.isExport = typeof this.preprocessor.export === 'function';
2420
}
2521

2622
/**

src/Loader/Modes/PreprocessorModeAbstract.js

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,41 @@ const { isUrl } = require('../../Common/Helpers');
44
/**
55
* @typedef {Object} PreprocessorModeProperties
66
*
7-
* @property{{}} preprocessor
8-
* @property {boolean} esModule
9-
* @property {boolean} hot
7+
* @property {Option} loaderOption The loader option instance.
8+
* @property {Compiler} pluginCompiler
109
* @property {Collection} collection
10+
* @property {Resolver} resolver
11+
* @property {boolean} hot
1112
*/
1213

1314
/**
1415
* Base Preprocessor Mode class with abstract methods.
1516
*/
1617
class PreprocessorModeAbstract {
18+
pluginCompiler = null;
19+
loaderOption = null;
1720
preprocessor = null;
1821
collection = null;
1922
resolver = null;
23+
exportCode = '';
2024

2125
/**
22-
* @param {{}} preprocessor
23-
* @param {boolean} esModule
24-
* @param {boolean} hot
26+
* @param {Option} loaderOption The loader option instance.
2527
* @param {Collection} collection
28+
* @param {Compiler} pluginCompiler
2629
* @param {Resolver} resolver
30+
* @param {boolean} hot
2731
*/
28-
constructor({ preprocessor, esModule, hot, collection, resolver }) {
32+
constructor({ loaderOption, pluginCompiler, collection, resolver, hot }) {
33+
const preprocessor = loaderOption.getPreprocessorModule();
34+
const { esModule } = loaderOption.get();
35+
36+
//console.log('collection: ', collection);
37+
2938
this.exportCode = esModule ? 'export default ' : 'module.exports=';
3039
this.preprocessor = preprocessor || {};
40+
this.loaderOption = loaderOption;
41+
this.pluginCompiler = pluginCompiler;
3142
this.collection = collection;
3243
this.resolver = resolver;
3344
this.hot = hot === true;
@@ -85,7 +96,15 @@ class PreprocessorModeAbstract {
8596
} else {
8697
resolvedFile = this.resolver.resolve(file, issuer);
8798

88-
if (isUrl(resolvedFile)) {
99+
let isEntryFile = this.loaderOption.isEntry(resolvedFile);
100+
let isRouteFile = this.loaderOption.isRoute(resolvedFile);
101+
let isRequestUrl = isUrl(resolvedFile);
102+
103+
if (isRouteFile && !isRequestUrl) {
104+
this.collection.saveInnerRoute(resolvedFile, issuer);
105+
}
106+
107+
if (isEntryFile || isRouteFile || isRequestUrl) {
89108
return {
90109
resolvedFile,
91110
requireExpression: resolvedFile,

src/Loader/Modes/Render.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,11 @@ const { errorToHtml } = require('../Messages/Exeptions');
77
* Render into HTML and export as a JS module.
88
*/
99
class Render extends PreprocessorModeAbstract {
10-
collection = null;
11-
pluginCompiler = null;
12-
1310
/**
1411
* @param {PreprocessorModeProperties} props
1512
*/
1613
constructor(props) {
1714
super(props);
18-
19-
this.collection = props.collection;
20-
this.pluginCompiler = props.pluginCompiler;
2115
}
2216

2317
/**

0 commit comments

Comments
 (0)