Skip to content

Commit 9d67a9f

Browse files
authored
partially fix css duplication in app dir (#61198)
### What? depends on facebook/react#28108 * fixes CSS Ordering issues due to CSS duplication in production mode * The issues still happen in dev mode * Highlights broken CSS Ordering for more dev cases, e. g. CSS in client components Closes PACK-2300
1 parent 7282682 commit 9d67a9f

20 files changed

+475
-60
lines changed

packages/next/src/build/webpack-config.ts

+76-60
Original file line numberDiff line numberDiff line change
@@ -966,74 +966,90 @@ export default async function getBaseWebpackConfig(
966966
}
967967
}
968968

969+
const frameworkCacheGroup = {
970+
chunks: 'all' as const,
971+
name: 'framework',
972+
// Ensures the framework chunk is not created for App Router.
973+
layer: isWebpackDefaultLayer,
974+
test(module: any) {
975+
const resource = module.nameForCondition?.()
976+
return resource
977+
? topLevelFrameworkPaths.some((pkgPath) =>
978+
resource.startsWith(pkgPath)
979+
)
980+
: false
981+
},
982+
priority: 40,
983+
// Don't let webpack eliminate this chunk (prevents this chunk from
984+
// becoming a part of the commons chunk)
985+
enforce: true,
986+
}
987+
const libCacheGroup = {
988+
test(module: {
989+
size: Function
990+
nameForCondition: Function
991+
}): boolean {
992+
return (
993+
module.size() > 160000 &&
994+
/node_modules[/\\]/.test(module.nameForCondition() || '')
995+
)
996+
},
997+
name(module: {
998+
layer: string | null | undefined
999+
type: string
1000+
libIdent?: Function
1001+
updateHash: (hash: crypto.Hash) => void
1002+
}): string {
1003+
const hash = crypto.createHash('sha1')
1004+
if (isModuleCSS(module)) {
1005+
module.updateHash(hash)
1006+
} else {
1007+
if (!module.libIdent) {
1008+
throw new Error(
1009+
`Encountered unknown module type: ${module.type}. Please open an issue.`
1010+
)
1011+
}
1012+
hash.update(module.libIdent({ context: dir }))
1013+
}
1014+
1015+
// Ensures the name of the chunk is not the same between two modules in different layers
1016+
// E.g. if you import 'button-library' in App Router and Pages Router we don't want these to be bundled in the same chunk
1017+
// as they're never used on the same page.
1018+
if (module.layer) {
1019+
hash.update(module.layer)
1020+
}
1021+
1022+
return hash.digest('hex').substring(0, 8)
1023+
},
1024+
priority: 30,
1025+
minChunks: 1,
1026+
reuseExistingChunk: true,
1027+
}
1028+
const cssCacheGroup = {
1029+
test: /\.(css|sass|scss)$/i,
1030+
chunks: 'all' as const,
1031+
enforce: true,
1032+
type: /css/,
1033+
minChunks: 2,
1034+
priority: 100,
1035+
}
9691036
return {
9701037
// Keep main and _app chunks unsplitted in webpack 5
9711038
// as we don't need a separate vendor chunk from that
9721039
// and all other chunk depend on them so there is no
9731040
// duplication that need to be pulled out.
9741041
chunks: (chunk: any) =>
9751042
!/^(polyfills|main|pages\/_app)$/.test(chunk.name),
976-
cacheGroups: {
977-
framework: {
978-
chunks: 'all',
979-
name: 'framework',
980-
// Ensures the framework chunk is not created for App Router.
981-
layer: isWebpackDefaultLayer,
982-
test(module: any) {
983-
const resource = module.nameForCondition?.()
984-
return resource
985-
? topLevelFrameworkPaths.some((pkgPath) =>
986-
resource.startsWith(pkgPath)
987-
)
988-
: false
989-
},
990-
priority: 40,
991-
// Don't let webpack eliminate this chunk (prevents this chunk from
992-
// becoming a part of the commons chunk)
993-
enforce: true,
994-
},
995-
lib: {
996-
test(module: {
997-
size: Function
998-
nameForCondition: Function
999-
}): boolean {
1000-
return (
1001-
module.size() > 160000 &&
1002-
/node_modules[/\\]/.test(module.nameForCondition() || '')
1003-
)
1004-
},
1005-
name(module: {
1006-
layer: string | null | undefined
1007-
type: string
1008-
libIdent?: Function
1009-
updateHash: (hash: crypto.Hash) => void
1010-
}): string {
1011-
const hash = crypto.createHash('sha1')
1012-
if (isModuleCSS(module)) {
1013-
module.updateHash(hash)
1014-
} else {
1015-
if (!module.libIdent) {
1016-
throw new Error(
1017-
`Encountered unknown module type: ${module.type}. Please open an issue.`
1018-
)
1019-
}
1020-
hash.update(module.libIdent({ context: dir }))
1021-
}
1022-
1023-
// Ensures the name of the chunk is not the same between two modules in different layers
1024-
// E.g. if you import 'button-library' in App Router and Pages Router we don't want these to be bundled in the same chunk
1025-
// as they're never used on the same page.
1026-
if (module.layer) {
1027-
hash.update(module.layer)
1028-
}
1029-
1030-
return hash.digest('hex').substring(0, 8)
1043+
cacheGroups: appDir
1044+
? {
1045+
css: cssCacheGroup,
1046+
framework: frameworkCacheGroup,
1047+
lib: libCacheGroup,
1048+
}
1049+
: {
1050+
framework: frameworkCacheGroup,
1051+
lib: libCacheGroup,
10311052
},
1032-
priority: 30,
1033-
minChunks: 1,
1034-
reuseExistingChunk: true,
1035-
},
1036-
},
10371053
maxInitialRequests: 25,
10381054
minSize: 20000,
10391055
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
$base1: rgb(255, 1, 0);
2+
3+
.base {
4+
color: $base1;
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.base {
2+
color: rgb(255, 0, 0);
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.base {
2+
color: rgb(255, 3, 0);
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.base {
2+
color: rgb(255, 2, 0);
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
'use client'
2+
3+
import Link from 'next/link'
4+
import baseStyle from '../base2.module.css'
5+
import baseStyle2 from '../base2-scss.module.scss'
6+
import style from './style.module.css'
7+
8+
export default function Page() {
9+
return (
10+
<div>
11+
<p
12+
className={`${style.name} ${baseStyle.base} ${baseStyle2.base}`}
13+
id="hello1c"
14+
>
15+
hello world
16+
</p>
17+
<Link href={'/first'} id="first">
18+
First
19+
</Link>
20+
<Link href={'/first-client'} id="first-client">
21+
First client
22+
</Link>
23+
<Link href={'/second'} id="second">
24+
Second
25+
</Link>
26+
<Link href={'/second-client'} id="second-client">
27+
Second client
28+
</Link>
29+
<Link href={'/third'} id="third">
30+
Third
31+
</Link>
32+
</div>
33+
)
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.name {
2+
composes: base from '../base.module.css';
3+
color: rgb(255, 0, 255);
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import Link from 'next/link'
2+
import baseStyle from '../base2.module.css'
3+
import baseStyle2 from '../base2-scss.module.scss'
4+
import style from './style.module.css'
5+
6+
export default function Page() {
7+
return (
8+
<div>
9+
<p
10+
className={`${style.name} ${baseStyle.base} ${baseStyle2.base}`}
11+
id="hello1"
12+
>
13+
hello world
14+
</p>
15+
<Link href={'/first'} id="first">
16+
First
17+
</Link>
18+
<Link href={'/first-client'} id="first-client">
19+
First client
20+
</Link>
21+
<Link href={'/second'} id="second">
22+
Second
23+
</Link>
24+
<Link href={'/second-client'} id="second-client">
25+
Second client
26+
</Link>
27+
<Link href={'/third'} id="third">
28+
Third
29+
</Link>
30+
</div>
31+
)
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.name {
2+
composes: base from '../base.module.css';
3+
color: blue;
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function Root({ children }: { children: React.ReactNode }) {
2+
return (
3+
<html>
4+
<body>{children}</body>
5+
</html>
6+
)
7+
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import Link from 'next/link'
2+
3+
export default function Page() {
4+
return (
5+
<div>
6+
<p>hello world</p>
7+
<Link href={'/first'}>First</Link>
8+
<Link href={'/second'}>Second</Link>
9+
</div>
10+
)
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
'use client'
2+
3+
import Link from 'next/link'
4+
import baseStyle from '../base2.module.css'
5+
import baseStyle2 from '../base2-scss.module.scss'
6+
import style from './style.module.css'
7+
8+
export default function Page() {
9+
return (
10+
<div>
11+
<p
12+
className={`${style.name} ${baseStyle.base} ${baseStyle2.base}`}
13+
id="hello2c"
14+
>
15+
hello world
16+
</p>
17+
<Link href={'/first'} id="first">
18+
First
19+
</Link>
20+
<Link href={'/first-client'} id="first-client">
21+
First client
22+
</Link>
23+
<Link href={'/second'} id="second">
24+
Second
25+
</Link>
26+
<Link href={'/second-client'} id="second-client">
27+
Second client
28+
</Link>
29+
<Link href={'/third'} id="third">
30+
Third
31+
</Link>
32+
</div>
33+
)
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.name {
2+
composes: base from '../base.module.css';
3+
color: rgb(255, 128, 0);
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import Link from 'next/link'
2+
import baseStyle from '../base2.module.css'
3+
import baseStyle2 from '../base2-scss.module.scss'
4+
import style from './style.module.scss'
5+
6+
export default function Page() {
7+
return (
8+
<div>
9+
<p
10+
className={`${style.name} ${baseStyle.base} ${baseStyle2.base}`}
11+
id="hello2"
12+
>
13+
hello world
14+
</p>
15+
<Link href={'/first'} id="first">
16+
First
17+
</Link>
18+
<Link href={'/first-client'} id="first-client">
19+
First client
20+
</Link>
21+
<Link href={'/second'} id="second">
22+
Second
23+
</Link>
24+
<Link href={'/second-client'} id="second-client">
25+
Second client
26+
</Link>
27+
<Link href={'/third'} id="third">
28+
Third
29+
</Link>
30+
</div>
31+
)
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.name {
2+
composes: base from '../base-scss.module.scss';
3+
color: green;
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import Link from 'next/link'
2+
import baseStyle from '../base2.module.css'
3+
import baseStyle2 from '../base2-scss.module.scss'
4+
import style from './style.module.scss'
5+
6+
export default function Page() {
7+
return (
8+
<div>
9+
<p
10+
className={`${style.name} ${baseStyle.base} ${baseStyle2.base}`}
11+
id="hello3"
12+
>
13+
hello world
14+
</p>
15+
<Link href={'/first'} id="first">
16+
First
17+
</Link>
18+
<Link href={'/first-client'} id="first-client">
19+
First client
20+
</Link>
21+
<Link href={'/second'} id="second">
22+
Second
23+
</Link>
24+
<Link href={'/second-client'} id="second-client">
25+
Second client
26+
</Link>
27+
<Link href={'/third'} id="third">
28+
Third
29+
</Link>
30+
</div>
31+
)
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.name {
2+
composes: base from '../base-scss.module.scss';
3+
color: rgb(0, 128, 128);
4+
}

0 commit comments

Comments
 (0)