Skip to content

Commit ec2ffb4

Browse files
authored
Handle css-loader file resolving change (#17724)
This is a follow-up to #16973 which adds handling for the breaking change in the latest version of css-loader that causes unresolved file references in `url` or `import` to cause the build to fail. This fixes it by adding our own resolve checking and when it fails disabling the `css-loader`'s handling of it. Fixes: #17701
1 parent c021662 commit ec2ffb4

File tree

12 files changed

+188
-0
lines changed

12 files changed

+188
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export function cssFileResolve(url: string, _resourcePath: string) {
2+
if (url.startsWith('/')) {
3+
return false
4+
}
5+
return true
6+
}

packages/next/build/webpack/config/blocks/css/loaders/global.ts

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import postcss from 'postcss'
22
import webpack from 'webpack'
33
import { ConfigurationContext } from '../../../utils'
44
import { getClientStyleLoader } from './client'
5+
import { cssFileResolve } from './file-resolve'
56

67
export function getGlobalCssLoader(
78
ctx: ConfigurationContext,
@@ -29,6 +30,9 @@ export function getGlobalCssLoader(
2930
sourceMap: true,
3031
// Next.js controls CSS Modules eligibility:
3132
modules: false,
33+
url: cssFileResolve,
34+
import: (url: string, _: any, resourcePath: string) =>
35+
cssFileResolve(url, resourcePath),
3236
},
3337
})
3438

packages/next/build/webpack/config/blocks/css/loaders/modules.ts

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import postcss from 'postcss'
22
import webpack from 'webpack'
33
import { ConfigurationContext } from '../../../utils'
44
import { getClientStyleLoader } from './client'
5+
import { cssFileResolve } from './file-resolve'
56
import { getCssModuleLocalIdent } from './getCssModuleLocalIdent'
67

78
export function getCssModuleLoader(
@@ -30,6 +31,9 @@ export function getCssModuleLoader(
3031
sourceMap: true,
3132
// Use CJS mode for backwards compatibility:
3233
esModule: false,
34+
url: cssFileResolve,
35+
import: (url: string, _: any, resourcePath: string) =>
36+
cssFileResolve(url, resourcePath),
3337
modules: {
3438
// Do not transform class names (CJS mode backwards compatibility):
3539
exportLocalsConvention: 'asIs',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
p {
2+
background-image: url('/vercel.svg');
3+
}
4+
5+
p:nth-child(1) {
6+
background-image: url(/vercel.svg);
7+
}
8+
9+
/* p:nth-child(2) {
10+
background-image: url('./vercel.svg');
11+
}
12+
13+
p:nth-child(3) {
14+
background-image: url(./vercel.svg);
15+
} */
16+
17+
p:nth-child(4) {
18+
background-image: url('./public/vercel.svg');
19+
}
20+
21+
p:nth-child(5) {
22+
background-image: url(./public/vercel.svg);
23+
}
24+
25+
div {
26+
background-image: url('https://vercel.com/vercel.svg');
27+
}
28+
29+
div:nth-child(1) {
30+
background-image: url('https://vercel.com/vercel.svg');
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
.p {
2+
background-image: url('/vercel.svg');
3+
}
4+
5+
.p:nth-child(1) {
6+
background-image: url(/vercel.svg);
7+
}
8+
9+
// .p:nth-child(2) {
10+
// background-image: url('./vercel.svg');
11+
// }
12+
13+
// .p:nth-child(3) {
14+
// background-image: url(./vercel.svg);
15+
// }
16+
17+
p:nth-child(4) {
18+
background-image: url('./public/vercel.svg');
19+
}
20+
21+
p:nth-child(5) {
22+
background-image: url(./public/vercel.svg);
23+
}
24+
25+
.div {
26+
background-image: url('https://vercel.com/vercel.svg');
27+
}
28+
29+
.div:nth-child(1) {
30+
background-image: url('https://vercel.com/vercel.svg');
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import '../global.css'
2+
import '../global.scss'
3+
4+
export default function MyApp({ Component, pageProps }) {
5+
return <Component {...pageProps} />
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import styles from './another.module.scss'
2+
3+
export default function Page() {
4+
return <p className={styles.first}>Hello from index</p>
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
.first {
2+
background-image: url('/vercel.svg');
3+
}
4+
5+
.first:nth-child(1) {
6+
background-image: url(/vercel.svg);
7+
}
8+
9+
// .first:nth-child(2) {
10+
// background-image: url('./vercel.svg');
11+
// }
12+
13+
// .first:nth-child(3) {
14+
// background-image: url(./vercel.svg);
15+
// }
16+
17+
.first:nth-child(4) {
18+
background-image: url('../public/vercel.svg');
19+
}
20+
21+
.first:nth-child(5) {
22+
background-image: url(../public/vercel.svg);
23+
}
24+
25+
.another {
26+
background-image: url('https://vercel.com/vercel.svg');
27+
}
28+
29+
.another:nth-child(1) {
30+
background-image: url('https://vercel.com/vercel.svg');
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import styles from './index.module.css'
2+
3+
export default function Page() {
4+
return <p className={styles.first}>Hello from index</p>
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
.first {
2+
background-image: url('/vercel.svg');
3+
}
4+
5+
.first:nth-child(1) {
6+
background-image: url(/vercel.svg);
7+
}
8+
9+
/* .first:nth-child(2) {
10+
background-image: url('./vercel.svg');
11+
}
12+
13+
.first:nth-child(3) {
14+
background-image: url(./vercel.svg);
15+
} */
16+
17+
.first:nth-child(4) {
18+
background-image: url('../public/vercel.svg');
19+
}
20+
21+
.first:nth-child(5) {
22+
background-image: url(../public/vercel.svg);
23+
}
24+
25+
.another {
26+
background-image: url('https://vercel.com/vercel.svg');
27+
}
28+
29+
.another:nth-child(1) {
30+
background-image: url('https://vercel.com/vercel.svg');
31+
}
Loading

test/integration/css/test/index.test.js

+33
Original file line numberDiff line numberDiff line change
@@ -1532,4 +1532,37 @@ describe('CSS Support', () => {
15321532
tests()
15331533
})
15341534
})
1535+
1536+
describe('should handle unresolved files gracefully', () => {
1537+
const workDir = join(fixturesDir, 'unresolved-css-url')
1538+
1539+
it('should build correctly', async () => {
1540+
await remove(join(workDir, '.next'))
1541+
const { code } = await nextBuild(workDir)
1542+
expect(code).toBe(0)
1543+
})
1544+
1545+
it('should have correct file references in CSS output', async () => {
1546+
const cssFiles = await readdir(join(workDir, '.next/static/css'))
1547+
1548+
for (const file of cssFiles) {
1549+
if (file.endsWith('.css.map')) continue
1550+
1551+
const content = await readFile(
1552+
join(workDir, '.next/static/css', file),
1553+
'utf8'
1554+
)
1555+
console.log(file, content)
1556+
1557+
// if it is the combined global CSS file there are double the expected
1558+
// results
1559+
const howMany = content.includes('p{') ? 4 : 2
1560+
1561+
expect(content.match(/\(\/vercel\.svg/g).length).toBe(howMany)
1562+
// expect(content.match(/\(vercel\.svg/g).length).toBe(howMany)
1563+
expect(content.match(/\(\/_next\/static\/media/g).length).toBe(2)
1564+
expect(content.match(/\(https:\/\//g).length).toBe(howMany)
1565+
}
1566+
})
1567+
})
15351568
})

0 commit comments

Comments
 (0)