html-webpack-plugin 4 has been released!
Jan Nicklas
Posted on March 23, 2020
It took way too long but finally the new major version of the html-webpack-plugin
is making it's leap from beta to a stable release!
Performance!
One big goal for this release was to improve the performance during development and production builds.
The performance boost was gained mainly by dropping the usage of compilation.getStats().toJson()
thanks to a new API provided by the webpack core team around @sokra. This new API provides all information necessary to inject the scripts and styles into the html code.
Unfortunately relying on that API means that webpack 1-3 can not be supported anymore.
To further increase the performance the entire caching approach was rebuilt from scratch to decrease the compilation efforts.
The alpha tester feedback was great!
#953 "The best of 5 total build time goes down from 10.41s (with 4.0.0-alpha) to 10.29s - which is now only 130ms slower than when not using the plugin at all :-)"
#962: "For reference, my project (which has grown substantially since #962) builds in ~8000ms without and ~1000ms with these changes."
While working on those performance improvements I wrote a cpuprofile-webpack-plugin - a small util to analyse your webpack build performance for production build but even more importantly for recompilations during development.
@addyosmani Have you been getting spammed about build speed questions?
Also:
🔥🕸️📦Use latest @webpack version
🔥🕸️📦Profile with @jantimon's cpuprofile-webpack-plugin
🔥🕸️📦Try out webpack v5 alpha to see the new build perf. improvements with persistent caching!
twitter.com/TheLarkInn/sta…23:53 PM - 11 Jul 2019Sean Thomas Larkin 廖肖恩 @thelarkinnOoo there's so many good ones for build speed not listed! 🔥📦🕸️ Limit usage of resolver capabilities (alias, modules, extensions) 🔥📦🕸️ Use /* webpackMode: "lazy-once" */ for import(`./some/${expr}`) in dev mode. 🔥📦🕸️ Use stats: errors-only if you don't need console feedback https://t.co/jPXfuOleR8
Feel free to give it a try and let me know what you think :)
Template language support
Since html-webpack-plugin 2.x has been able to use the loaders specified inside the webpack config file. Therefore it is not only capable of compiling .ejs
templates but any code which can be transpiled with a webpack loader (hbs
, ejs
, twig
, dust
, pug
, htl
, js,
ts,
jsx
, tsx
...).
A javascript or jsx template allows even to generate a static server side rendered version of your application.
html-webpack-plugin template:
import ReactDOMServer from 'react-dom/server';
import React from 'react';
import { App } from './App';
export default () => `
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Server Side Rendering Demo</title>
</head>
<body>
<div id="root">${ReactDOMServer.renderToString(<App />)}</div>
</body>
</html>
`
For further details on how to connect loaders to the html-webpack-plugin checkout the template option docs or take a look at the html-webpack-plugin jsx codesandbox.
Another way to use the html-webpack-plugin to prerender a static page out of your app is the prerender-loader from @developit.
Meta Tags
The html-webpack-plugin is now able to inject meta-tags without writing custom templates:
new HtmlWebpackPlugin({
meta: {viewport: 'width=device-width, initial-scale=1, shrink-to-fit=no'},
})
Base Tags
Similar to the meta tags it is now also possible to add a base tag:
new HtmlWebpackPlugin({
base: '/',
})
Custom Template with Zero Config
Customizing the template is now possible without configuration.
From version 4 the html-webpack-plugin will look for a local src/index.ejs
file. If such a file can be found it will be used as a template:
Minification by default
Thanks to the work by @edmorley we were able to enable html minification by default if webpack is running in production
mode. This behaviour can be disabled by adding minification: false
to the html-webpack-plugin configuration.
Enable minification by default when 'mode' is production #1048
Previously minification was disabled by default. Now, if minify
is undefined
and mode
is 'production'
, then it is enabled using the following options:
{
collapseWhitespace: true,
removeComments: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
useShortDoctype: true
}
These options were based on the settings used by create-react-app, Neutrino and vue-cli, and are hopefully fairly conservative. See: https://github.com/jantimon/html-webpack-plugin/issues/1036#issuecomment-421408841 https://github.com/kangax/html-minifier#options-quick-reference
These same defaults can enabled regardless of mode
, by setting minify
to true
(which previously passed an empty object to html-minifier, meaning most minification features were disabled). Similarly, minification can be disabled even in production, by setting minify
to false
.
This change has no effect on users who pass an object to minify
.
Fixes #1036.
Allow template variable modification
Evan You asked for a better way to modify which values are sent down to the template:
feat(template): support custom template params #830
This allows the user to inject custom variables to be used in the template interpolation, e.g. simplifying webpackConfig.output.publicPath
to something shorter.
Docs/tests are not included, but if this sounds like a good idea I can add those upon request.
The outcome was a new templateVariables
option which allows to add additional data e.g. process.env
to the values which are sent down to the template:
Nonblocking script loading
Until now all script tags were added at the end of the body tag.
However now that all modern browsers allow to load javascript in parallel without pausing the html parsing the scriptLoading
option can speed up your users page loads.
Usage:
new HtmlWebpackPlugin({
scriptLoading: 'defer'
})
New Hooks
The webpack core team asked to upgrade to the new hook system to further increase the webpack build speed.
These hooks allow plugin developers to change the default behaviour of the html-webpack-plugin. The following chart shows the flow and the hooks (beforeAssetTagGeneration
, alterAssetTags
, alterAssetTagGroups
, afterTemplateExecution
, beforeEmit
, afterEmit
):
Here is an example for a plugin which manipulates the generated html file in the beforeEmit
hook:
const HtmlWebpackPlugin = require('html-webpack-plugin');
class MyPlugin {
apply (compiler) {
compiler.hooks.compilation.tap('MyPlugin', (compilation) => {
// Static Plugin interface |compilation |HOOK NAME | register listener
HtmlWebpackPlugin.getHooks(compilation).beforeEmit.tapAsync(
'MyPlugin', // <-- Set a meaningful name here for stacktraces
(data, cb) => {
// Manipulate the content
data.html += 'The Magic Footer'
// Tell webpack to move on
cb(null, data)
}
)
})
}
}
module.exports = MyPlugin
For more information please take a look at the readme events section
Contributors
People around the world are approaching me to ask for help, suggest and work on new features, fix a typo or even fix entire problems. Thank you so much and please keep it up! :)
If you have any feedback for this release create an issue or contact me on twitter @jantimon (direct messages are open).
Sponsors
Big thanks to all the sponsors who supported the development over the last years.
Especially TipeIO and Principal Financial Services, Inc
Full changelog
The changelog with all changes can be found directly on github
What is coming up next?
The next goal is to be fully compatible with the Webpack 5. Especially with the new Webpack 5 FileSystemInfo
API to solve
Webpack 5 Support Plan? #1269
The webpack 5.0 changelog https://github.com/webpack/changelog-v5/blob/master/README.md
.
Another goal would be to further improve browser load times. For browsers with support for preloading @sokra proposed an even faster approach than scriptLoading: 'defer'
.
Posted on March 23, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.