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

fix: css insert order #9278

Closed
wants to merge 27 commits into from
Closed

fix: css insert order #9278

wants to merge 27 commits into from

Conversation

poyoho
Copy link
Member

@poyoho poyoho commented Jul 21, 2022

Description

fix #3924
relate #6301
close: #6044

IIUC, the test case provided by #6044 will not get the expected results originally. But this test case exposes another problem.

When using chunk CSS, the insertion order of CSS in dev and build modes is different. Currently, there is no clear specification for CSS insertion order. So I chose the CSS sequence of build mode with higher performance as the benchmark to correct the inconsistent CSS insertion sequence.

In prod mode, Vite will concurrent request dependency for async chunk. It good point to optimize loading. https://vitejs.dev/guide/features.html#async-chunk-loading-optimization

Entry ---> (A + C)

But in dev load chunk will one by one.

Entry ---> A ---> C

For js it ok. But for css it will break the css insert order and make element node got an unexpected style.

To kept this optimization, we should keep dev in the same CSS insertion order as prod.

  1. ensure dynamic import chunk entry point.

when meet a dynamic import will call preload helper to load all the deps in prod. It will insert <link rel="stylesheet" src="css url"> by BFS order.

Browser load the module is also BFS, but the dev module had the diff resolveId / load / transform hook handle timing, it will make the css order confusion.

In this PR, collect the loading order by browser.

  • mark dynamic import as entry point on importAnalysis plugin.
  • ensure the entry point weight on browser. (rewrite the import method to record the dynamic import order in browser and inject the url query (http query params will break the browser cache) send the weight state by websocket to shared the entry point weight to vite dev serve module graph)
  1. via 1 collect state, we can ensure the file importer by what entry point in entry point moduleGraph.updateModuleInfo time point.

In this PR, add entryPoint field on ModuleNode to record the entry point for each module node.

  1. insert the style node as the same as the collect loading weight.

via entry point weight we can ensure the style node weight as same as build mode.

After this PR, kept the build load async module order and mock the serve mode style order as same as build mode.

Additional context

TODO

  • hmr test
  • conditional triggered dynamic import
  • performance report

What is the purpose of this pull request?

  • Bug fix
  • New Feature
  • Documentation update
  • Other

Before submitting the PR, please make sure you do the following

  • Read the Contributing Guidelines.
  • Read the Pull Request Guidelines and follow the Commit Convention.
  • Check that there isn't already a PR that solves the problem the same way to avoid creating a duplicate.
  • Provide a description in this PR that addresses what the PR is solving, or reference the issue that it solves (e.g. fixes #123).
  • Ideally, include relevant tests that fail without this PR but pass with it.

@@ -164,6 +183,30 @@ export class ModuleGraph {
}
}
})
// ensure the module entry point
mod.importers.forEach((importerMod) => {
if (importerMod.entryPoint === 'self') {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a question - how do circular deps affect something like this? I guess that's just a general ESM problem of which the answer is "circular deps are illegal"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for review. I think this is no circular deps affect problem. Because mod just find the parent node (mod.importers) which is first to use the mod.

@poyoho poyoho marked this pull request as draft July 21, 2022 14:33
@poyoho
Copy link
Member Author

poyoho commented Jul 21, 2022

Oh when I write the PR context, I find miss some context. Make it draft and do it later 🤦

@poyoho poyoho marked this pull request as ready for review July 23, 2022 17:49
@poyoho poyoho marked this pull request as draft July 23, 2022 18:06
@poyoho poyoho marked this pull request as ready for review July 24, 2022 06:04
Copy link
Contributor

@IanVS IanVS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks so much for working on this! I tested it out on my own project, and unfortunately I'm still seeing style problems. But the way that vite is bundling up the files is making it really hard to figure out why, or what exactly is happening. I'll keep trying to investigate, but it seems like normal .css files are being associated with .js files from a component library I'm using, though the two are not connected to each other other than I normally import both files into the same components. I'll report back if I can figure out more, or make a test case for it.

import styles from './blue.module.css'

const div = document.createElement('div')
div.className = `base ${styles.blue} async-modules-and-css-blue`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this class should also contain hotpink, to verify that the blue style "wins" because it is imported second.

Copy link
Member Author

@poyoho poyoho Aug 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes. I think the css order should as same as build load module order

if the module is a chunk will insert into head later.

import './hotpink.css'

const div = document.createElement('div')
div.className = `base ${styles.black} async-modules-and-css-black`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hotpink seems unused here. Maybe it should be added to the class list, and the assertion should check that the text is pink, since it is loaded last.

@IanVS
Copy link
Contributor

IanVS commented Jul 25, 2022

I was able to reproduce the issue that I think I'm having, by importing a shared function into both blue and black.

IanVS@8c8bc43

In the case of both blue and black, I would expect their colors to be correct, since each one imports the css module after the global hotpink styles. But that doesn't happen, and one turns pink.

@ghost
Copy link

ghost commented Oct 17, 2022

Is this PR still being worked on? It seems development has stopped on this.

@atzcl
Copy link

atzcl commented Oct 18, 2022

Is this PR still being worked on? It seems development has stopped on this.

It seems that the problem has been fixed, please see #9949

@IanVS
Copy link
Contributor

IanVS commented Oct 18, 2022

@atzcl unfortunately not. That was one piece of it, but there are still problems which the PR you referenced did not address.

@maicWorkGithub
Copy link

maicWorkGithub commented Mar 29, 2023

As of today, more than 160 days have passed since the latest update. Is there any progress? Any plans to merge and release? We're looking forward to fixing this issue, we are blocked by this bug. thank you for your work!

@poyoho poyoho closed this Mar 29, 2023
@maicWorkGithub
Copy link

@poyoho Why this pr closed? Has this bug fixed or no need to fix? We blocked by #3924

@poyoho
Copy link
Member Author

poyoho commented Mar 29, 2023

Because I feel like this pr can't solve the problem 🤦

@patak-dev
Copy link
Member

@maicWorkGithub there are some new comments on #3924 (comment) that are hinting at this issue not being solvable. I suggest you look for a workaround, like the proposal there of using CSS layers. I don't think this issue is going to be solved any time soon and we may need to close it as expected.

@maicWorkGithub
Copy link

@poyoho Thanks for your work!
@patak-dev CSS layers too new, it's compatibility not suitable. postcss plugin of CSS layers seems a better way, I will suggest this in our dev group. Thanks.

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

Successfully merging this pull request may close these issues.

Vite injects css assets in wrong order with dynamic import and css modules.
6 participants