html-webpack-plugin: compilation.getAssetPath is not a function when using yarn workspaces

Expected behaviour

The way webpack version is resolved to determine which api to use in L162 and L540 delegates to nodejs the wepack resolution, this causes version mismatch in cases where the dependencies are hoisted. It should resolve the webpack.config.js where was required to determine the api version.

https://github.com/jantimon/html-webpack-plugin/blob/19b5122746c0a34c4a341ad1758eb743c87a4c55/index.js#L30

Current behaviour

This error is produced because @storybook/react uses a wepack@4.44.2 version, and html-webpack-plugin is picking the root webpack@5.3.2 instead of the local one.

(node:50947) UnhandledPromiseRejectionWarning: TypeError: compilation.getAssetPath is not a function
    at compiler.hooks.emit.tapAsync (.../cnix-ui/node_modules/html-webpack-plugin/index.js:164:25)
    at AsyncSeriesHook.eval [as callAsync] (eval at create (.../cnix-ui/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:27:1)
    at AsyncSeriesHook.lazyCompileHook (.../cnix-ui/node_modules/tapable/lib/Hook.js:154:20)
    at Compiler.emitAssets (.../cnix-ui/node_modules/@storybook/core/node_modules/webpack/lib/Compiler.js:491:19)
    at onCompiled (.../cnix-ui/node_modules/@storybook/core/node_modules/webpack/lib/Watching.js:51:19)
    at hooks.afterCompile.callAsync.err (.../cnix-ui/node_modules/@storybook/core/node_modules/webpack/lib/Compiler.js:681:15)
    at AsyncSeriesHook.eval [as callAsync] (eval at create (.../cnix-ui/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:15:1)
    at AsyncSeriesHook.lazyCompileHook (.../cnix-ui/node_modules/tapable/lib/Hook.js:154:20)
    at compilation.seal.err (.../cnix-ui/node_modules/@storybook/core/node_modules/webpack/lib/Compiler.js:678:31)
    at AsyncSeriesHook.eval [as callAsync] (eval at create (.../cnix-ui/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:9:1)
    at AsyncSeriesHook.lazyCompileHook (.../cnix-ui/node_modules/tapable/lib/Hook.js:154:20)
    at hooks.optimizeAssets.callAsync.err (.../cnix-ui/node_modules/@storybook/core/node_modules/webpack/lib/Compilation.js:1423:35)
    at AsyncSeriesHook.eval [as callAsync] (eval at create (.../cnix-ui/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:9:1)
    at AsyncSeriesHook.lazyCompileHook (.../cnix-ui/node_modules/tapable/lib/Hook.js:154:20)
    at hooks.optimizeChunkAssets.callAsync.err (.../cnix-ui/node_modules/@storybook/core/node_modules/webpack/lib/Compilation.js:1414:32)
    at AsyncSeriesHook.eval [as callAsync] (eval at create (.../cnix-ui/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:9:1)
(node:50947) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 8)

Environment

darwin 19.6.0
npm 6.13.4

yarn list webpack 
warning Filtering by arguments is deprecated. Please use the pattern option instead.
├─ @storybook/addon-docs@6.0.28
│  └─ webpack@4.44.2
├─ @storybook/react@6.0.28
│  └─ webpack@4.44.2
└─ webpack@5.3.2
✨  Done in 1.45s.

yarn list html-webpack-plugin
warning Filtering by arguments is deprecated. Please use the pattern option instead.
└─ html-webpack-plugin@4.5.0
✨  Done in 1.10s.

Posible Solution

It would be more simple if instead of use the version matching use a fallback call providing the newest api definition firts, ie:

--- html-wepack-plugin.cur	2020-11-01 12:19:09.450509028 +0100
+++ node_modules/html-webpack-plugin/index.js	2020-11-01 12:19:16.304563095 +0100
@@ -161,9 +161,8 @@
           hash: templateResult.mainCompilationHash
         };
 
-        const childCompilationOutputName = webpackMajorVersion === 4
-          ? compilation.mainTemplate.getAssetPath(this.options.filename, compiledEntries)
-          : compilation.getAssetPath(this.options.filename, compiledEntries);
+        const getAssetPath = (compilation.getAssetPath || compilation.mainTemplate.getAssetPath).bind(compilation);
+        const childCompilationOutputName = getAssetPath(this.options.filename, compiledEntries);
 
         // If the child compilation was not executed during a previous main compile run
         // it is a cached result

or even better if there is a global call polyfill like this:

const getAssetPath = (compilation, ...args) => compilation.getAssetPath ? compilation.getAssetPath(...args) : compilation.mainTemplate.getAssetPath(...args);

Another solution to keep the logic untouched would be resolve webpack version taking in mind which component is requiring this module, ie @storybook/react is requiring in its webpack config so resolving the webpack from the parent module will obtain the version used in webpack.config.js, but this is potentially dangerous and deprecated. so in favor of simplify the logic the polyfill solution would be the best choice.

Relevant Links

PR https://github.com/jantimon/html-webpack-plugin/pull/1547

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 4
  • Comments: 15 (3 by maintainers)

Most upvoted comments

use yarn add html-webpack-plugin@next -D, this resolve

Thanks for the help above. I ran into this in my Storybook build job as well today.

npx build-storybook --output-dir storybook-static/src

Errors:

TypeError: compilation.getAssetPath is not a function

Resolved it by manually adding this dependency:

npm install html-webpack-plugin --save-dev

Feels like a bandaid, but it works for now.

is there a solution here that doesn’t require installing an unnecessary dependency? with server-side rendering, i’m not using html-webpack-plugin

@deeborges @jantimon , usei yarn add html-webpack-plugin@next -De agora estou "html-webpack-plugin": "^5.0.0-beta.6",no meu package.jsonmas ainda com rodando yarn storybookenfrento erro relatado.

check this project that I structured with webpack and storybook https://github.com/deeborges/archetype-react

@Robbie-Cook yes I am trying to release it as @latest soon.