Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CSS ordering from shared chunk not deterministic with multi entry points #202

Closed
ferdaber opened this issue Jul 5, 2018 · 22 comments
Closed

Comments

@ferdaber
Copy link

ferdaber commented Jul 5, 2018

Minimal reproduction repo (kind of): https://github.com/ferdaber/css-plugin-ordering-bug
Node: v9.11.1
OS: MacOS v10.12.6

With the latest version v0.4.1, in multiple-entry-points situations, I found that the CSS ordering is not deterministic. I set up a repo that "reproduces" the bug to the best of my ability (before getting stuck in Webpack internals).

The gist of it is that in cases where a chunk is shared between multiple chunk groups, it's not always the case that the first chunk group actually has the CSS modules that we want to sort on, which results in this line returning undefined for the module index:
https://github.com/webpack-contrib/mini-css-extract-plugin/blob/master/src/index.js#L393

Chunk groups:

  • entry-a~vendor: has a.js and shared_modules/other.js
  • entry-b~vendor: has b.js, shared_modules/red.css and shared_modules/blue.css

In my repo, I set it up so that anything in shared_modules is split out into a separate chunk, but have the entry points ordered such that the first chunk group contains no CSS modules (entry-a's dependency tree only contains JS files but touches the shared_modules chunk group). This leads to the sorting mechanism as mentioned above to return undefined for a CSS module's index.

The output in this repo still ended up having the correct ordering but I think it was because the chunk.modulesIterable set had the correct ordering at the time:

Output css/vendor.css:

html {
  background: blue;
}
html {
  background: red;
}

Expected css/vendor.css:

html {
  background: red;
}
html {
  background: blue;
}

To my understanding, chunk.modulesIterable is generated (or added) asynchronously so the ordering is not always guaranteed?

At this point I got stuck trying to get more information to submit to this issue, if a maintainer could offer me some guidance to what a better chunking strategy would be to work around this, or a fix for this, that would be super appreciated - thanks!

@ferdaber ferdaber changed the title CSS ordering not deterministic CSS ordering from shared chunk not deterministic with multi entry points Jul 5, 2018
@alexander-akait
Copy link
Member

/cc @sokra

@dtothefp
Copy link

dtothefp commented Jul 6, 2018

@evilebottnawi I can report a similar issue from the v4.0.1 release. This is pretty much the exact same behavior I was seeing when upgrading to Webpack 4 and using the extract-text plugin webpack-contrib/extract-text-webpack-plugin#745

I have a single entrypoint and am using PostCSS Loader with CSS modules. In development without extraction everything works as expected, although in prod when using mini-css-extract I see a regression in order of some classes. Reverting to `0.4.01 fixes the issue.

This seems to be happening in combination with using the

  • postcss-import module
  • using composes: via CSS loader

ex. the following css most likely occurs in various files throughout the application resulting in class duplication and changes in order

@import 'config/common.css';
@import 'config/header.css';

.container {
  position: relative;
}

.cta-text {
  composes: heading-4 from 'helpers/typography.css';
}

This problem is in a large repo and I'm having problems replicating it in a minimal use case but when I do I will post a demo.

In the real life situation:

the order of css is wrong (typography__heading-1 should be the base style, and then overwritten with the Hero__heading)
image

Resulting from the following CSS when both global.css and Hero.css are extracted together into the same file:

// global.css
@import 'helpers/typography.css';
// Hero.css
.text-headline {
  composes: heading-1 from 'helpers/typography.css';
  color: var(--color-text);

  @media (--large-up) {
    width: 100%;
  }
}
//main.js
import './global.css';
import Hero from `./Hero'; // where Hero.js imports Hero.css as css-module

@boraturant
Copy link

This issue is same as #188

I have also posted a repo that shows the problem at https://github.com/boraturant/MiniCssExtractPlugin_CSSOrderProblem

@smrq
Copy link

smrq commented Aug 16, 2018

Ran into this as well. I have another somewhat minimal repro but it is not pretty, as triggering an actual bug with this requires hitting a random case where Array.prototype.sort yields weird behavior given the existence of a stray undefined. Altering file paths, order of imports, etc. can trigger or fix the problem.

https://github.com/smrq/mini-css-extract-plugin-repro

Perhaps order modules by their position in the first chunk group, then any modules not existing in the first chunk group by their position in the second chunk group, etc.?

https://github.com/webpack-contrib/mini-css-extract-plugin/blob/master/src/index.js#L390

-    const [chunkGroup] = chunk.groupsIterable;
-    if (typeof chunkGroup.getModuleIndex2 === 'function') {
-      modules.sort((a, b) => chunkGroup.getModuleIndex2(a) - chunkGroup.getModuleIndex2(b));
-    } else {

+    if (typeof chunk.groupsIterable[0].getModuleIndex2 === 'function') {
+      let sortedModules = [];
+      chunk.groupsIterable.forEach(chunkGroup => {
+        sortedModules = sortedModules.concat(
+          modules.filter(m => chunkGroup.getModuleIndex2(m) != null)
+            .sort((a, b) => chunkGroup.getModuleIndex2(a) - chunkGroup.getModuleIndex2(b)));
+        modules = modules.filter(m => chunkGroup.getModuleIndex2(m) == null);
+      });
+      modules = sortedModules;
+    } else {

@cameronbraid
Copy link

I have a css ordering issue with multiple entry points broken for both 0.4.1 and 0.4.2

0.4.0 does the right thing

@cameronbraid
Copy link

I was thinking about this issue and I think what the user would expect is that the css extractor orders the styles the same way they are done when you run devserver.

So, if there is a common chunk that needs to be ordered differently for two other chunks then I should think that either there needs to be two common chunks output.

@smelukov
Copy link

smelukov commented Sep 5, 2018

The same issue.
Are there any changes? )

@smelukov
Copy link

smelukov commented Sep 19, 2018

If we use style-loader instead of mini-css-extract-plugin then the problem is gone (chunks ordered correctly), but style-loader is not what we need cause it can't extract text :(

@nmfzone
Copy link

nmfzone commented Nov 18, 2018

Any update on this? 🤔

Mention maintainer: @sokra

@alexander-akait
Copy link
Member

PR welcome

@alexander-akait
Copy link
Member

alexander-akait commented Nov 21, 2018

If somebody have other minimum reproducible test repos, feel free to left link here, try to solve issue

@AndrewBogdanovTSS
Copy link

AndrewBogdanovTSS commented Jan 14, 2019

@evilebottnawi I'm experiencing same order issue while using Nuxt 2.3.4 which is using mini-extract-css-plugin internally.
Repro link: https://codesandbox.io/s/qqp1wq28yw
Additional screenshot from a real world project:
https://monosnap.com/file/pbTr2qlW2Y5GByq2RoV3y3Mlmytrg4
as you can see app.css is linked twice and the second time it's linked after pages.css that should be last in a list of css linkages.
Correct order:

  1. vendors.css
  2. app.css
  3. pages.css

No duplicates should be present

nuxt/nuxt#4219

@seeden
Copy link

seeden commented Feb 12, 2019

version 0.5.0 same error. with sideEffects false you get bigger bundle size

@meta-meta
Copy link

I'm seeing this when I turn on tree shaking. Can someone explain why tree shaking impacts compiled CSS order?

@cameronbraid
Copy link

FYI I discovered after some time that the issue I had wasn't a problem with mini-css-extract-plugin. I was just calling require in a different order than I had expected.

@belozer
Copy link

belozer commented Aug 7, 2019

I got this problem after tree shaking. "sideEffects": [ ".css" ]

satazor added a commit to moxystudio/next-with-moxy that referenced this issue Dec 21, 2019
The "sideEffects" property in package.json improves webpack treeshaking. However that causes the out-of-order CSS we were seeing in production builds. We may enable again once the bug is fixed.
For more context see webpack/webpack#7094 and webpack-contrib/mini-css-extract-plugin#202.
satazor added a commit to moxystudio/next-with-moxy that referenced this issue Dec 22, 2019
The "sideEffects" property in package.json improves webpack treeshaking. However that causes the out-of-order CSS we were seeing in production builds. We may enable again once the bug is fixed.
For more context see webpack/webpack#7094 and webpack-contrib/mini-css-extract-plugin#202.
@rpearce
Copy link

rpearce commented Jun 25, 2020

Is this still an issue? Are there any ways around it without switching to style-loader?

@reilly-webster
Copy link

This is still ongoing. The common chunk ends up loading before the entrypoint specific chunk, but the common chunk has rules that are at the same specificity and meant to supersede entrypoint styles based on order. But right now the common chunk behaviour makes the opposite happen.

@ilicmarko
Copy link

I think that I encountered this exact problem. A reproducible example can be found here:

ilicmarko/webpack-chunk-test#1

Note: This is vue-cli under the hood but it uses mini-css-extract-plugin.

@XiaofengXie16
Copy link

any updates on this?

@alexander-akait
Copy link
Member

hm, should be fixed, what is the version?

@alexander-akait
Copy link
Member

alexander-akait commented Apr 6, 2021

Fixed in mini-css-extract-plugin@1.4.0, all repos above output expected result (tested), please check you have webpack v5 and mini-css-extract-plugin v1.4.0, if you faced with the issue again please open a new issue with reproducible test repo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests