DanielSchaffer/webpack-babel-multi-target-plugin

Error normalizing CSS files

Closed this issue · 4 comments

When running a build I get the following error:

75% basic chunk optimization BabelMultiTargetPlugin(node:11621) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'reasons' of undefined
  at chunk.modulesIterable.forEach.module (/home/ranger/some-project/node_modules/webpack-babel-multi-target-plugin/src/normalize.css.chunks.plugin.js:46:49)
  at Set.forEach (<anonymous>:null:null)
  at chunks.forEach.chunk (/home/ranger/some-project/node_modules/webpack-babel-multi-target-plugin/src/normalize.css.chunks.plugin.js:41:35)
  at Array.forEach (<anonymous>:null:null)
  at NormalizeCssChunksPlugin.extractCssChunks (/home/ranger/some-project/node_modules/webpack-babel-multi-target-plugin/src/normalize.css.chunks.plugin.js:26:16)
  at SyncBailHook.eval (<anonymous>:12:16)
  at SyncBailHook.lazyCompileHook [as _call] (/home/ranger/some-project/node_modules/tapable/lib/Hook.js:35:21)
  at Compilation.seal (/home/ranger/some-project/node_modules/webpack/lib/Compilation.js:1205:35)
  at hooks.make.callAsync.err (/home/ranger/some-project/node_modules/webpack/lib/Compiler.js:547:17)
  at _done (<anonymous>:9:1)
  at _fn4.then._result4 (<anonymous>:64:22)
  at <anonymous>:null:null
  at process._tickDomainCallback (internal/process/next_tick.js:229:7)

(node:11621) 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: 3)
(node:11621) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Whups, sorry about that! Funny, I've even got a FIXME on that in the source:

image

Unfortunately, simply adding a null check won't be enough since it needs the data that's missing. Any chance you can publish a small repro?

I'm getting some other error now, didn't find the the time yet to find out which chunk this is coming from:

clean-webpack-plugin: /home/ranger/some-project/dist/*.* has been removed.
 75% basic chunk optimization BabelMultiTargetPlugin(node:2907) UnhandledPromiseRejectionWarning: Error: Could not determine entry module for chunk null
  at NormalizeCssChunksPlugin.getEntryModule (/home/ranger/some-project/node_modules/webpack-babel-multi-target-plugin/src/normalize.css.chunks.plugin.js:90:15)
  at chunks.forEach.chunk (/home/ranger/some-project/node_modules/webpack-babel-multi-target-plugin/src/normalize.css.chunks.plugin.js:41:38)
  at Array.forEach (<anonymous>:null:null)
  at NormalizeCssChunksPlugin.extractCssChunks (/home/ranger/some-project/node_modules/webpack-babel-multi-target-plugin/src/normalize.css.chunks.plugin.js:26:16)
  at SyncBailHook.eval (<anonymous>:12:16)
  at SyncBailHook.lazyCompileHook [as _call] (/home/ranger/some-project/node_modules/tapable/lib/Hook.js:35:21)
  at Compilation.seal (/home/ranger/some-project/node_modules/webpack/lib/Compilation.js:1205:35)
  at hooks.make.callAsync.err (/home/ranger/some-project/node_modules/webpack/lib/Compiler.js:547:17)
  at _done (<anonymous>:9:1)
  at _fn4.then._result4 (<anonymous>:64:22)
  at <anonymous>:null:null
  at process._tickDomainCallback (internal/process/next_tick.js:229:7)

(node:2907) 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: 1)
(node:2907) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

A question aside from this issue: As far as I understand everything involved, your plugin's method of duplicating entry points, will not generate 'modern' and 'legacy' chunks for any lazy-loaded parts of an application.
From my understanding your plugin won't produce the desired result for any project that uses code splitting through dynamic imports because there will be only one chunk (either in ES5 or ES2015). Am I right about this? Do you have any idea how one might work around this?

@rangermeier to be honest, I'm not entirely sure. I've only been using this technique with TypeScript, where, unless I'm misunderstanding, dynamic imports aren't a thing.

I'd have to add another example project to really know for sure, but it depends on how the dependency tree is generated and walked. The duplicating method works because each module has its hierarchy of parents, and you can walk up that hierarchy all the way to the entry point. It's possible that this could still work for dynamic imports as well - they have to come from somewhere, and that somewhere would have the context data needed to determine which entry it's coming from (modern/legacy).

Where that falls down is with something where that context is lost - for example, there is special logic for dealing with lazy routes generated by Angular's routing system. In that case, the plugin doesn't get any of the aforementioned context since these requests are created by the Angular compiler, so I give it a "blind target": I assume that for any given module, I'll be getting one request for each target (since the dependency that triggers the lazy route is still targeted - it just doesn't retain any of that information) - so I just create an array for each request that contains each of the targets, and assign a target based on what's left in the array.

If the plugin doesn't work out of the box with dynamic imports, I'm pretty sure that they can be handled by detecting them and applying a similar method.

Update: I just tried it and it doesn't work -- it just emits the one file.

Update 2: I was able to get it working by using the "blind targeting" method I described above. The way it works is that if it runs into a module that doesn't have a target, AND it's using BabelMultiTargetPlugin.loader (to limit this logic to javascript-y file types and avoid targeting things like pug template files), it'll assign it a blind target. Try it out in v1.0.1-alpha.2