webpack-babel-multi-target-plugin
webpack-babel-multi-target-plugin copied to clipboard
Ignores dynamic import css chunks generated via mini-css-extract-plugin
Hello, seems like this plugin can't output dynamic import css chunks generated via mini-css-extract-plugin. I am using version 2.3.1-next.1 (Windows 10) to overcome #38 #39
Please see this repo for further details: https://github.com/bitfella/webpack-babel-multi-target-plugin-test
Thanks!
@bitfella can you elaborate a little on what's going on? Are you seeing any errors? If not, what behavior are you expecting that is not happening? I'm not seeing any build errors on Mac (waiting for a Windows VM to download currently).
If this is a Windows-only issue, it's possible that you're also running into the root cause of #39 (see the ongoing discussion there) - and if that's the case, try updating to next.3
.
@DanielSchaffer hi, no console errors whatsoever. Simply It does not spit out dynamic import css chunks. If I remove webpack-babel-multi-target-plugin in my example repo, everything works as expected (dynamic import css chunks are correctly generated). I will try next.3 as soon as I get back to the office (I got no Windows PC at home).
Thanks!
@DanielSchaffer updated to next.3
as you suggested, but unfortunately the build process fails this time. See log:
C:\Migu\webpack-babel-multi-target-plugin-test\node_modules\webpack-cli\bin\cli.js:93
throw err;
^
SyntaxError: Invalid regular expression: /node_modules\\(webpack\)-dev-server/: Unterminated group
at new RegExp (<anonymous>)
at excludeNodeModulesPackage (C:\Migu\webpack-babel-multi-target-plugin-test\node_modules\webpack-babel-multi-target-plugin\dist\src\excluded.packages.js:8:12)
at Object.<anonymous> (C:\Migu\webpack-babel-multi-target-plugin-test\node_modules\webpack-babel-multi-target-plugin\dist\src\excluded.packages.js:20:5)
at Module._compile (C:\Migu\webpack-babel-multi-target-plugin-test\node_modules\v8-compile-cache\v8-compile-cache.js:192:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)
at Module.load (internal/modules/cjs/loader.js:589:32)
at tryModuleLoad (internal/modules/cjs/loader.js:528:12)
at Function.Module._load (internal/modules/cjs/loader.js:520:3)
at Module.require (internal/modules/cjs/loader.js:626:17)
at require (C:\Migu\webpack-babel-multi-target-plugin-test\node_modules\v8-compile-cache\v8-compile-cache.js:161:20) at Object.<anonymous> (C:\Migu\webpack-babel-multi-target-plugin-test\node_modules\webpack-babel-multi-target-plugin\dist\index.js:8:10)
at Module._compile (C:\Migu\webpack-babel-multi-target-plugin-test\node_modules\v8-compile-cache\v8-compile-cache.js:192:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)
at Module.load (internal/modules/cjs/loader.js:589:32)
at tryModuleLoad (internal/modules/cjs/loader.js:528:12)
at Function.Module._load (internal/modules/cjs/loader.js:520:3)
at Module.require (internal/modules/cjs/loader.js:626:17)
at require (C:\Migu\webpack-babel-multi-target-plugin-test\node_modules\v8-compile-cache\v8-compile-cache.js:161:20) at Object.<anonymous> (C:\Migu\webpack-babel-multi-target-plugin-test\webpack.config.js:6:32)
at Module._compile (C:\Migu\webpack-babel-multi-target-plugin-test\node_modules\v8-compile-cache\v8-compile-cache.js:192:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)
at Module.load (internal/modules/cjs/loader.js:589:32)
at tryModuleLoad (internal/modules/cjs/loader.js:528:12)
at Function.Module._load (internal/modules/cjs/loader.js:520:3)
at Module.require (internal/modules/cjs/loader.js:626:17)
at require (C:\Migu\webpack-babel-multi-target-plugin-test\node_modules\v8-compile-cache\v8-compile-cache.js:161:20) at WEBPACK_OPTIONS (C:\Migu\webpack-babel-multi-target-plugin-test\node_modules\webpack-cli\bin\utils\convert-argv.js:114:13)
at requireConfig (C:\Migu\webpack-babel-multi-target-plugin-test\node_modules\webpack-cli\bin\utils\convert-argv.js:116:6)
at C:\Migu\webpack-babel-multi-target-plugin-test\node_modules\webpack-cli\bin\utils\convert-argv.js:123:17
at Array.forEach (<anonymous>)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] start: `webpack --mode development --config webpack.config.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! C:\nodejs\npm-cache\_logs\2019-10-21T08_23_19_604Z-debug.log
@DanielSchaffer I've updated my test repo with a new branch no-multi-target
(https://github.com/bitfella/webpack-babel-multi-target-plugin-test/tree/no-multi-target): in the latter you can see how tabs.css
chunk is correctly generated in dist/chunks
folder when webpack-babel-multi-target-plugin
is disabled.
Thanks again
Hi @DanielSchaffer, any update on this?
Thanks
@bitfella hey there - sorry, I haven't been able to look at this specifically yet. Hopefully I'll be able to take a peek this weekend. If you have the time and inclination to take a look yourself before then, NormalizeCssChunksPlugin
would be a good place to start - if I had to make a guess, it would be that extractCssChunks
isn't correctly preserving dynamically generated chunks when it does its thing, and it needs a way to identify them without also including the duplicate chunks it's trying to filter out.
For some background, NormalizeCssChunksPlugin
exists to avoid creating duplicate CSS files when using a plugin like MiniCssExtractPlugin
. Duplicate CSS files are created because the CSS is generated and attached for each of the targets - so there's a file created for the legacy
bundle as well as the modern
bundle. Since this plugin only deals with JavaScript, the CSS will always be identical between them, so there's no sense in keep both, so NormalizeCssChunkPlugin
figures out which are the duplicates and removes them.
I'm poking around a bit now with the debugger, and seeing a couple things:
- For the dynamic module chunks,
BabelTarget.findTarget
is unable to determine the target (line 49) -
findEntryName
is unable to determine an entry name for these chunks, which is used to help name the resulting CSS file and identify duplicate CssModules between "sibling" chunks (e.g. chunks representing the same code, but for different targets) so the entry name ends up just beingundefined
(line 62) - the above results in creating a new module for an entry named
undefined
and assigning the CssModules from the dynamic chunks to it (lines 66 and 78, respectively) -
hasUntaggedTarget
gets set to true when there's a target withtagAssetsWithKey=false
- the default settings have thelegacy
target set up like this, which results in[entry].js
and[entry].modern.js
bundles - and because of that, the code after line 89 never runs to add any of the dynamic CSS modules back into the compilation.
I'm a bit unclear on what my intention was with the hasUntaggedTarget
behavior, and I wish I'd included a bit more in the way of code comments around it, but it is possible that this is ultimately responsible for the CSS for dynamic chunks being abandoned. When I get some more time (again, hopefully this weekend), I'll start with fixing the BabelTarget.findTarget
and findEntryName
issues and see if that works - if not, I'll have to look into hasUntaggedTarget
a little more.
@bitfella - I've got something working for the updated es6-dynamic-import
example ... give 2.3.2-next.1
a shot.
Hi @DanielSchaffer, thanks for your work!
I've updated to 2.3.2-next.1
and this time dynamic import css chunks are correctly generated in the file system, BUT I am now facing a different issue: there's some logic missing in the ES6 version of the JS output: inside the function requireEnsure a whole block of code is missing:
/******/ // mini-css-extract-plugin CSS loading
/******/ var cssChunks = {"tabs":1};
/******/ if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);
/******/ else if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) {
/******/ promises.push(installedCssChunks[chunkId] = new Promise(function(resolve, reject) {
/******/ var href = "chunks/" + ({"tabs":"tabs"}[chunkId]||chunkId) + ".css";
/******/ var fullhref = __webpack_require__.p + href;
/******/ var existingLinkTags = document.getElementsByTagName("link");
/******/ for(var i = 0; i < existingLinkTags.length; i++) {
/******/ var tag = existingLinkTags[i];
/******/ var dataHref = tag.getAttribute("data-href") || tag.getAttribute("href");
/******/ if(tag.rel === "stylesheet" && (dataHref === href || dataHref === fullhref)) return resolve();
/******/ }
/******/ var existingStyleTags = document.getElementsByTagName("style");
/******/ for(var i = 0; i < existingStyleTags.length; i++) {
/******/ var tag = existingStyleTags[i];
/******/ var dataHref = tag.getAttribute("data-href");
/******/ if(dataHref === href || dataHref === fullhref) return resolve();
/******/ }
/******/ var linkTag = document.createElement("link");
/******/ linkTag.rel = "stylesheet";
/******/ linkTag.type = "text/css";
/******/ linkTag.onload = resolve;
/******/ linkTag.onerror = function(event) {
/******/ var request = event && event.target && event.target.src || fullhref;
/******/ var err = new Error("Loading CSS chunk " + chunkId + " failed.\n(" + request + ")");
/******/ err.code = "CSS_CHUNK_LOAD_FAILED";
/******/ err.request = request;
/******/ delete installedCssChunks[chunkId]
/******/ linkTag.parentNode.removeChild(linkTag)
/******/ reject(err);
/******/ };
/******/ linkTag.href = fullhref;
/******/
/******/ var head = document.getElementsByTagName("head")[0];
/******/ head.appendChild(linkTag);
/******/ }).then(function() {
/******/ installedCssChunks[chunkId] = 0;
/******/ }));
/******/ }
as a consequence, in the ES6 bundle dynamic import css chunks are not loaded in the browser even if they're in the filesystem. In the ES5 bundle, otherwise, these chunks are correctly loaded.
I've updated my test repo (both branches): in master
, index.html
loads the es6 bundle (no red border on tabs
component 😔), whilst in no-multi-target
branch, index.html
loads the es5 bundle and tabs
component is correctly displayed. Now start
npm task builds sources and then launches a static server to ease browser tests.
Hope you can help, thanks again!
Ohh interesting. I think I understand why this is happening - the CSS module gets removed from the ES6 bundles to prevent creating a duplicate, but that also removes the JS code that causes it to be loaded. For non-dynamic CSS modules it's not a problem since they're automatically linked by HtmlWebpackPlugin
, but it breaks them when they are dynamic.
I'll have to see if there's a way I can just replace the duplicate CSS module with the non-duplicate instead of removing it completely.
@bitfella okay, got another update for you. My assumption was correct - the extracted CSS modules also have sibling JS modules that include the code required to load the CSS assets when the dynamic module is loaded. Since the CSS modules were getting removed and getting added to the "standin" chunk, there is nothing left to link the loading code and the actual CSS, so while the dynamic module's CSS gets generated into an asset, nothing happens to load it.
I'm working around the issue for now by disabling the "css normalizing" functionality for dynamic modules, so starting with 2.3.2-next.2
, your dynamic css should load - but you will see separate and identical CSS files for each of the bundles (e.g. dynamic-module.css
and dynamic-module.modern.css
with the default settings). It's not ideal, but figuring out how to normalize these correctly will require a separate effort, and this at least gets you unblocked for now. I'll be adding details for supporting normalization of dynamic CSS in #47.
Let me know if this works for you, and I'll cut the final 2.3.2
release. Thanks!
Hi, @DanielSchaffer thanks for the update! Just tested 2.3.2-next.2
, but nothing seems to have changed from 2.3.2-next.1
😢
Still got one css chunk output; it is correctly imported in es5 bundle but NOT in es6 one.
I've updated both branches of my test repo.
Thanks again!
@bitfella hi, I have the same problem, the css in dynamic import not output, did you solve it?
Hi @xn330125, yes I "solved" it since I changed job, so I am not using that stuff anymore :) Hope you can deal with it!