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): module css deep first insert #6301

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions packages/playground/css/__tests__/css.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,35 @@ test('treeshaken async chunk', async () => {
}
})

test('async css modules', async () => {
const green = await page.$('.async-modules-green')
const blue2 = await page.$('.async-modules-blue2')
const red = await page.$('.async-modules-red')
const blue = await page.$('.async-modules-blue')

const _black = await page.$('.async-modules-and-css-black')
const _blue = await page.$('.async-modules-and-css-blue')

expect(await getColor(green)).toBe('green')
expect(await getColor(blue2)).toBe('blue')

expect(await getColor(_black)).toBe('black')
expect(await getColor(_blue)).toBe('blue')

// because that loaded blue > red first
// and can't change the style order
expect(await getColor(blue)).toBe('black')
expect(await getColor(red)).toBe('black')
})

test('async css modules with normal css', async () => {
const black = await page.$('.async-modules-and-css-black')
const blue = await page.$('.async-modules-and-css-blue')

expect(await getColor(black)).toBe('black')
expect(await getColor(blue)).toBe('blue')
})

test('PostCSS dir-dependency', async () => {
const el1 = await page.$('.dir-dep')
const el2 = await page.$('.dir-dep-2')
Expand Down
9 changes: 9 additions & 0 deletions packages/playground/css/async-modules-and-css/black.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import styles from './black.module.css'
import './hotpink.css'

const div = document.createElement('div')
div.className = `base ${styles.black} async-modules-and-css-black`
document.body.appendChild(div)
div.textContent = `async css modules and normal css (black) ${
getComputedStyle(div).color
}`
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.black {
color: black;
}
9 changes: 9 additions & 0 deletions packages/playground/css/async-modules-and-css/blue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import './hotpink.css'
import styles from './blue.module.css'

const div = document.createElement('div')
div.className = `base ${styles.blue} async-modules-and-css-blue`
document.body.appendChild(div)
div.textContent = `async css modules and normal css (blue) ${
getComputedStyle(div).color
}`
3 changes: 3 additions & 0 deletions packages/playground/css/async-modules-and-css/blue.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.blue {
color: blue;
}
4 changes: 4 additions & 0 deletions packages/playground/css/async-modules-and-css/hotpink.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.hotpink {
font-size: 1rem;
color: hotpink;
}
10 changes: 10 additions & 0 deletions packages/playground/css/async-modules/base.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import styles from './black.module.css'

export function baseAsync(className, color) {
const div = document.createElement('div')
div.className = `${styles.black} ${className} async-modules-${color}`
document.body.appendChild(div)
div.textContent = `async css modules (${color}) ${
getComputedStyle(div).color
}`
}
10 changes: 10 additions & 0 deletions packages/playground/css/async-modules/base2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import styles from './red.module.css'

export function baseAsync(className, color) {
const div = document.createElement('div')
div.className = `${styles.red} ${className} async-modules-${color}`
document.body.appendChild(div)
div.textContent = `async css modules2 (${color}) ${
getComputedStyle(div).color
}`
}
3 changes: 3 additions & 0 deletions packages/playground/css/async-modules/black.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.black {
color: black;
}
4 changes: 4 additions & 0 deletions packages/playground/css/async-modules/blue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import styles from './blue.module.css'
import { baseAsync } from './base'

baseAsync(styles.blue, 'blue')
3 changes: 3 additions & 0 deletions packages/playground/css/async-modules/blue.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.blue {
color: blue;
}
6 changes: 6 additions & 0 deletions packages/playground/css/async-modules/green.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { baseAsync } from './base2'
import green from './green.module.css'
import blue from './blue.module.css'

baseAsync(green.green, 'green')
baseAsync(blue.blue, 'blue2')
3 changes: 3 additions & 0 deletions packages/playground/css/async-modules/green.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.green {
color: green;
}
4 changes: 4 additions & 0 deletions packages/playground/css/async-modules/red.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { baseAsync } from './base'
import styles from './red.module.css'

baseAsync(styles.red, 'red')
3 changes: 3 additions & 0 deletions packages/playground/css/async-modules/red.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.red {
color: red;
}
9 changes: 9 additions & 0 deletions packages/playground/css/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@ if (import.meta.env.DEV) {
import inlined from './inlined.css?inline'
text('.inlined-code', inlined)

// async css modules
import('./async-modules/blue')
import('./async-modules/red')
import('./async-modules/green')

// async css module with normal css
import('./async-modules-and-css/black')
import('./async-modules-and-css/blue')

// glob
const glob = import.meta.glob('./glob-import/*.css')
Promise.all(Object.keys(glob).map((key) => glob[key]())).then((res) => {
Expand Down
37 changes: 31 additions & 6 deletions packages/vite/src/node/plugins/css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,14 @@ const cssModulesCache = new WeakMap<
Map<string, Record<string, string>>
>()

export const cssModulesSets = new WeakMap<
ResolvedConfig,
{
isJSChunk: Set<string> // css module is js chunk
inJSChunk: Set<string> // css module in js chunk
}
>()

export const chunkToEmittedCssFileMap = new WeakMap<
RenderedChunk,
Set<string>
Expand Down Expand Up @@ -265,6 +273,8 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
// styles initialization in buildStart causes a styling loss in watch
const styles: Map<string, string> = new Map<string, string>()
let pureCssChunks: Set<string>
let cssModulesIsJSChunkSet: Set<string>
let cssModulesInJSChunkSet: Set<string>

// when there are multiple rollup outputs and extracting CSS, only emit once,
// since output formats have no effect on the generated CSS.
Expand All @@ -278,6 +288,13 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
// Ensure new caches for every build (i.e. rebuilding in watch mode)
pureCssChunks = new Set<string>()
outputToExtractedCSSMap = new Map<NormalizedOutputOptions, string>()

cssModulesIsJSChunkSet = new Set<string>()
cssModulesInJSChunkSet = new Set<string>()
cssModulesSets.set(config, {
isJSChunk: cssModulesIsJSChunkSet,
inJSChunk: cssModulesInJSChunkSet
})
hasEmitted = false
},

Expand Down Expand Up @@ -356,20 +373,29 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
async renderChunk(code, chunk, opts) {
let chunkCSS = ''
let isPureCssChunk = true
let moduleCssCount = 0
const ids = Object.keys(chunk.modules)
for (const id of ids) {
if (
!isCSSRequest(id) ||
cssModuleRE.test(id) ||
commonjsProxyRE.test(id)
) {
const isCssModule = cssModuleRE.test(id)
if (isCssModule) {
moduleCssCount++
}
if (!isCSSRequest(id) || isCssModule || commonjsProxyRE.test(id)) {
isPureCssChunk = false
}
if (styles.has(id)) {
chunkCSS += styles.get(id)
}
}

if (moduleCssCount) {
if (moduleCssCount === ids.length) {
cssModulesIsJSChunkSet.add(chunk.fileName)
} else {
cssModulesInJSChunkSet.add(chunk.fileName)
}
}

if (!chunkCSS) {
return null
}
Expand Down Expand Up @@ -410,7 +436,6 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
}
return css
}

if (config.build.cssCodeSplit) {
if (isPureCssChunk) {
// this is a shared CSS-only chunk that is empty.
Expand Down
Loading