- fix: in TypeScript the
renderStage
option should be optional
- feat: add the
renderStage
option to define the stage for rendering output HTML in the processAssets Webpack hook - fix: set default render stage before the stage used in
compression-webpack-plugin
to save completely rendered HTML, #134 - test: add test for the render stage
- docs: add documentation for the new option in readme
fix: fail rebuild after changed css file if no html entry defined, #132
- fix: resolve webpack alias correctly if it is external URL
- fix: if a module build has failed then stop further processing of modules to allow output original error
- fix: re-deploy broken package
v4.10.0
in npm repository. An error occurred during deployment.
- feat: add support for handlebars helpers in compile mode
- fix: Error Cannot find module 'nunjucks', introduced in
4.9.1
- fix: rebuild all entrypoints after changes in partials matching to the
watchFiles
plugin option, this fix extends the feature ofv4.9.0
- feat: using serve/watch, after a partial file is modified all entry point templates will be rebuilt, #127.
The problem: 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.
- fix: if template is imported in JS in compile mode and the same template function called with different variables set then variables from previous definition must not be cached. This fix is for all template engines. #128
- feat: add
minimized
tag in stats output for minimized HTML assets
- feat: precompile Handlebars templates with sub partials
- fix: missing optional dependencies
- fix: watching changes in files outer the project directory
- feat: add support the Markdown
*.md
files in the template engines:eta
,ejs
,handlebars
,pug
. The markdown file can be included in the HTML template, e.g.Eta
:<html> <head> <!-- Load Markdown and Highlighting styles --> <link href="github-markdown-css/github-markdown-light.css" rel="stylesheet" /> <link href="prismjs/themes/prism.min.css" rel="stylesheet" /> </head> <body class="markdown-body"> <!-- Load Markdown file --> <%~ include('readme.md') %> </body> </html>
- fix: issue by HMR when CSS contains Tailwind-like style names with backslashes
E.g.:
.\32xl\:w-96
,.lg\:ml-4
- fix: issue by HMR when CSS contains a comment with
back-tick
quotes
- fix: if used
splitChunks.chunks
option then this options will be removed and will be displayed a warning This option makes no sense, because we will split only scripts. - docs: update readme
- feat: add support the HMR for styles imported in JavaScript files
- feat: add new
css.hot
option to enable HMR for styles
- fix: issue by inline a style when in the tag used single quotes for attribute
- fix: add Exception when used
splitChunks
and occurs the error: Can't resolve a CSS file in template - fix: correct Exception message when a source CSS file is not found
- fix: if used multiple config and cache
filesystem
, occurs the error 'PersistentCache is already registered' - test: add test for multiple config when used cache
filesystem
- feat: add
context
loader option to resolve assets w/o leading/
in a directory outer your project:new HtmlBundlerPlugin({ loaderOptions: { context: path.resolve(__dirname, '../other/'), }, }),
- docs: update readme
- feat: add preprocessor for Tempura template engine. Supports the static render and template function.
- test: add test for the
tempura
preprocessor - docs: add documentation for Tempura
- chore: add usage example
- feat: add support for Webpack
>= 5.96
to correct inline images into CSS and HTML WARNING: Webpack version5.96.0
introduces the BREAKING CHANGE in theCodeGenerationResults
class! - feat: add support for Webpack
>= 5.96
to correct CSS lazy loading WARNING: Webpack version5.96.0
introduces the BREAKING CHANGE in theAssetGenerator
class! - chore: update package and devel dependencies
- test: update tests
- chore: update dependencies
- fix: if
filesystem
cache is used, webpack stats or errors are not displayed, #115 - test: allow set the
stats.preset
webpack option to display stats info by testing
- fix: issue
file is not resolved
after start->stop->start in serve/watch mode when used cache filesystem, #114 - chore: update dev packages
- fix: after 2-3 changes of the data file (global or entry), the dependent entry template is not recompiled.
- test: add test for Eta preprocessor with default options
- feat: add supports the
require
of CommonJS and JSON files in EJS templates:or<% const data = require('./data.js') %> <div>Film: <%= data.title %></div> <div>Genre: <%= data.genre %></div>
<% const data = require('./data.json') %> <div>Film: <%= data.title %></div> <div>Genre: <%= data.genre %></div>
- chore: update peerDependencies
- test: refactor test cases for preprocessor
-
Minimum supported Node.js version
18+
.
The plugin may works on the Node.js >=16.20.0
, but we can't test the plugin with outdated Node.js versions. GitHub CI test works only on Node.js >= 18. Many actual dev dependencies requires Node.js >= 18. -
Minimum supported Webpack version
5.81+
. -
The plugin
option
property is not static anymore:OLD (up to v3.x)
class MyPlugin extends HtmlBundlerPlugin { constructor(options = {}) { super({ ...options }); } init(compiler) { // MyPlugin.option. ...; <= was as static property } }
NEW (since v4.0)
class MyPlugin extends HtmlBundlerPlugin { constructor(options = {}) { super({ ...options }); } init(compiler) { // this.option. ...; <= now is non static property } }
-
Using the
addProcess()
plugin method is changed:OLD (up to v3.x)
class MyPlugin extends HtmlBundlerPlugin { constructor(options = {}) { super({ ...options }); } init(compiler) { // the method was as property of the static `option` MyPlugin.option.addProcess('postprocess', (content) => { return content; }); } }
NEW (since v4.0)
class MyPlugin extends HtmlBundlerPlugin { constructor(options = {}) { super({ ...options }); } init(compiler) { // now is the class method this.addProcess('postprocess', (content) => { return content; }); } }
-
The
watchFiles.files
option has been renamed towatchFiles.includes
.
Thefiles
option is still supported but is deprecated. It's recommended to replace thefiles
withincludes
in your config. -
The
watchFiles.ignore
option has been renamed towatchFiles.excludes
.
Theignore
option is still supported but is deprecated. It's recommended to replace theignore
withexcludes
in your config.
- feat: add support the multiple webpack configuration:
const path = require('path');
const HtmlBundlerPlugin = require('@test/html-bundler-webpack-plugin');
module.exports = [
{
name: 'first',
output: {
path: path.join(__dirname, 'dist/web1/'),
},
plugins: [
new HtmlBundlerPlugin({
entry: {
index: './web1/views/home.html',
},
}),
],
},
{
name: 'second',
output: {
path: path.join(__dirname, 'dist/web2'),
},
plugins: [
new HtmlBundlerPlugin({
entry: {
index: './web2/views/home.html',
},
}),
],
},
];
- feat: display webpack config name in console output:
module.exports = { name: 'client', // <= this name will displayed in console output }
- fix: ERROR in RealContentHashPlugin in serv/watch mode after adding new import file
- fix: when using integrity occurs ERROR in RealContentHashPlugin in serv/watch mode after changes by using dynamic import
- refactor: rewrite all static classes to regular, this is needed to support webpack multiple configurations
- refactor: code refactoring, invisible improvements
- test: add testing for Node.js
v22
on GitHub - test: add tests to improve the code coverage to 98%, 2% code can be tested only manual, e.g. in watch/serve mode after changes
- chore: update dev packages, many packages requires Node.js >= v18
- docs: update readme
See release 4.0.0
See release 4.0.0
See release 4.0.0
See release 4.0.0
- fix: in dev mode imports SCSS in JS when in the same file is inlined another SCSS file via
?inline
query, #102
- fix: error when
integrity
option is enabled but no template defined in entry, #107
- fix: when using the integrity option, leaves the original attributes in the script tag as is
- feat: add support the
?inline
query for styles imported in JavaScript:import './style-a.css?inline'; // the extracted CSS will be injected into HTML import './style-b.css'; // the extracted CSS will be saved into separate output file
- feat: add
runtime
option for thehandlebars
preprocessor - test: add test for the
runtime
option - docs: update readme
- fix: resolving source file in a tag attribute when another attribute contains the
>
char, e.g.:<img src="./arrow.png" alt="right->">
- chore: improve error handling when attributes parsing
- test: improve test coverage
- feat: update
eta
package to latest version 3.4.0 - chore: update dev dependencies and tests
- feat: add
watchFiles.includes
andwatchFiles.excludes
options to allow watch specifically external file, e.g. *.md file included via Pug filter from any location outer project directoryWARNING: in the 4.0 version the undocumentedtype WatchFiles = { paths?: Array<string>; files?: Array<RegExp>; includes?: Array<RegExp | string>; // <= NEW ignore?: Array<RegExp>; excludes?: Array<RegExp | string>; // <= NEW };
includes
andexcludes
properties are removed from code.
- feat: add resolving the url() value in the style attribute:
<div style="background-image: url(./image.png);"></div>
- feat: add support for the
css-loader
optionexportType
as css-style-sheet - test: add tests for import of CSS stylesheet
- docs: update readme
- feat: add
entryFilter
option to include or exclude entry files when theentry
option is the path
- feat: add support the CSS Modules for styles imported in JS using the css-loader modules option.
Required:css-loader
>=7.0.0
The CSS module rule in the webpack config:CSS:{ test: /\.(css)$/, use: [ { loader: 'css-loader', options: { modules: { localIdentName: '[name]__[local]__[hash:base64:5]', exportLocalsConvention: 'camelCase', }, }, }, ], },
Using in JS:.red { color: red; } .green { color: green; }
// the styles contains CSS class names: { red: 'main__red__us4Tv', green: 'main__green__bcpRp' } import styles from './main.css';
- fix: issue when used js dynamic import with magic comments /* webpackPrefetch: true */ and css.inline=true, #88
- fix: ansi colors for verbose output in some terminals
- feat: add support for dynamic import of styles
const loadStyles = () => import('./component.scss'); loadStyles();
- fix: extract CSS from styles imported in dynamically imported JS
- feat(Pug): add experimental (undocumented) syntax to include (using
?include
query) compiled CSS directly into style tag to allow keep tag attributeswill be generatestyle(scope='some')=require('./component.scss?include')
<style scope="some"> ... CSS ... </style>
- test: add test for lazy loading CSS using
fetch()
anddocument.adoptedStyleSheets
- docs: update readme
- feat: add the possibility to add many post processes. Next postprocess receives the result from previous.
So you can extend this plugin with additional default functionality.
This feature is used in the pug-plugin for pretty formatting generated HTML.
class MyPlugin extends HtmlBundlerPlugin { init(compiler) { MyPlugin.option.addProcess('postprocess', (content) => { // TODO: modify the generated HTML content return content; }); } } module.exports = { plugins: [ new MyPlugin({ entry: { index: './src/index.html', }, }), ], };
See an example in the test case.
- fix: define the unique instance name for the plugin as
HtmlBundlerPlugin
instead ofPlugin
- fix: catching of the error when a peer dependency for a Pug filter is not installed
- fix: resolving asset files on windows
- fix: avoid recompiling all entry templates after changes of a non-entry partial file, pug-plugin issue
- fix: cannot find module 'nunjucks/src/object', introduced in v3.6.0
- feat: resolve resource files in an attribute containing the JSON value using the
require()
function,
source template:generated HTML contains resolved output assets filenames:<a href="#" data-image='{ "alt":"image", "imgSrc": require("./pic1.png"), "bgImgSrc": require("./pic2.png") }'> ... </a>
<a href="#" data-image='{ "alt":"image", "imgSrc": "img/pic1.da3e3cc9.png", "bgImgSrc": "img/pic2.e3cc9da3.png" }'> ... </a>
- fix: initialize the singleton of the Config only once
- optimize: lazy load the plugin config file
- refactor: change the label in output:
html-bundler-webpack-plugin
=>HTML bundler plugin
- refactor: optimize code for other plugins extending from this plugin.
For example: the pug-plugin since the version5.0.0
is extended from thehtml-bundler-webpack-plugin
with Pug specifically settings. - docs: add description how to use the
entry
plugin option as the array of theEntryDescription
, e.g.:{ entry: [ { filename: 'index.html', // output filename in dist/ import: 'src/views/index.html', // template file data: { title: 'Homepage' }, // page specifically variables }, { filename: 'news/sport.html', import: 'src/views/news/sport/index.html', data: { title: 'Sport' }, }, ], }
- fix: correct parsing the data passed via query in JSON notation, e.g.:
index.ejs?{"title":"Homepage","lang":"en"}
- fix: by parsing of the generated html ignore files already resolved via a preprocessor, e.g. pug
- fix(pug): resolve resource required in pug code and content, also outer tag attributes
- fix(pug): resolve images generated via
responsive-loader
when used query parameters with,
and&
separators - test: add tests from pug-plugin
- fix: when used TS then could not find a declaration file for module 'html-bundler-webpack-plugin'
- fix(pug): correct resolving required resources in multiple pages
- feat: add support for the
Pug
template engine. Thepug
preprocessor based on the @webdiscus/pug-loader source code and has the same options and features. - test: add pug tests
- docs: add documentation for using the pug
- fix: serialization issue when used the
cache.type = 'filesystem'
- fix: missing output js files after second run build when used the
cache.type = 'filesystem'
- fix: error by resolving url() in the CSS file defined in the entry option
- fix: save the webmanifest files in the directory defined in the
faviconOptions.path
option
- fix: use the favicons default options for the build-in FaviconsBundlerPlugin when no plugin options
- fix: error by resolving
url(date:image...)
in CSS
- fix: if the same CSS file is imported in many js files, then the CSS is extracted for the first issuer only, #68
- fix: the
pathData.chunk.name
is undefined when thejs.filename
is a function, this bug was introduced in3.4.5
- fix: the
pathData.filename
is undefined after changes when thejs.filename
is a function
- fix: extract css from complex libs like MUI leads to an infinity walk by circular dependency, #59
- test: refactor tests
- fix: favicon plugin causes a crash without an error explaining if no link tag is included
- fix: watching changes in template function imported in JS
- fix: runtime error using template function in JS when external data is not defined
- feat: add support for the template function on the client-side for
ejs
- docs: update readme
- test: add tests for compile mode
- feat: add support for the template function on the client-side for
eta
- feat: add Twig preprocessor. Now you can use "best of the best" template engine. Enjoy ;-)
- fix: fatal error when using the handlebars preprocessor (introduced in v3.1.2)
- fix: access
@root
variables in hbspartial
helper inside theeach
block
3.1.2 (2023-11-24) DEPRECATED: the critical bug by using the handlebars preprocessor is fixed in the v3.1.3
- fix: access
@root
variables in hbspartial
helper inside theeach
block
- fix: define
js.test
field intypes.d.ts
as optional
- feat: add support for the
template function
in JS runtime on the client-side.
For example:Template function works with preprocessors:import personTmpl from './partials/person.ejs'; // render template function with variables in browser document.getElementById('person').innerHTML = personTmpl({ name: 'Walter White', age: 50});
ejs
,handlebars
,nunjucks
.
Note: Theeta
(default preprocessor) doesn't support template function in JS on the client-side, use theejs
instead. - feat: add CSS extraction from styles used in *.vue files.
For example, MyComponent.vue:<template> ... </template> <script setup> ... </script> <!-- CSS will be extracted from the SCSS file into a separate *.css file --> <style src="./style.scss" lang="scss"></style> <!-- CSS will be extracted from the style tag into a separate *.css file --> <style> h1 { color: red; } </style>
- fix: add the missing
plugins
directory to package - chore: add usage example of the build-in favicons plugin
- fix: installation error 'Invalid tag name of the favicons package' (introduced in v3.0.0)
- fix: add the root dir of the module to exports in the package.json
- test: update manual tests for using with the Eta version 3.x
- docs: update readme for live reloading
-
feat(BREAKING CHANGE): changed
postprocess
callback arguments and return
OLD:postprocess(content: string, info: TemplateInfo, compilation: webpack.Compilation): string | null; type TemplateInfo = { filename: string | ((pathData: PathData) => string); assetFile: string; sourceFile: string; outputPath: string; verbose: boolean | undefined; };
When return
null
then the template processing was skipped.NEW:
Removed properties:filename
,verbose
. Added properties:name
,resource
.postprocess(content: string, info: TemplateInfo, compilation: webpack.Compilation): string | undefined; type TemplateInfo = { name: string; // the entry name assetFile: string; // the output asset filename relative to output path sourceFile: string; // the source filename without a query resource: string; // the source filename including a query outputPath: string; // output path of assetFile };
When return
null
orundefined
then the content stay unchanged bypostprocess
and will be processed in next hooks/callbacks. -
feat: optimize
postprocess
callback option, moved fromrenderManifest
sync hook toprocessAssets
async hook -
feat: add
postprocess
hook -
feat: add
beforePreprocessor
hook -
feat: add
beforePreprocessor
callback option -
feat: add
preprocessor
hook -
feat: add
resolveSource
hook -
feat: add
beforeEmit
hook -
feat: add
beforeEmit
callback option -
feat: add
afterEmit
hook -
feat: add
afterEmit
callback option -
feat: add possibility to create own plugin using the hooks:
beforePreprocessor
,preprocessor
,resolveSource
,postprocess
,beforeEmit
,afterEmit
-
feat: add the first plugin (plugin for bundler plugin :-) -
favicons-bundler-plugin
to generate and inject favicon tags for many devices.
For example:const HtmlBundlerPlugin = require('html-bundler-webpack-plugin'); const { FaviconsBundlerPlugin } = require('html-bundler-webpack-plugin/plugins'); module.exports = { plugins: [ new HtmlBundlerPlugin({ entry: { index: './src/views/index.html', }, }), // add the plugin to extend the functionality of the HtmlBundlerPlugin new FaviconsBundlerPlugin({ faviconOptions: { ... }, // favicons configuration options }), ], };
If you use the
favicons-bundler-plugin
, you need to install the favicons module. -
feat: add possibility to get output CSS filename in JS via import a source style file with the
url
query.
This feature allows the dynamic load the CSS in JavaScript, for example:function loadCSS(file) { const style = document.createElement('link'); style.href = file; style.rel = 'stylesheet'; document.head.appendChild(style); } loadCSS(require('./style.scss?url')); // <= dynamic load the source style file with `url` query
-
feat: add
js.inline.attributeFilter
option to keep some original script tag attributes when JS is inlined.
For example, keep theid
andtext/javascript
attributes by inlined<script id="my-id">...inlined JS code...</script>
:new HtmlBundlerPlugin({ // ... js: { inline: { attributeFilter: ({ attributes, attribute, value }) => { if (attribute === 'type' && value === 'text/javascript') return true; if (attribute === 'id' && attributes?.type === 'text/javascript') return true; }, }, }, }
-
refactor: optimize inner processes for HTML rendering
-
test: add tests for new features
-
docs: add descriptions for new features
- feat: add
resolveSource
hook - test: add a test as the example how to create a plugin using the
favicons
module
- fix: compute integrity for the current compilation only to isolate them by async tests
- fix: output exceptions for new callbacks
- test: add test for
beforePreprocessor
hook - test: add test for
beforePreprocessor
callback - test: add test for
preprocessor
hook - test: add test for
beforeEmit
hook - test: add test for
beforeEmit
callback - test: add test for
afterEmit
hook - test: add test for
afterEmit
callback
- feat: add
js.inline.keepAttributes
option to keep some original script tag attributes when JS is inlined - feat(EXPERIMENTAL): add
afterEmit
callback, undocumented - fix(EXPERIMENTAL, BREAKING CHANGE): rename
lazy
query tourl
to get output URL of CSS// your code to add the CSS file dynamically function dynamicLoad(outputFilename) { const style = document.createElement('link'); style.rel = 'stylesheet'; style.href = outputFilename; document.head.appendChild(style); } dynamicLoad(require('./style.scss?url')); // <= dynamic load the style file with `url` query
- chore: add usage example of image-minimizer-webpack-plugin
- feat(EXPERIMENTAL): add possibility to get output CSS filename in JS via import a style file with the
lazy
query.
DON'T use it for production, it is just EXPERIMENTAL undocumented feature!
This feature allows to lazy load the extracted CSS, for example:function loadCSS(file) { const style = document.createElement('link'); style.href = file; style.rel = 'stylesheet'; document.head.appendChild(style); } loadCSS(require('./style.scss?lazy')); // <= dynamic load the source style file with `lazy` query
- feat(EXPERIMENTAL): add
beforePreprocessor
hook, undocumented - feat(EXPERIMENTAL): add
beforePreprocessor
callback, undocumented - feat(EXPERIMENTAL): add
preprocessor
hook, undocumented - feat(EXPERIMENTAL, BREAKING CHANGE): rename
undocumented
experimentalafterCompile
callback tobeforeEmit
- feat(EXPERIMENTAL): add
beforeEmit
hook, undocumented - feat(EXPERIMENTAL): add
afterEmit
hook, undocumented - fix: disable preprocessor when the value of the
preprocessor
plugin option isfalse
- fix: error when used integrity with root publicPath, #42, #43
- feat: add
parsedValue
argument as an array of parsed filenames w/o URL query, in thefilter()
function of thesources
- fix(BREAKING CHANGE): for
srcset
attribute the type of thevalue
argument is nowstring
(was asArray<string>
), in thefilter()
function of thesources
Note: forsrcset
attribute you can use theparsedValue
as an array instead of thevalue
, thevalue
contains now an original string - docs: fix attributes type
- fix: correct attributes type in the
filter()
function of thesources
loader option - refactor: improve code
- docs: fix attributes type
- chore: update dependencies in examples
- docs: update readme
- fix: pass correct entry data in the template when the same template used for many pages with different data, in
serve
mode
- fix: remove unused
isEntry
property from theinfo
argument of thepostprocess
callback theisEntry
property was always true, because template is defined as an entrypoint - chore: code cleanup
- chore: add examples of using
PureCSS
as a plugin for Webpack and for PostCSS - docs: fix formatting in readme
- docs: fix some inaccuracies in readme
- feat: add the
integrityHashes
hook to allow retrieving the integrity values - test: add tests for the
integrityHashes
hook - docs: update README
- feat: add the
beforePreprocessor
callback option, called right before thepreprocessor
- test: add tests for new option
beforePreprocessor
- docs: update README
- feat: remove support for the
webpack-subresource-integrity
plugin, because it works not optimized and contains Webpack deprecated code - feat: add support for
subresource integrity
independent of other plugins. It was implemented own very compact, optimized and fast code to generateintegrity
forlink
andscript
tags. - feat(changed behavior): the
integrity
option defaults is nowfalse
(in v2.11.0 wasauto
usingwebpack-subresource-integrity
plugin) - feat: extend the
integrity
option values with the object to pass additionalhashFunctions
option - refactor: optimize code and improve performance for html parsing
- fix: remove comments of node module imported in dynamic imported chunks
- fix: correct content hash in the output JS filename when license comment is removed
- test: add tests for integrity
- test: remove the test strategy for node 14 on GitHub because the generated hashed test filenames are different from nodes 16, 18, 20
- chore: update dev dependencies
- docs: update README
- feat: add support for the
webpack-subresource-integrity
plugin to include the subresource integrity hash - feat: add the
integrity
option to enable/disable the support forwebpack-subresource-integrity
plugin
- fix: avoid generation of empty css files when source styles are imported in TS file
- feat: add Handlebars helpers
assign
,partial
andblock
to extend a template layout with blocks - chore: add
handlebars-layout
example - docs: update README
- feat(experimental): add support the Webpack
cache.type
asfilesystem
. This is yet an alpha version of the feature. You can try it, but if that doesn't work, just use the defaultcache.type
asmemory
. - feat: remove the
json5
dependency, take only the parser code from this package, remove unused code from it and optimize it for use with the plugin - fix: resolve output asset filenames without the needless index
.1
, likeindex.1.js
, when used the same base filename for template and js files. For example, if the source files with the same base namesrc/index.html
andsrc/index.js
were used, thendist/index.html
anddist/index.1.js
were created, because the entry name used for compilation must be unique. This case is fixed. - test: add tests for features and fixes
- test: remove unused code in test suits
- chore: update dev dependencies
- docs: update README
- feat: add watching for changes (add/remove/rename) in handlebars helpers without restarting Webpack
- feat: change the default value of the
hotUpdate
option tofalse
. This is not breaking change.
If you already have a js file, this setting should befalse
as Webpack automatically injects the hot update code into the compiled js file. Enable this option only if you don't have a referenced source file of a script in a html template. - docs: update README
- feat: add
js.inline.chunk
andjs.inline.source
options to inline only js chunks matching regular expressions - fix: if the html outputPath is a relative path, it is relative to
output.path
, not to CWD - fix: resolve
asset
module by 2ndnpm start
whencache.type
is'filesystem'
(usingmemory
type was OK) - chore: update the
eta
to the latestv3.1.0
version - docs: update README
- fix: when the Webpack
output.path
option is undefined, set the default path as CWD +/dist
- feat: add the
css.chunkFilename
option for output filename of non-initial chunk files - feat: add the
hotUpdate
option to enable/disable live reload in serve/watch mode - fix: missing an output css file when the same style file is imported in js and linked in html
- chore: add the "hello world" example
- chore: add simple-site example with automatically processing many HTML templates
- chore: add the Handlebars example
- chore: add react-app example, ejected from
create-react-app
(alpha version)
- fix: missing output html file after renaming template file in watch mode when using entry as a path
- chore: add example for bootstrap
- chore: update npm packages
- docs: update README
- feat: add the reference for
data
in the plugin options.
The NEW syntactic "sugar":The old syntax is still valid:new HtmlBundlerPlugin({ entry: { index: './src/views/home.ejs', }, // new reference to the loaderOptions.data data: {...}, }),
new HtmlBundlerPlugin({ entry: { index: './src/views/home.ejs', }, loaderOptions: { // original option is under loaderOptions data: {...}, }, }),
- refactor: code refactoring
- test: add more tests
- docs: update README
- feat: add support for Webpack CSS optimization
- fix: resolving the same resources used in imported styles on different pages
- fix: add the missing types.d.ts file to npm package
- feat: add support for TS
- docs: update README
- fix: correct importing styles in JS when used serve mode
- fix: importing the raw content of the html file in js
- fix: load the Handlebars's partials with allowed extensions only, #24
- feat: add the references for
preprocessor
andpreprocessorOptions
in the plugin options.
The NEW syntactic "sugar":The old syntax is still valid:new HtmlBundlerPlugin({ entry: { index: './src/views/home.ejs', }, // new references to options in the loaderOptions preprocessor: 'ejs', preprocessorOptions: {...}, }),
new HtmlBundlerPlugin({ entry: { index: './src/views/home.ejs', }, loaderOptions: { // original options are under loaderOptions preprocessor: 'ejs', preprocessorOptions: {...}, }, }),
- feat: improve performance when using the same style file in many templates
- fix: correct order of styles when the same style is imported in many nested js files
- chore: update npm packages
- chore: fix the image path in readme
- feat: add watching for create/rename/delete files in the entry path, without restarting Webpack
- fix: watching for create/rename/delete JS files
- fix: add to watching only parent directories, ignore all subdirectories
- fix: generate correct output filenames for assets in deep nested pages after changes in serve mode
- fix: in some cases is missing the hot-update.js file after changes in serve mode
- fix: missing slash in output filename when publicPath is an url without finishing slash
- test: add tests for new features and bug fixes
- chore: update npm packages
- docs: update readme
- fix: watching for create/rename Handlebars partials
- chore: update npm packages
- feat: add support for importing style files in JavaScript.
- feat(BREAKING CHANGE): upgrade the default preprocessor
eta
to next major version 3.0. Perhaps you may need to migrate your Eta templates to v3 syntax. - refactor: optimize source code
- fix: some invisible rare bug fixes
- test: add tests for new features and bug fixes
- chore: add code example how to use the tailwindcss
- chore: update npm packages
- docs: update readme
- feat: add the
js.chunkFilename
option - fix: do not delete split chunks from compilation loading dynamically
- fix: allow to define the
as
property of the preload option in the attributes, e.g.:{ test: /\.(ttf|woff2?)$/, attributes: { as: 'font', crossorigin: true }, },
- fix: correct parsing of a query where the key does not contain a value, e.g.
?enable&size=100
- refactor: code refactoring and optimization
- chore: small performance improvement due to code optimization
- chore: spelling corrections in code
- chore: update dev dependencies
- test: refactor tests to async run
- docs: update readme
- fix: live reload after changes if a template contains a commented out script
- fix: issue if a CSS file is imported in SCSS with a filename, including the
.css
extension, e.g.@import 'npm-module/styles.css'
- fix: issue if used the copy plugin which copies an HTML file
- fix: pass data via query parameters into template imported in JS file
template.htmlapp.js<div>Hello <%= name %>!</div>
import tmpl from './template.html?name=World'; // exports '<div>Hello World!</div>' document.body.innerHTML = html;
- test: add test for import a template in JS as rendered HTML string
- docs: update readme
- feat: allow the
data
loader option as a filename for dynamically loading global template variables - feat: allow the
data
entry-point option as a filename for dynamically loading page template variables - fix: inject hot update js file after changes when the template has no scripts
- docs: add description of new features
- feat: new compact verbose output, all resources are grouped by their issuers
- feat: remove
js.verbose
option, because it makes no sense with new verbose output (no breaking change) - feat: remove
css.verbose
option, because it makes no sense with new verbose output (no breaking change) - feat: improve performance
- fix: display loader dependencies only once in the watch mode
- fix: correct inline CSS and JS when is used minify, #8
- refactor: optimize processing for inline resources and preload tags
- chore: update packages
- docs: update readme
- feat: add the
views
option for thenunjucks
preprocessor - feat: allow to pass the configuration options for the
nunjucks
preprocessor - feat: automatically add to watching directories defined in the preprocessor options
root
views
partials
for example, several template directories are not subdirectories, but are on the same level:preprocessorOptions: { root: 'pages/', views: ['templates/layouts/', 'templates/includes/'], partials: ['templates/partials/'], }
- feat: add
root
loader option to allow use the/
as root path to source directory for asset files:to resolve thenew HtmlBundlerPlugin({ loaderOptions: { root: path.join(__dirname, 'src'), }, }),
/src/images/apple.png
source file, use the root path/
:<img src="/images/apple.png" />
- refactor: optimize code
- test: add tests for new features
- docs: add description of new features
- feat: add
preload
option to auto generate preload tags for resources such as font, image, video, audio, script, style, etc. - feat: allow resolving all duplicate scripts and styles in the template so that they can be preloaded with a link tag
- feat: remove warnings for duplicate script and styles in the template
- fix: set the default
removeRedundantAttributes: false
minify option to prevent styling bug when input "type=text" is removed - chore: update dev dependencies
- test: add tests for new features
- docs: add description of new features
- feat: add
minifyOptions
to customize minification when theminify
options isauto
, FR #5 - feat: add
helpers
value as array of a relative or absolute path to helper directories for thehandlebars
preprocessor - fix: allow the
partials
values to be relative paths for thehandlebars
preprocessor - test: add tests for new features
- docs: add description of new features
- feat: add the entry option value as a relative or absolute path to pages.
Template files matching thetest
option are read recursively from the path.
For example, there are files in the./src/views/pages/
Define the entry option as the relative path to pages:./src/views/pages/index.html ./src/views/pages/about/index.html ./src/views/pages/news/sport/index.html ./src/views/pages/news/sport/script.js ./src/views/pages/news/sport/style.scss ...
Internally, the entry is created with the templates matching to thenew HtmlBundlerPlugin({ entry: 'src/views/pages/', });
test
option:The output HTML filenames keep their source structure relative to the entry path.{ index: 'src/views/pages/index.html', // => dist/index.html 'about/index': 'src/views/pages/about/index.html', // => dist/about/index.html 'news/sport/index': 'src/views/pages/news/sport/index.html', // => dist/news/sport/index.html }
- fix: display an original error stack by nested exceptions
- feat: add the
data
loader option to pass global data into all templates
Note: use thedata
property of the entry option to pass data only in one templatenew HtmlBundlerPlugin({ entry: { index: { import: './src/home.html', data: { title: 'Home', // overrides the `title` defined in the loader data }, }, about: './src/about.html', }, loaderOptions: { data: { // <= NEW option to pass global variables for all pages title: 'Default Title', globalData: 'Global Data', }, }, });
- feat: add default template extensions:
.njk
.
The following default template extensions are now supported:/\.(html|ejs|eta|hbs|handlebars|njk)$/
- feat: add
preprocessor
value as stringnunjucks
to use the preconfigured Nunjucks compiler (nunjucks
package needs to be installed)new HtmlBundlerPlugin({ entry: { index: './src/views/pages/home.njk', }, loaderOptions: { preprocessor: 'nunjucks', // <= NEW 'nunjucks' value preprocessorOptions: { // async: true, // dafaults is false, to compile asynchronous templates set as true }, }, }),
- fix: handle unsupported value of the preprocessor option
- refactor: optimize preprocessor code
- chore: update dev dependencies
- docs: add description of new features
-
feat: add
preprocessorOptions
to the loader option to define a custom config for the default preprocessor.
For all options of the default preprocessor see https://eta.js.org/docs/learn/configuration#big-list-of-configuration-options.
Usage example:new HtmlBundlerPlugin({ entry: { index: './src/views/pages/home.html', }, loaderOptions: { preprocessorOptions: { // root path for includes with an absolute path (e.g., /file.html), defaults is process.cwd() root: path.join(process.cwd(), 'src/views/'), // directories that contain partials, defaults is undefined views: [ path.join(process.cwd(), 'src/views/layouts'), path.join(process.cwd(), 'src/views/partials'), ], }, }, }),
-
feat: add resolving a template partial relative to template. For example, there are templates:
src/views/pages/home.html - the main template src/views/pages/includes/gallery.html - the partial used in the main template
You can include the
src/views/pages/includes/gallery.html
partial inhome.html
using a relative path:<%~ includeFile('includes/gallery.html') %>
-
feat: add default template extensions:
.hbs
and.handlebars
.
The following default template extensions are now supported:/\.(html|ejs|eta|hbs|handlebars)$/
-
feat: add
preprocessor
value as stringejs
to use the preconfigured EJS compiler (ejs
package needs to be installed) -
feat: add
preprocessor
value as stringhandlebars
to use the preconfigured Handlebars compiler (handlebars
package needs to be installed).
ThepreprocessorOptions
hasHandlebars.compile
option plus additional options for the build-ininclude
helper:root {string}
- root path for includes with an absolute path (e.g., /file.html), defaultsprocess.cwd()
views {string|Array<strings>}
- directory or directories that contain templates.
For example:
preprocessorOptionsinclude a partial without an extension{ root: path.join(__dirname, 'src/views'), views: [ path.join(__dirname, 'src/views/includes'), ], }
{{ include '/partials/footer' }}
- the root path relative to defined in theroot
option
{{ include 'gallery' }}
- the relative path to defined in theviews
option- The following extensions will be automatically resolved by default:
.html
,.hbs
,.handlebars
.
Other options: partials {Object.<[name: string], [file: string]>}
- Use thepartials
as an object to define partials manually.
The key is apartial name
, the value is an absolute path of the partial.
For example:partials: { gallery: path.join(__dirname, 'src/views/includes/gallery.html'), 'menu/nav': path.join(__dirname, 'src/views/partials/menu/nav.html'), 'menu/top/desktop': path.join(__dirname, 'src/views/partials/menu/top/desktop.html'), },
partials {Array<string>}
- Usepartials
as an array of absolute paths to automatically find partials in these paths.
Files with the following extensions will be found recursively in the given paths:*.html
,*.hbs
,*.handlebars
.
For example:Note: thepartials: [ path.join(__dirname, 'src/views/includes'), path.join(__dirname, 'src/views/partials'), ],
partial name
is a complete relative path to a file without an extension. This is different from plugins, in which Id is a base directory and filename without extension.helpers {Object.<[name: string], function()>}
- the key is a helper name, the value is the helper function.
-
fix: inline a style from the
link
tag with the attributeas="style"
, e.g.:<link href="style.css?inline" rel="preload" as="style" />
-
fix: resolve a script in the
link
tag with theas="script"
or therel="modulepreload"
attributes, e.g.:<link href="script.js" rel="prefetch" as="script" /> <link href="script.js" rel="preload" as="script" /> <link href="script.js" rel="modulepreload" />
-
fix: keep output filename extension, different from
.html
, e.g.[name].php
, #4 -
refactor: optimize code
-
test: add tests for new features
-
docs: add description of new features
- feat: add
asset/source
support for SVG to inline it in HTML - test: add test to inline SVG using the
asset/source
type
- feat: add hot update file to HTML in serv mode when there is no script in template, to reload page after changes
- chore: update dev dependencies
- docs: update readme
- fix: extra fix for yarn fans. Yarn can't correctly install packages form standard npm peerDependencies. move the enhanced-resolve from peerDependencies into dependencies, it is needed for yarn only
- test: add test for resolving the source manifest.json
- fix: add the enhanced-resolve to peerDependencies
- chore: update dev dependencies
- docs: add links to demo examples
- fix: correct rebuild the node modules specified in a template or imported in a script, after changes in the template of in the script
- chore: update dev dependencies
- test: add test for rebuild the node modules
- fix: add missing node modules to compilation after rebuild
- fix: resolve resources in the entry file containing a query
- test: add tests for fixes
- fix: correct inline JS when used split chunks
- refactor: optimize code for windows, clean up from needless code
- test: add test for inline JS with split chunks
- test: refactor and clean up tests
- feat: add
css.inline
option, replaces the functionality ofstyle-loader
.
The values ofinline
option:- false - extract processed CSS in an output file, defaults
- true - inline processed CSS into HTML via
style
tag - 'auto' - in development mode - inline CSS, in production mode - extract in a file
- feat: add
js.inline
option to inline extracted JS into HTML - feat: add to the
?inline
query parameter for JS and CSS files the values:false
,true
,'auto'
.
Note: the query parameter takes precedence over globaljs.inline
orcss.inline
option. - fix: emit a loader exception as an instance of Error instead a string
- fix: throw exception when the loader is used but the
HtmlBundlerPlugin
is not initialized in Webpack plugins option - refactor: optimize and improve the code
- test: add tests for inline CSS and JS
- docs: update readme with new features
- fix: correct loader export when template contain CRLF line separators
- fix: correct resolve
auto
value forverbose
option
- fix: add LF after each generated script tag in dev mode for pretty HTML formatting
- feat: add the
loaderOptions
to the plugin option to allow defining loader options with the plugin. No need to additionally specify the template loader inmodule.rules
. You can specify plugin and loader options in one place, in plugin options. - feat(experimental): add the
cacheable
loader option to disable caching of loader results, can be useful in a specific use case - fix: the default
watchFiles.paths
value is now a first-level subdirectory of a template, relative to root context. E.g. the template path is./src/views/index.html
then the default watching dir is./src
. - fix: watching a changes in template partials
- test: add manual test for watching changes in partials used in multiple page configuration
- docs: update readme
- feat: display watch files in watch/serv mode when verbose option is enabled
- feat: add
auto
value for theverbose
option - refactor: improve the code structure
- test: add tests for watch mode
- chore: add GitHub test badge
- docs: improve readme
- fix: after an error, restore watching without restarting
- refactor: improve the loader code
- feat: add
watchFiles
option to configure paths and files to watch file changes
- fix: resolve correct output asset path when the publicPath is a URL
- docs: add description of important Webpack options used to properly configure the plugin
- feat: set the config option
root
of the Eta preprocessor as current working dir by defaults, now you can use the template root path, e.g.:<%~ includeFile('/src/views/partials/header') %>
- test: add test
async
preprocessor for Eta - docs: add
back to contents
navigation in readme, improve readme
- fix: resolving of assets under Windows
- docs: update readme
- fix: handling an issue when used an async preprocessor
- refactor: optimize handling of loader options
- test: add test case for issue in async preprocessor
- docs: improve readme
- feat: add support for both
async
andsync
preprocessor, the preprocessor should return a string or a promise. This can be used for async templating engines likeLiquidJs
,EJS
,Nunjucks
. - feat: add resolving of
href
attribute in the SVG<image>
and<use>
tags, by defaults<svg><image href="image.png"></image></svg> <svg><use href="icons.svg#home"></use></svg>
- feat: improve error handling in the loader
- fix: add only unique optional sources attribute
- test: add async tests for templating engines LiquidJS, EJS, Nunjucks
- core: update dev packages
- docs: add in readme description of new features
Defaults, HTML templates defined in the entry are processed via Eta (same EJS syntax) templating engine. If you have pure HTML file you can disable this processing to save the compilation time:
{
test: /\.html$/,
loader: HtmlBundlerPlugin.loader,
options: {
preprocessor: false, // <= disable default processing
},
},
- feat: add the default template loader in Webpack
module.rule
.
In most cases, the default loader options are used. You can omit the template loader inmodule.rule
, then the default template loader will be added automatically:{ test: /\.(html|ejs|eta)$/, loader: HtmlBundlerPlugin.loader, },
- feat: add the
Eta
templating engine (smaller and faster alternative toEJS
with same syntax) as the default preprocessor. If no preprocessor option is specified, Eta is used in the preprocessor. - feat: add
minify
option - test: add tests for the default loader and the default preprocessor
- fix: error by display verbose inlined module
- test: add verbose test when a module is inlined
- test: add manual test for multiple pages with inlined resources
- feat: improve verbose information output for extracted scripts
- fix: resolve scripts in diff pages generated from one template
- fix: warning for duplicate files when many html files are generated from one template
- refactor: optimise code structure, code cleanup
- refactor: optimize code for processing of scripts
- test: add base and advanced test template for new issues
- chore: add GitHub CONTRIBUTING.md
- chore: add GitHub PULL_REQUEST_TEMPLATE.md
- chore: add GitHub ISSUE_TEMPLATE
- chore: add SECURITY.md
- docs: update content structure, improve readme content
- fix: resolve filename containing a URI fragment, e.g.:
<use href="./icons.svg#home"></use>
- fix: resolve assets when the same file is used on many pages generated from the same template
- fix: pass data to template after changes when using HMR
- fix: by verbose display a file path relative by working directory instead of an absolute path
- refactor: code optimisation
- test: add tests for bugfixes
- docs: update readme
- BREAKING CHANGE: the 3rd argument
data
of thepreprocessor
has been moved to the 2nd argument as a property
v0.9.0
:preprocessor: (content, { resourcePath, data }) => {}
<= NEW syntax
v0.8.0
:preprocessor: (content, { resourcePath }, data) => {}
<= old syntax - fix: avoid an additional query param for internal use in the module's
resource
property - fix: remove info comments before inlined SVG
- docs: add description how to pass data into template using new option
entry
-
feat: add
entry
plugin option, this option is identical to Webpack entry plus additionaldata
property -
feat: add 3rd
data
argument of thepreprocessor
to pass template specific data:module.exports = { plugins: [ new HtmlBundlerPlugin({ entry: { // <= NEW `entry` option index: { import: 'src/views/template.html', data: { // <= NEW `data` property title: 'Home', }, }, }, }), ], module: { rules: [ { test: /\.(html)$/, loader: HtmlBundlerPlugin.loader, options: { preprocessor: (content, { resourcePath }, data) => { // <= NEW 3rd `data` argument return render(content, data); }, }, }, ], }, };
-
feat: support split chunk
- feat: add
postprocess
plugin option - fix: parse srcset attribute containing a query as JSON5, e.g.
srcset="image.png?{sizes: [100,200,300], format: 'jpg'}"
- test: add tests for options, responsive images, exceptions
- docs: update readme
- feat: add
sources
loader option to define custom tags and attributes for resolving source files - feat: add
extractComments
plugin option to enable/disable saving comments in *.LICENSE.txt file - feat: add to default resolving the
data
attribute ofobject
tag - feat: add supports the
responsive-loader
- fix: resolve exact attribute name w/o leading wildcard
- fix: resolve mutiline attributes
- fix: resolve mutiline values in srcset attribute
- test: add tests for new options, messages
- docs: update readme
- refactor: optimize code
- test: add test for usage
Nunjucks
template engine - docs: update readme for usage the multipage configuration with
Nunjucks
template engine
- feat: add
test
plugin option to process entry files that pass test assertion - feat: add
preprocessor
loader option to allow pre-processing of content before handling - test: add test for usage
Handlebars
template engine - docs: update readme with new features
- feat: add support for
<input>
<audio>
<video>
<track>
tags - fix: automatic publicPath must be empty string when used HMR
- fix: corrupted inline JS code when code contains
$$
chars chain
- refactor: optimize parsing of source
- chore: update dev packages
- docs: update readme
- feat: inline binary images, e.g. PNG
- feat: inline SVG images
- fix: resolve href in the
<link>
tag with the attributetype="text/css"
as the style file
- fix: resolving inlined styles on windows
- feat: add supports for the inline CSS in HTML
- feat: add supports for the inline JS in HTML
- test: add test for new features
- docs: update readme
First beta release:
- feat: handle HTML files from webpack entry
- feat: resolve the Webpack alias in the source file name
- feat: add
js
plugin option to extract JavaScript files from source scripts loaded in HTML via a<script>
tag and generates a separate file for it - feat: add
css
plugin option to extract CSS files from source styles loaded in HTML via a<link>
tag and generates a separate file for it - feat: process the images, fonts from sources loaded via
<link>
,<img>
or<source>
tags and generates a separate file for it - feat: resolve and extracts images from sources loaded via
url()
in a style (css, scss) - feat: resolve auto
publicPath
- docs: announcement of the plugin