html-webpack-plugin: Can't get assets by entry point chunk name in v4

Congrats on the new major version guys.

Expected behaviour

In v3, it was possible to obtain chunk assets by accessing htmlWebpackPlugin.files.chunks[entryName].entry from the template.

Current behaviour

According to https://github.com/jantimon/html-webpack-plugin/blob/master/CHANGELOG.md#breaking-changes there’s a breaking change affecting such feature:

The chunks property was removed and the js and css property was converted from a string into an object { entryName: string, path: string}

According to that, one would expect js and css properties in htmlWebpackPlugin.files to contain the mentioned object but I still get the same array of strings as in v3:

{
  ...,
  "files": {
    "publicPath": "",
    "js": [
      "scripts/main.js",
      "scripts/service-worker.js",
      "scripts/ping-worker.js"
    ],
    "css": [
      "styles/main.css"
    ]
  },
  ...
}

Environment

Tell us which operating system you are using, as well as which versions of Node.js, npm, webpack, and html-webpack-plugin. Run the following to get it quickly:

~/projects/lag (dependabot/npm_and_yarn/html-webpack-plugin-4.0.1, Node v12.11.1)
❯ node -e "var os=require('os');console.log('Node.js ' + process.version + '\n' + os.platform() + ' ' + os.release())"
npm --version
npm ls webpack
npm ls html-webpack-plugin
Node.js v12.11.1
darwin 19.3.0

~/projects/lag (dependabot/npm_and_yarn/html-webpack-plugin-4.0.1, Node v12.11.1) ❯ npm --version npm ls webpack npm ls html-webpack-plugin 6.13.7

~/projects/lag (dependabot/npm_and_yarn/html-webpack-plugin-4.0.1, Node v12.11.1) ❯ npm ls webpack npm ls html-webpack-plugin lag@0.0.0 /Users/frosas/projects/lag └── webpack@4.42.0

~/projects/lag (dependabot/npm_and_yarn/html-webpack-plugin-4.0.1, Node v12.11.1) ❯ npm ls html-webpack-plugin lag@0.0.0 /Users/frosas/projects/lag └── html-webpack-plugin@4.0.1

Config

Copy the minimal webpack.config.js to produce this issue:

https://github.com/frosas/lag/blob/f82961175485b1540cefc7f48bc251dad83df10b/webpack.config.js#L55-L71

Copy your template file if it is part of this issue:

https://github.com/frosas/lag/blob/f82961175485b1540cefc7f48bc251dad83df10b/html/index.ejs

Additional context

I couldn’t find any reference to entryName in the plugin code that suggested the new behavior was actually implemented.

Also, htmlWebpackPlugin.files section in https://github.com/jantimon/html-webpack-plugin/blob/master/README.md seems outdated now.

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 6
  • Comments: 15 (7 by maintainers)

Commits related to this issue

Most upvoted comments

Any updates about this issue?

I don’t know if I am following these commits properly, but it looks like they’re not going the way the discussion here was going, and more like the opposite! @jantimon the files.chunks object property was quite useful in earlier versions specially for SPAs. Is this still something you consider rethinking a solution for?

I just upgraded from v3 to v5 and ran into this issue. This was part of a larger effort to upgrade to Webpack 5. The removal of the chunks property from the template context was the most difficult part of the upgrade.

I ended up writing a backwards compatibility plugin however this is far from complete.

class HtmlWebpackBackwardsCompatibilityPlugin {
  apply(compiler) {
    compiler
      .hooks
      .compilation
      .tap("HtmlWebpackBackwardsCompatibilityPlugin", compilation => {
        HtmlWebpackPlugin
          .getHooks(compilation)
          .beforeAssetTagGeneration
          .tapAsync("HtmlWebpackBackwardsCompatibilityPlugin", (data, callback) => {
            const { publicPath } = data.assets;
            data.assets.chunks = {};

            for (const entryPoint of compilation.entrypoints.values()) {
              for (const chunk of entryPoint.chunks) {
                data.assets.chunks[chunk.name] = {
                  entry: chunk.files
                    .map(file => publicPath + file)
                    .find(file => file.endsWith(".js"))
                };
              }
            }

            callback(null, data);
          }
        );
      });
  }
}

There is a lot of logic that would need to be copied from https://github.com/jantimon/html-webpack-plugin/blob/d5ce5a8f2d12a2450a65ec51c285dd54e36cd921/index.js#L629 in order to make this complete, e.g. chunk sorting, proper chunk filtering, public path resolution, hot module replacement, etc.

In our index.ejs file we need to be able to look up, and filter, a chunk entry by name. Not all of our chunks are simply loaded as script tags.

Given the barrier to upgrade by either rearchitecting our chunk loading strategy or writing a custom Webpack plugin to duplicate the logic in the HTMLWebpack plugin I think it makes sense for this plugin to add back the chunks property in some form of deprecated manor or to provide an API that allows listing and indexing chunks in the template context.

Reposting in right ticket.

So…

Doing

  <!--
    // DEBUG
    <%= JSON.stringify(htmlWebpackPlugin.files, null, 1) %>
  -->

in template will reveal structure such as this in 3.2.0

<!--
    // DEBUG
    {
 "publicPath": "assets/",
 "chunks": {
  "runtime": {
   "size": 0,
   "entry": "assets/runtime.8379fd9de1396362f7d6.js",
   "hash": "2ca3c4b7e4ed2cdacddd",
   "css": []
  },
  "vendors": {
   "size": 1155526,
   "entry": "assets/vendors.eb616a137720b1a65dd4.js",
   "hash": "9ef5ffdd5a6b634a2d3d",
   "css": []
  },
  "corepoly": {
   "size": 88179,
   "entry": "assets/corepoly.0cf265cbf5506d68f293.js",
   "hash": "b2a7eccd9d2fa4b53fd6",
   "css": []
  },
  "index": {
   "size": 682872,
   "entry": "assets/index.a8a382748a1236847da2.js",
   "hash": "ff015be1159991382c21",
   "css": [
    "assets/index.5728905c20b76099151d.css"
   ]
  }
 },
 "js": [
  "assets/runtime.8379fd9de1396362f7d6.js",
  "assets/vendors.eb616a137720b1a65dd4.js",
  "assets/corepoly.0cf265cbf5506d68f293.js",
  "assets/index.a8a382748a1236847da2.js"
 ],
 "css": [
  "assets/index.5728905c20b76099151d.css"
 ]
}
  -->

however in 4.x it generates

<!--
    // DEBUG
    {
 "publicPath": "assets/",
 "js": [
  "assets/runtime.8379fd9de1396362f7d6.js",
  "assets/vendors.63498add9423ff0ff9a0.js",
  "assets/corepoly.b51addbe29703dc78ebb.js",
  "assets/index.9eca6c1781f27940f1de.js"
 ],
 "css": [
  "assets/index.5728905c20b76099151d.css"
 ]
}
  -->

thus in 4.0 it is not as shown in docs https://github.com/jantimon/html-webpack-plugin#writing-your-own-templates which shows

"htmlWebpackPlugin": {
  "files": {
    "css": [ "main.css" ],
    "js": [ "assets/head_bundle.js", "assets/main_bundle.js"],
    "chunks": {
      "head": {
        "entry": "assets/head_bundle.js",
        "css": [ "main.css" ]
      },
      "main": {
        "entry": "assets/main_bundle.js",
        "css": []
      },
    }
  }
}

Thus template that worked with 3.2.0

<% for (let key in htmlWebpackPlugin.files.chunks) { %>
   <script src="<%= htmlWebpackPlugin.files.chunks[key].entry %>"></script>
<% } %>

does not work any more with 4.0. Just as the OP states.

So what is the supposed way to get chunks in template in v4?

The original feature seems to be quite popular (https://github.com/search?q=htmlWebpackPlugin.files.chunks&type=Code), would it be possible to maintain backwards compatibility to make the upgrade process as easy as possible to all? Happy to discuss alternatives if not 😃

@jantimon This seems to still be an issue, do you have any plan to provide some way how to get common chunk names?

I will not remove or change the existing structure but probably extend it in some way to allow accessing the chunkname and source of the files to allow inlining again

Sorry for the confusion you are right only chunks was removed.

The new structure is:

https://github.com/jantimon/html-webpack-plugin/blob/c5a58824b8d33c3f9b85d1f541a27844a62721e4/typings.d.ts#L149-L171

The easiest way to output all head tags is:

<%= htmlWebpackPlugin.tags.headTags %>
<%= htmlWebpackPlugin.tags.bodyTags %>

@kroko I am very sorry but right now <%= htmlWebpackPlugin.chunks is no longer supported anymore as explained here: https://github.com/jantimon/html-webpack-plugin/issues/1369#issuecomment-604382645

I have some solutions in mind but it will take me a moment to implement it (as I am doing that in my spare time).

Thanks for bringing up the issue with the outdated documentation 👍