Skip to content

Commit b156817

Browse files
committed
optimize: lazy load the plugin config file
1 parent bae5691 commit b156817

62 files changed

Lines changed: 410 additions & 45 deletions

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: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,29 @@
11
# Change log
22

3+
## 3.5.4 (2024-03-03)
4+
5+
- optimize: lazy load the plugin config file
6+
- refactor: change the label in output: `html-bundler-webpack-plugin` => `HTML bundler plugin`
7+
- refactor: optimize code for other plugins extending from this plugin.\
8+
For example: the [pug-plugin](https://github.com/webdiscus/pug-plugin) since the version `5.0.0` is extended from the `html-bundler-webpack-plugin` with Pug specifically settings.
9+
- docs: add description how to use the `entry` plugin option as the array of the `EntryDescription`, e.g.:
10+
```js
11+
{
12+
entry: [
13+
{
14+
filename: 'index.html', // output filename in dist/
15+
import: 'src/views/index.html', // template file
16+
data: { title: 'Homepage' }, // page specifically variables
17+
},
18+
{
19+
filename: 'news/sport.html',
20+
import: 'src/views/news/sport/index.html',
21+
data: { title: 'Sport' },
22+
},
23+
],
24+
}
25+
```
26+
327
## 3.5.3 (2024-02-28)
428

529
- fix: correct parsing the data passed via query in JSON notation, e.g.: `index.ejs?{"title":"Homepage","lang":"en"}`

README.md

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,10 @@ See [boilerplate](https://github.com/webdiscus/webpack-html-scss-boilerplate)
435435
1. [Plugin options](#plugin-options)
436436
- [test](#option-test) (RegEx to handle matching templates)
437437
- [entry](#option-entry) (entry as a list of template files)
438+
- [entry as an array](#option-entry-array) (array notation)
439+
- [entry as an object](#option-entry-object) (object notation)
440+
- [entry as a path](#option-entry-path) (find templates in a directory recursively)
441+
- [entry data](#option-entry-data) (pass data in the single template as an object or a file)
438442
- [entry dynamic](#option-entry-path) (entry as a path to template files)
439443
- [outputPath](#option-outputpath) (output path of HTML file)
440444
- [filename](#option-filename) (output filename of HTML file)
@@ -467,7 +471,7 @@ See [boilerplate](https://github.com/webdiscus/webpack-html-scss-boilerplate)
467471
- [pug](#loader-option-preprocessor-options-pug)
468472
- [twig](#loader-option-preprocessor-options-twig)
469473
- [custom](#loader-option-preprocessor-custom) (using any template engine)
470-
- [data](#loader-option-data) (pass data into templates)
474+
- [data](#loader-option-data) (pass global data into all templates as an object or a file)
471475
1. [Using template engines](#template-engine)
472476
- [Eta](#using-template-eta)
473477
- [EJS](#using-template-ejs)
@@ -1219,7 +1223,7 @@ This plugin can completely replace the functionality of `mini-css-extract-plugin
12191223
12201224
### `entry`
12211225
1222-
Type: `EntryObject | string`.
1226+
Type: `EntryObject | Array<EntryDescription> | string`.
12231227
12241228
The `EntryObject` is identical to [Webpack entry](https://webpack.js.org/configuration/entry-context/#entry)
12251229
plus additional `data` property to pass custom variables into the HTML template.
@@ -1384,7 +1388,62 @@ To pass global variables in all templates use the [data](#loader-option-data) lo
13841388
> **Note**
13851389
>
13861390
> You can define templates both in Webpack `entry` and in the `entry` option of the plugin. The syntax is identical.
1387-
> But the `data` property can only be defined in the `entry` option of the plugin.
1391+
> But the `data` property can only be used in the `entry` option of the plugin.
1392+
1393+
<a id="option-entry-array" name="option-entry-array"></a>
1394+
#### Entry as an array
1395+
1396+
If the `entry` is the array of the `EntryDescription` then the `filename` property is required.
1397+
1398+
```js
1399+
{
1400+
entry: [
1401+
{
1402+
filename: 'index.html', // => output filename dist/index.html
1403+
import: 'src/views/index.html', // template file
1404+
data: { title: 'Homepage' }, // page specifically variables
1405+
},
1406+
{
1407+
filename: 'about.html',
1408+
import: 'src/views/about.html',
1409+
data: { title: 'About' },
1410+
},
1411+
{
1412+
filename: 'news/sport.html',
1413+
import: 'src/views/news/sport.html',
1414+
data: { title: 'Sport' },
1415+
},
1416+
],
1417+
}
1418+
```
1419+
1420+
<a id="option-entry-object" name="option-entry-object"></a>
1421+
#### Entry as an object
1422+
1423+
The absolute equivalent to the example above using an object is:
1424+
1425+
```js
1426+
{
1427+
entry: {
1428+
index: { // => output filename dist/index.html
1429+
import: 'src/views/index.html', // template file
1430+
data: { title: 'Homepage' }, // page specifically variables
1431+
},
1432+
about: {
1433+
import: 'src/views/about.html',
1434+
data: { title: 'About' },
1435+
},
1436+
'news/sport': {
1437+
import: 'src/views/news/sport.html',
1438+
data: { title: 'Sport' },
1439+
},
1440+
},
1441+
}
1442+
```
1443+
1444+
The difference between **object** and **array** notation:
1445+
- Using the **object** notation the output **filename** is the key of the entry item without the `.html` file extension.
1446+
- Using the **array** notation the output **filename** is the `filename` property of the array item contained the file with `.html` file extension.
13881447
13891448
<a id="option-entry-path" name="option-entry-path"></a>
13901449

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": "3.5.3",
3+
"version": "3.5.4",
44
"description": "HTML bundler plugin for webpack handles a template as an entry point, extracts CSS and JS from their sources referenced in HTML, supports template engines like Eta, EJS, Handlebars, Nunjucks.",
55
"keywords": [
66
"html",

src/Common/Config.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
const path = require('path');
2+
3+
class Config {
4+
static #loaded = false;
5+
static #configFile = '';
6+
static #config = {
7+
// plugin name, must be same as node module name
8+
pluginName: 'webpack-plugin',
9+
// label in terminal output from plugin
10+
pluginLabel: 'plugin',
11+
// label in terminal output from loader
12+
loaderLabel: 'loader',
13+
};
14+
15+
static init(file) {
16+
this.#configFile = path.isAbsolute(file)
17+
? require.resolve(file)
18+
: // path relative to `./src/Common`
19+
require.resolve(path.join('../', file));
20+
}
21+
22+
static get() {
23+
// lazy load config data
24+
if (!this.#loaded) {
25+
this.#load();
26+
}
27+
28+
return this.#config;
29+
}
30+
31+
static #load() {
32+
if (this.#configFile) {
33+
let config = require(this.#configFile);
34+
this.#config = Object.assign(this.#config, config);
35+
this.#loaded = true;
36+
}
37+
}
38+
}
39+
40+
module.exports = Config;

src/Common/FileUtils.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
const path = require('path');
44
const { isWin, pathToPosix } = require('./Helpers');
5-
const { pluginName } = require('../config');
5+
const Config = require('../Common/Config');
6+
7+
const { pluginName } = Config.get();
68

79
// string containing the '/node_modules/'
810
const nodeModuleDirname = path.sep + 'node_modules' + path.sep;

src/Loader/Messages/Exeptions.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ const makeSerializable = require('webpack/lib/util/makeSerializable');
66

77
const ansis = require('ansis');
88
const { red, yellow, cyan, green, ansi256, cyanBright, reset, whiteBright, bgYellow } = require('ansis');
9-
const { pluginName } = require('../../config');
9+
const Config = require('../../Common/Config');
10+
11+
const { pluginLabel } = Config.get();
1012

1113
const redBright = ansi256(203);
12-
const pluginHeaderHtml = `<span style="color:#e36049">[${pluginName}]</span>`;
14+
const pluginHeaderHtml = `<span style="color:#e36049">[${pluginLabel}]</span>`;
1315

1416
class LoaderException extends WebpackError {
1517
error = null;
@@ -20,7 +22,7 @@ class LoaderException extends WebpackError {
2022
* @param {Error?} error The original error.
2123
*/
2224
constructor(message, error) {
23-
message = `\n${reset.whiteBright.bgRedBright` ${pluginName} `} ${whiteBright(message)}\n`;
25+
message = `\n${reset.whiteBright.bgRedBright` ${pluginLabel} `} ${whiteBright(message)}\n`;
2426

2527
if (error && error.stack) {
2628
message += error.stack;
@@ -63,7 +65,7 @@ class LoaderException extends WebpackError {
6365
* @returns {string}
6466
*/
6567
const errorToHtml = (error) => {
66-
let message = ansis.strip(error.toString()).replace(pluginName, pluginHeaderHtml).replace(/\n/g, '<br>');
68+
let message = ansis.strip(error.toString()).replace(pluginLabel, pluginHeaderHtml).replace(/\n/g, '<br>');
6769

6870
return `<!DOCTYPE html><html><head></head><body>${message}</body></html>`;
6971
};

src/Plugin/AssetCompiler.js

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const AssetGenerator = require('webpack/lib/asset/AssetGenerator');
1010
//const JavascriptParser = require('webpack/lib/javascript/JavascriptParser');
1111
//const JavascriptGenerator = require('webpack/lib/javascript/JavascriptGenerator');
1212

13-
const { pluginName } = require('../config');
13+
const Config = require('../Common/Config');
1414
const { baseUri, urlPathPrefix, cssLoaderName } = require('../Loader/Utils');
1515
const { findRootIssuer } = require('../Common/CompilationHelpers');
1616
const { isDir } = require('../Common/FileUtils');
@@ -37,6 +37,7 @@ const { compilationName, verbose } = require('./Messages/Info');
3737
const { PluginError, afterEmitException } = require('./Messages/Exception');
3838

3939
const loaderPath = require.resolve('../Loader');
40+
const { pluginName } = Config.get();
4041

4142
/**
4243
* The CSS loader.
@@ -181,7 +182,22 @@ class AssetCompiler {
181182
* @param {Compiler} compiler The instance of the webpack compiler.
182183
* @abstract
183184
*/
184-
initialize(compiler) {}
185+
init(compiler) {}
186+
187+
/**
188+
* Initialize loader for entry files.
189+
*/
190+
initLoader() {
191+
const defaultLoader = {
192+
test: Option.get().test,
193+
// ignore 'asset/source' with the '?raw' query
194+
// see https://webpack.js.org/guides/asset-modules/#replacing-inline-loader-syntax
195+
resourceQuery: { not: [/raw/] },
196+
loader: loaderPath,
197+
};
198+
199+
Option.addLoader(defaultLoader);
200+
}
185201

186202
/**
187203
* Apply plugin.
@@ -194,6 +210,7 @@ class AssetCompiler {
194210
const { webpack } = compiler;
195211
const { NormalModule, Compilation } = webpack;
196212

213+
this.promises = [];
197214
this.fs = compiler.inputFileSystem.fileSystem;
198215
this.webpack = webpack;
199216
HotUpdateChunk = webpack.HotUpdateChunk;
@@ -204,8 +221,8 @@ class AssetCompiler {
204221
Option.enableLibraryType(this.entryLibrary.type);
205222
AssetResource.init(compiler);
206223

207-
this.initialize(compiler);
208-
this.promises = [];
224+
this.init(compiler);
225+
this.initLoader();
209226

210227
// initialize integrity plugin
211228
this.integrityPlugin = new Integrity(Option);

src/Plugin/Messages/Deprecation.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
const { red, green, black } = require('ansis');
2-
const { pluginName } = require('../../config');
32
const { outToConsole } = require('../../Common/Helpers');
3+
const Config = require('../../Common/Config');
44

5-
const header = `\n${black.bgYellow` ${pluginName} `}${black.bgAnsi(227)` DEPRECATE `} `;
5+
const { pluginLabel } = Config.get();
6+
7+
const header = `\n${black.bgYellow` ${pluginLabel} `}${black.bgAnsi(227)` DEPRECATE `} `;
68

79
// Example for deprecations
810

src/Plugin/Messages/Exception.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
const fs = require('fs');
22
const path = require('path');
33
const { reset, green, cyan, cyanBright, yellow, white, whiteBright, redBright } = require('ansis');
4-
const { pluginName } = require('../../config');
4+
const Config = require('../../Common/Config');
55

6+
const { pluginLabel } = Config.get();
67
const PluginError = new Set();
78

89
class PluginException extends Error {
@@ -11,7 +12,7 @@ class PluginException extends Error {
1112
* @param {Error?} error The original error.
1213
*/
1314
constructor(message, error) {
14-
message = `\n${reset.whiteBright.bgRedBright` ${pluginName} `} ${whiteBright(message)}\n`;
15+
message = `\n${reset.whiteBright.bgRedBright` ${pluginLabel} `} ${whiteBright(message)}\n`;
1516

1617
if (error && error.stack) {
1718
message += error.stack;

src/Plugin/Messages/Info.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ const {
1515
const Collection = require('../Collection');
1616
const { outToConsole, isFunction } = require('../../Common/Helpers');
1717
const { relativePathForView } = require('../../Common/FileUtils');
18-
const { pluginName } = require('../../config');
18+
const Config = require('../../Common/Config');
1919

2020
const Dependency = require('../../Loader/Dependency');
2121
const PluginService = require('../PluginService');
2222

23+
const { pluginLabel } = Config.get();
24+
2325
const gray = ansi256(244);
2426
const padLevel1 = 16;
2527
const padLevel2 = padLevel1 + 10;
@@ -36,8 +38,8 @@ const padChunks = padLevel1 + 4;
3638
*/
3739
const compilationName = (error) =>
3840
error
39-
? bgAnsi(196).whiteBright` HTML Bundler Plugin ` + red` ▶▶▶`
40-
: bgAnsi(118).black` HTML Bundler Plugin ` + green` ▶▶▶`;
41+
? bgAnsi(196).whiteBright` ${pluginLabel} ` + red` ▶▶▶`
42+
: bgAnsi(118).black` ${pluginLabel} ` + green` ▶▶▶`;
4143

4244
const colorType = (item, pad) => {
4345
let { type, inline } = item;
@@ -100,7 +102,7 @@ const renderAssets = (item, pad = padLevel2) => {
100102
* Display all processed assets in entry points.
101103
*/
102104
const verbose = () => {
103-
let str = '\n' + black.bgGreen` ${pluginName} ` + bgAnsi256(193).black` Entry processing ` + '\n';
105+
let str = '\n' + black.bgGreen` ${pluginLabel} ` + bgAnsi256(193).black` Entry processing ` + '\n';
104106

105107
// display loader watch dependencies
106108
if (PluginService.isWatchMode()) {

0 commit comments

Comments
 (0)