Html-webpack-plugin: Inject Webpack Manifest

Created on 15 Dec 2015  路  18Comments  路  Source: jantimon/html-webpack-plugin

After looking through the code it looks like it would not be extremely hard to add this functionality. What it would do is extract the chunk manifest from the webpack stats and insert it into the HTML with a given variable name, and then removed from the bootstrap entry chunk to allow for long term caching of assets.

See https://github.com/diurnalist/chunk-manifest-webpack-plugin for how to extract the correct data and how to remove the manifest from the entry chunk.

The reason I don't use the existing plugin is due to the fact that I need to add the manifest manually after each build. I feel this goes hand in hand with the html-webpack-plugin because now I can inject my hashed chunks and the manifest which will allow me to cache my chunks and only bust the cache for chunks that have changed instead of busting the cache for the entry chunk every time as it contains the manifest.

enhancement

Most helpful comment

For anyone else who finds this issue and wonders how to adapt @kevinrenskers solution to version 2 of this plugin (plugin version >= 2.10.0 is needed, so that compilation is available in templateParams):

In webpack config:

var config = {
    // ...

    plugins: [
        // ...
        new ChunkManifestPlugin({
            filename: "manifest.json",
            manifestVariable: "webpackManifest"
        }),
        new HtmlWebpackPlugin({
            template: './src/index.html.js', // input
            filename: 'index.html', // output (relative to output path)
            inject: 'body' // inject script tags at end of body
        })
    ]
};

In index.html.js:

module.exports = function(templateParams) {
    var manifestSource = templateParams.compilation.assets['manifest.json'].source();

    // remove manifest.json from assets so it won't be written to disk
    delete templateParams.compilation.assets['manifest.json'];

    return `<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Inline Manifest</title>
    </head>
    <body>
        <div id="app"></div>
        <script type="text/javascript">window.webpackManifest=${manifestSource};</script>
    </body>
</html>`;
};

All 18 comments

Maybe we could fire an event and move this part into another plugin?

@cnatis Maybe you can use appcache-webpack-plugin to insert manifest file into html template, like:

<html manifest="<%= htmlWebpackPlugin.options.MANIFEST_FILENAME %>">
...
</html>

@kerryChen95 I am looking to inject the webpack chunk manifest so I can have deterministic hashes on my chunks, enabling me to cache them knowing that the chunks hash will change only when the contents have changed. Webpack currently injects its manifest into the entry chunk causing it's hash to change even if its contents do not.

With this feature I can automatically inject the webpack chunk manifest into the index HTML file and my chunk hashes will only change if the contents change, put the hash in the filename and cache forever knowing the second a change occurs the cache will be effectively busted.

For clarification, Appcache manifest and Webpack chunk manifest are not the same.

I'm still using version 1.7.0 of html-webpack-plugin and I'm inlining the manifest like this:

in my webpack config:

    new HtmlWebpackPlugin({
      excludeChunks: ['manifest'],
      templateContent: function(templateParams, compilation) {
        Object.keys(compilation.assets).forEach((key) => {
          if (key.indexOf('manifest.') === 0) {
            if (compilation.assets[key].children) {
              templateParams.chunkManifest = compilation.assets[key].children[0]._value;
            }
            delete compilation.assets[key];
          }
        });

        var indexTemplate = fs.readFileSync(path.resolve('./src/index.html'), 'utf8');
        var tmpl = require('blueimp-tmpl').tmpl;

        return tmpl(indexTemplate, templateParams);
      },
      minify: {
        removeComments: true,
        collapseWhitespace: true
      }
    }),

in my index.html:

{% if(o.chunkManifest) { %}
<script>{%#o.chunkManifest%};</script>
{% } %}

You can see an example project here. It's my solution to proper chunk hashes that don't change every time you add or remove modules to your app.

But yeah it would be great if html-webpack-plugin had support to inline certain assets / chunks, instead of doing this manually like this.

I also have made a Pull Request to support inlining compiled assets into html template

191 provide a complete solution by which you can create an JS file containing webpack manifest and then inline it into html template

For anyone else who finds this issue and wonders how to adapt @kevinrenskers solution to version 2 of this plugin (plugin version >= 2.10.0 is needed, so that compilation is available in templateParams):

In webpack config:

var config = {
    // ...

    plugins: [
        // ...
        new ChunkManifestPlugin({
            filename: "manifest.json",
            manifestVariable: "webpackManifest"
        }),
        new HtmlWebpackPlugin({
            template: './src/index.html.js', // input
            filename: 'index.html', // output (relative to output path)
            inject: 'body' // inject script tags at end of body
        })
    ]
};

In index.html.js:

module.exports = function(templateParams) {
    var manifestSource = templateParams.compilation.assets['manifest.json'].source();

    // remove manifest.json from assets so it won't be written to disk
    delete templateParams.compilation.assets['manifest.json'];

    return `<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Inline Manifest</title>
    </head>
    <body>
        <div id="app"></div>
        <script type="text/javascript">window.webpackManifest=${manifestSource};</script>
    </body>
</html>`;
};

@skleeschulte maybe you could turn this into a stand alone plugin?

Maybe this is a good startpoint: https://github.com/jantimon/favicons-webpack-plugin/blob/f80d8c260691848b41d7ce3fabfc317cd43f7968/index.js#L56-L64

IMO its not really worth the effort to create a plugin for this + a plugin would mean a loss in flexibility. Maybe it should be documented in a more prominent place?

I guess you are right.. it looks like chunk-manifest-webpack-plugin isn't maintained anymore..

Maybe... But it's still working fine for me with the latest webpack version, it is referenced in the webpack docs and is still downloaded a lot from npm...

@jantimon try to use Inline Manifest Webpack Plugin

So, is there any simple solution now?

Cp. #600

@csentis, thanks!

@csentis, unfortunately I have an issue with that plugin https://github.com/jouni-kantola/inline-chunk-manifest-html-webpack-plugin/issues/3
:(

Thank you for reporting, @pavel06081991!

Example template, after update of inline-chunk-manifest-html-webpack-plugin (now v0.2.0):

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <h1>My web site</h1>
    <%=htmlWebpackPlugin.files.webpackChunkManifest%>
    <%=htmlWebpackPlugin.files.webpackManifest%>
  </body>
</html>

The default is that chunk manifest is injected into head. When inject: false is passed to html-webpack-plugin the chunk manifest can be injected by using <%=htmlWebpackPlugin.files.webpackChunkManifest%>.

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ruoyiqing picture ruoyiqing  路  3Comments

azat-io picture azat-io  路  4Comments

laruiss picture laruiss  路  3Comments

var-bp picture var-bp  路  3Comments

lonelyclick picture lonelyclick  路  3Comments