vitejs / vite

Next generation frontend tooling. It's fast!
http://vite.dev
MIT License
68.89k stars 6.23k forks source link

Wrong CSS ordering in build output when using two entrypoints (fine in serve mode) #4890

Open fango256 opened 3 years ago

fango256 commented 3 years ago

Hi, I've been struggling with an issue that causes our override CSS rules to fail on some builds. In our production app it is actually inconsistent - however the simple local reproduction repository i've linked to seems to reproduce consistently.

When using a single entrypoint the generated index.html correctly outputs vendor.css followed by the local css (index.css). However when i include a second entrypoint with exactly the same content as the first entrypoint the generated index.html files have the CSS defined in the wrong order in all entrypoints. The CSS is ordered correctly in Vite serve mode.

Using main.js

import { VApp } from "vuetify/lib";
console.log(VApp);

import '../style.css'

document.querySelector('#app').innerHTML = `
  <div class="v-application theme--light">I should have a blue background as my CSS is overridden in style.css</v-application>
`

With one entrypoint in correctly outputs:

...
<link rel="stylesheet" href="/assets/vendor.06e82a89.css">
<link rel="stylesheet" href="/assets/main.b16cdc1a.css">
...

But including a second entrypoint with the same js content flips the CSS ordering in both the output html files: build/index.html

...
<link rel="stylesheet" href="/assets/style.0cc4c6eb.css">
<link rel="stylesheet" href="/assets/vendor.06e82a89.css">
...

build/entrypoint2/index.html

...
<link rel="stylesheet" href="/assets/style.0cc4c6eb.css">
<link rel="stylesheet" href="/assets/vendor.06e82a89.css">
...

Reproduction

https://github.com/fango256/vite-css-ordering-issue

System Info

System:
    OS: Windows 10 10.0.22000
    CPU: (24) x64 AMD Ryzen 9 5900X 12-Core Processor
    Memory: 40.92 GB / 63.92 GB
  Binaries:
    Node: 16.5.0 - C:\Program Files\nodejs\node.EXE
    npm: 7.19.1 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Edge: Spartan (44.22000.120.0), Chromium (93.0.961.38)
    Internet Explorer: 11.0.22000.120
  npmPackages:
    vite: ^2.5.4 => 2.5.6

Used Package Manager

npm

Logs

No response

Validations

cdll commented 3 years ago

Same issue here with react@17.0 and @material-ui/core@4.12.

intrnl commented 3 years ago

Also having the same issue, I tried bisecting Vite on my project to see if it's just a recent change but it seems the issue has been present since 2.0.0.

Edit: Ah, it seems that mine is a different issue entirely (relating to chunk preloading).

molily commented 2 years ago

I think I ran into the same issue with <link> + <style> (no JS).

This is my minimal reproducible example: https://github.com/molily/vite-style-order

index.html

<link rel="stylesheet" href="./base.css" />
<style> body { color: blue; } </style>

another.html

<link rel="stylesheet" href="./base.css" />
<style> body { color: red; } </style>

dist/index.html (note the wrong order)

<link rel="stylesheet" href="/assets/index.ca90b8db.css">
<link rel="stylesheet" href="/assets/base.05db2039.css">

dist/another.html (note the wrong order)

<link rel="stylesheet" href="/assets/another.fca6b6f0.css">
<link rel="stylesheet" href="/assets/base.05db2039.css">

The order is correct in vite dev, broken in production build, just like @fango256 described.

My workaround is to not use <style> but <link rel="stylesheet"> directly, then the dist output is basically the same (three generated .css files: base.*.css, index.*.css, another.*.css) but the order is correct.

worldtok commented 2 years ago

I have same issue while working with bootstrap 5.2.2

louia commented 2 years ago

Any update on these ?

benskz commented 2 years ago

I'm running into the same issue.

I'm unable to do a similar workaround to @molily since the styling that's in the style tag is coming from a library.

worldtok commented 2 years ago

I ran into this error while importing css and scss files together while retaining the extensions for the css files. As I fiddle around the code, I found out that the issues occur as a result of importing css files and scss together and at the same time adding an extension to the css import code

This code throws the issues as the css file is imported first instead of scss file

@import './scss/file'; // .scss file @import './chunk-1.css'; // .css file

This resolves as expected importing the scss file before the css file

@import './scss/file'; // .scss file @import './chunk-1'; // .css file

I was importing everything into a sass file

jordan-erisman commented 1 year ago

Any updates to this issue?

alexdeia commented 1 year ago

It is a real problem. Why is there so little written about her? I try to fix this by !important prop (but it is awful workaround)

haroldiedema commented 1 year ago

Just to confirm; We're trying to migrate from webpack to vite in a Vue 2 + Vuetify application. Due to the fact that Vuetify uses lots of !important rules in their CSS files, we sort-of "hacked around" it by loading another CSS file after it with even more !important rules (yes, I know... 😅).

However, this doesn't work in Vite due to the wrong CSS order. This issue is kind of a blocker for us as well.

kleinfreund commented 1 year ago

I’m seeing this issue in a Vue application which has one JS and one CSS entry point in its head like so:

<script type="module" src="/src/main.ts"></script>
<link rel="stylesheet" href="/src/main.scss">

The stylesheet order ends up being different between serving and a build. In dev, Vue component styles are being injected before </head>.

<script type="module" src="/src/main.ts?t=1697011881434"></script>
<link rel="stylesheet" href="/src/main.scss">
<style type="text/css" data-vite-dev-id="/path/src/MyComponent.vue?vue&amp;type=style&amp;index=0&amp;scoped=7c794cdb&amp;lang.scss">

But in the build, they’re being bundled into the sole CSS entry point and specifically they’re being put at the start of it. This breaks the order.

<script type="module" crossorigin src="./assets/index-ba2f01fe.js"></script>
<!-- this file has MyComponent.vue styles **at the start** -->
<link rel="stylesheet" href="./assets/index-f09d5511.css">
danielvy commented 3 months ago

I'm surprised that after three years, this is still an issue.

I'm running into this problem when trying to split css (compiled from .scss) into style sheets and keep vendor css (bootstrap) separated. My style sheets need to be loaded last otherwise it messes up css cascading.

At least with Vue, the issue happens not because of the import order per se. Vite will keep the order of the imported style sheets but it will process the styles from Vue's SFC files first and the chunk that ends up including those styles will be added first to the style sheet import order.

Consequently, if the main style (imported from the index js/ts) ends up in the same chunk as the SFC styles, it will be imported first along with them (because that style sheet is already on the top), regardless of its actual import order.

Haven't found a clean solution, I used a hack in the form of ad hoc plugin in my Vite config to transform the result html, remove the style sheet in question and append it to the end of <head>:

{
  name: "html-transform",
  enforce: "post",
  transformIndexHtml(html) {
    // Match the entire line in html that includes that stylesheet that needs
    // to go last. Regex group to extract link href.
    const rxStyle = /^\s*<link rel="stylesheet".+href="(\/css\/MAKELAST\.css).*$\n/m;
    const tags: HtmlTagDescriptor[] = [];
    const m = html.match(rxStyle);
    if (m) {
      html = html.replace(rxStyle, "");
      tags.push({
        injectTo: "head",
        tag: "link",
        attrs: { rel: "stylesheet", crossorigin: true, href: m[1] }
      });
    }
    return { html, tags };
  }
}

This works well but it's another thing to track and remember to update if project structure changes.

immdevrov commented 1 month ago

Stumbled upon similar problem. Vite builds styles from sfc be loaded before styles that was imported in js styles (some vendor css). Becouse of that vendor styles cannot be overwritten by sfc styles