Imports with expression cause infinite loop when called inside a dynamic import
Closed this issue ยท 6 comments
With Webpack you can define an import with any expression in the name e.g.
import(`./plugins/${pluginName}/plugin.js`);
I've run into an issue with this plugin (via the configuration from open-wc/building-webpack), where I find that imports like the one above do not work if they are themselves defined inside of a file which is imported dynamically.
I receive the following error:
(node:18564) UnhandledPromiseRejectionWarning: RangeError: Maximum call stack size exceeded
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:105:23)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
at NormalizeCssChunksPlugin.getEntryFromModule (C:\EWB\Code\dynamic_bug\node_modules\webpack-babel-multi-target-plugin\dist\src\normalize.css.chunks.plugin.js:110:25)
I've tried to debug the issue in your code but don't understand webpack plugins enough.
I have however created a simple case which reproduces the problem:
https://gist.github.com/ggriffithsIDBS/f61f475831f4beef02e1d58f5f960e2d
or see zip
dynamic_bug.zip
Please let me know if you need any more information, i'll let the people whose config i've been using know i've run into this issue
@ggriffithsIDBS Hi, thanks for the report and the repro! I'll try and take a look this week.
Just for some context, in case you want to take another look at debugging:
NormalizeCssChunksPlugin
is responsible for de-duping any CSS modules that are generated by the app (e.g. so you get a single styles.css
module instead of both styles.modern.css
and styles.legacy.css
, for example). That particular part of the code that's getting hung up is trying, as the stack trace suggests, to figure out the name of the entry point for chunk that it found.
Admittedly, and unsurprisingly, this is one of the more brittle parts of the plugin. as you can see in the code and comments for findEntryModule
, there are so many different use cases, and so many ways the hierarchy of chunk and dependencies and modules can end up. Ultimately, it's just trying to find a chunk somewhere in its hierarchy that has an entryModule
defined.
If you're interested in taking another look, what I've done in the past is just set a breakpoint in findEntryModule
, and then used my IDE to browse the module/chunk objects and hierarchy until I could find what I was looking for. Then, I just wrote code that could do the same programmatically.
@ggriffithsIDBS Sorry for the delay - just got the chance to sit down with this today. I wasn't able to reproduce the error. I didn't use the repro you included since the dynamic_feature
variable you reference isn't actually declared or set anywhere, so I'm not sure how that would be expected to work. I added an import to the existing es6-dynamic-import
example using the same pattern, and it seems to work fine - you can check out the branch (https://github.com/DanielSchaffer/webpack-babel-multi-target-plugin/tree/feature/23-expression-dynamic-import) and run locally yourself:
- Run
npm install
to install the plugin dependencies - Run
npm run install-examples
to install dependencies for the example projects - Run
npm start es6-dynamic-import
to start a dev server for thees6-dynamic-import
example - Open http://localhost:3002/examples/es6-dynamic-import in your browser to view the example.
- Open http://localhost:3002/examples/es6-dynamic-import?plugin=b to load the
b
plugin instead of thea
plugin.
For me, this results in either plugin a
or plugin b
being logged to the console, respectively. If you're still running into the above error, could you adapt the example so that it reproduces the error?
@DanielSchaffer thanks for looking into this, I created a pr on your branch which adjusts the code to reproduce the problem.
I had a few issues building the code, i'm a windows user, so I had to have Ubuntu for windows save me ๐
@Georgegriff I think I've fixed the main underlying issue in c99dc19 - I'm working on some further improvements so that you can have better control over the naming of the resulting chunks:
- Adapting the included
NamedLazyChunksPlugin
to work with ES6 dynamic imports: this will basically take the filename and use it for the chunk name - though it would work better if the plugin files themselves were uniquely named (e.g.plugin-a.js
instead ofa/plugin.js
) - More internal updates/fixes so that Webpack's inline chunk naming (e.g.
import(/* webpackChunkName: "[request]" */`./plugin/${plugin}`)
) works more correctly - currently it appears to merge both legacy and modern versions into the same file
Sounds good, for some background where the same named files comes from, it comes from our architecture where we selectively load features from a json API e.g. features : ["save","edit","search"]
ultimately this results in a dynamic import in the form of import(`plugins/${features[i]}/plugin.js`)
lets us do lazy loaded features of the UI that are driven by backend permissions.