vite
vite copied to clipboard
Vite injects css assets in wrong order with dynamic import and css modules.
Describe the bug
Vite injects css assets in wrong order with dynamic import and css modules.
Reproduction
For example:
- You have component Button with default styles (text color: red)
/* button.tsx */
import React from "react"
import classnames from 'classnames'
import styles from './button.module.css'
type ButtonProps = {
children: string
className?: string
onClick?: () => void
}
function Button({ children, className, onClick }: ButtonProps) {
return <button className={classnames(styles.button, className)} onClick={onClick}>{children}</button>
}
export default Button
/* button.module.css */
.button {
color: red
}
- You have Page component. This page use Button component and overrides it styles by passing custom class name as a prop (text color: green)
/* home.tsx /*
import React from "react"
import Button from "../../components/button/button"
import styles from './home.module.css'
function HomePage() {
return <div>
<h1>Home page</h1>
<Button className={styles.greenTextButton}>should be green</Button>
</div>
}
export default HomePage
/* home.module.css */
.greenTextButton {
color: green;
}
- You import Page component with dynamic import.
import React, { lazy, Suspense, useState } from 'react'
const HomePage = lazy(() => import('./pages/home/home'))
const AboutPage = lazy(() => import('./pages/about/about'))
function App() {
const [page, setPage] = useState('home')
return (
<div>
<a href="#" onClick={() => setPage('home')} style={{ marginRight: '5px' }}>home page</a>
<a href="#" onClick={() => setPage('about')}>about page</a>
<Suspense fallback={<div>loading</div>}>
{page === 'home' && (
<HomePage />
)}
{page === 'about' && (
<AboutPage />
)}
</Suspense>
</div>
)
}
export default App
- You exepect page styles will override button styles, but they are not (as vite injects styles in wrong order)
P.S. You can reproduce this but with cssCodeSplit: true or false.
System Info
Output of npx envinfo --system --npmPackages vite,@vitejs/plugin-vue --binaries --browsers:
System:
OS: macOS 11.4
CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
Memory: 94.85 MB / 16.00 GB
Shell: 5.8 - /bin/zsh
Binaries:
Node: 14.16.1 - ~/.volta/tools/image/node/14.16.1/bin/node
npm: 6.14.12 - ~/.volta/tools/image/node/14.16.1/bin/npm
Browsers:
Chrome: 91.0.4472.114
Firefox: 89.0
Safari: 14.1.1
npmPackages:
vite: ^2.3.8 => 2.3.8
Used package manager:
Logs
vite:config bundled config file loaded in 42ms +0ms
vite:config using resolved config: {
vite:config plugins: [
vite:config 'alias',
vite:config 'react-refresh',
vite:config 'vite:dynamic-import-polyfill',
vite:config 'vite:resolve',
vite:config 'vite:html',
vite:config 'vite:css',
vite:config 'vite:esbuild',
vite:config 'vite:json',
vite:config 'vite:wasm',
vite:config 'vite:worker',
vite:config 'vite:asset',
vite:config 'vite:define',
vite:config 'vite:css-post',
vite:config 'vite:build-html',
vite:config 'commonjs',
vite:config 'vite:data-uri',
vite:config 'rollup-plugin-dynamic-import-variables',
vite:config 'vite:import-analysis',
vite:config 'vite:esbuild-transpile',
vite:config 'vite:terser',
vite:config 'vite:reporter'
vite:config ],
vite:config build: {
vite:config target: [ 'es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1' ],
vite:config polyfillDynamicImport: false,
vite:config outDir: 'dist',
vite:config assetsDir: 'assets',
vite:config assetsInlineLimit: 4096,
vite:config cssCodeSplit: true,
vite:config sourcemap: false,
vite:config rollupOptions: {},
vite:config commonjsOptions: { include: [Array], extensions: [Array] },
vite:config minify: 'terser',
vite:config terserOptions: {},
vite:config cleanCssOptions: {},
vite:config write: true,
vite:config emptyOutDir: null,
vite:config manifest: false,
vite:config lib: false,
vite:config ssr: false,
vite:config ssrManifest: false,
vite:config brotliSize: true,
vite:config chunkSizeWarningLimit: 500,
vite:config watch: null
vite:config },
vite:config configFile: '/Users/anatoliidomaratskyi/Work/Mimy/css-code-split-order/vite.config.ts',
vite:config configFileDependencies: [ 'vite.config.ts' ],
vite:config inlineConfig: {
vite:config root: undefined,
vite:config base: undefined,
vite:config mode: undefined,
vite:config configFile: undefined,
vite:config logLevel: undefined,
vite:config clearScreen: undefined,
vite:config build: {}
vite:config },
vite:config root: '/Users/anatoliidomaratskyi/Work/Mimy/css-code-split-order',
vite:config base: '/',
vite:config resolve: { dedupe: undefined, alias: [ [Object] ] },
vite:config publicDir: '/Users/anatoliidomaratskyi/Work/Mimy/css-code-split-order/public',
vite:config cacheDir: '/Users/anatoliidomaratskyi/Work/Mimy/css-code-split-order/node_modules/.vite',
vite:config command: 'build',
vite:config mode: 'production',
vite:config isProduction: true,
vite:config server: {
vite:config fsServe: {
vite:config root: '/Users/anatoliidomaratskyi/Work/Mimy/css-code-split-order',
vite:config strict: false
vite:config }
vite:config },
vite:config env: { BASE_URL: '/', MODE: 'production', DEV: false, PROD: true },
vite:config assetsInclude: [Function: assetsInclude],
vite:config logger: {
vite:config hasWarned: false,
vite:config info: [Function: info],
vite:config warn: [Function: warn],
vite:config warnOnce: [Function: warnOnce],
vite:config error: [Function: error],
vite:config clearScreen: [Function: clearScreen]
vite:config },
vite:config createResolver: [Function: createResolver],
vite:config optimizeDeps: { esbuildOptions: { keepNames: undefined } }
vite:config } +6ms
vite v2.3.8 building for production...
✓ 33 modules transformed.
dist/assets/favicon.17e50649.svg 1.49kb
dist/index.html 0.45kb
dist/assets/home.5d3a6e0a.js 0.26kb / brotli: 0.15kb
dist/assets/button.14aa6fb9.js 0.80kb / brotli: 0.41kb
dist/assets/home.deac2baa.css 0.04kb / brotli: 0.04kb
dist/assets/about.563410d2.js 0.60kb / brotli: 0.28kb
dist/assets/button.a44dba50.css 0.03kb / brotli: 0.03kb
dist/assets/index.3938cd91.js 1.55kb / brotli: 0.60kb
dist/assets/about.d57e38e3.css 0.06kb / brotli: 0.05kb
dist/assets/vendor.cc984a25.js 127.61kb / brotli: 36.05kb
Before submitting the issue, please make sure you do the following
- [ +] Read the Contributing Guidelines.
- [ +] Read the docs.
- [ +] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- [ +] Provide a description in this issue that describes the bug.
- [+] Make sure this is a Vite issue and not a framework-specific issue. For example, if it's a Vue SFC related bug, it should likely be reported to https://github.com/vuejs/vue-next instead.
- [ +] Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.
the same issue for vue vite
i also meet the same problem
I also have the same problem with React
I also have the same problem with React
+1
I also have the same problem with React
How did you solve it
Same problem.
Same problem.
Same problem.
Same problem.
Same problem.
Any updates?(
Maybe @sodatea will provide some thoughts where to find problem in project and i will try to make pull request to vite?
I'm seeing this issue as well, now that I've started to use storybook's new dynamic loading feature, my styles are broken in production stories. I've found that the css files are directly after the component in the network tab. So, in one example, I have a RadioButton component that imports Label (which has its own styles that I want to override), and then it imports some css module with the overrides. However, when building now, I see this:

Which puts the RadioButton styles higher in the cascade, and they are overwritten by the Label styles, which is backwards from what I want.
Here is a minimal stackblitz reproduction: https://stackblitz.com/edit/vite-gu874q?file=main.jsx
vite: 2.7.1 @vitejs/plugin-react: 1.1.1
Great work @IanVS! Really hope this helps resolving the issue. I would help, but have no idea on where to start unfortunately.
I finally found the culprit, and FOR a while I thought vite-plugin-pages and unplugin-vue-components were causing the problem, my bad. Glad to use them again.
My temporary solution is to load influenced page synchronously in router configuration.
any idea when will #6301 be merged?
As far as I know it's not ready, @mgiraldo. This is a sticky problem to solve. If you have any ideas or can help out, please do!
i understand. thanks for all this work!
I wonder whether Vite could maybe look for a __vite__injectStyle global hook to allow overriding the head.appendChild behavior.
With Webpack's style-loader one can specify a function/hook that will be called to place the style tag into the DOM (by default it will just append it to the head like Vite does).
Webpack Configuration
// webpack.config.js
{
test: /\.css$/,
use: [
{
loader: "style-loader",
options: {
injectType: "singletonStyleTag",
// this hook will be
insert: require.resolve("./tools/insertStyleTag.ts"),
},
},
{ loader: "css-loader" },
],
},
// insertStyleTag.ts
function insertStyleTag(element) {
element.dataset.styleLoader = "";
// Custom logic, could be more complicated. Here I added a marker
// to ensure `import ...` styles are added before `styled-component`
// styles.
document.head.insertBefore(
element,
document.head.querySelector("[data-styled]")
);
}
module.exports = insertStyleTag;
For those who (like me) had to ship and need a temporary workaround: Depending on your project, you may be able to use build.cssCodeSplit to extract a single css file which has the classes in the correct order.
sadly this didnt work out for me @laurentvd 😔 i might need to refactor my components 🤔
hay!
It's almost finished now, but it's stuck at one point. Now the loading order should be as expected, but there is still a problem with the execution order
Why pre-load blue.module.css but execute first __vite__updateStyle is post-load red.module.css 🥲
However change the import order I do, it always load order by red -> green -> blue in dev mod.
This is a pretty big issue. The production build styling order also differs in order compared with the dev build making working with Vite a nightmare for me. Is there no workaround I can use in the meanwhile, it seems we are a long way from having this fixed?
same issue
Same
@poyoho Any progress?
Same problem.
I tried out the latest vite 2.9.14 version, and the situation seems to be improved (not as many style errors as before), but not quite yet resolved. I rebased https://github.com/vitejs/vite/pull/6301 onto the latest 2.9 branch as well, but its test is still failing.
I have this problem i add antd css in main file and other css in component but in dev ant last style and component css before antd. Any have solution until fix it?
While this is frustrating, I was able to work around it using CSS layers.
<style>
@import url('../path/to/css') layer(layer-1);
@import url('../path/to/css-2') layer(layer-2);
/* unlayered styles take preference over any layers */
</style>
If you're worried about browser support, there is a PostCSS plugin to help with that.