Skip to content

Commit

Permalink
Handle css-loader file resolving change (#17724)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
ijjk committed Oct 8, 2020
1 parent c021662 commit ec2ffb4
Show file tree
Hide file tree
Showing 12 changed files with 188 additions and 0 deletions.
@@ -0,0 +1,6 @@
export function cssFileResolve(url: string, _resourcePath: string) {
if (url.startsWith('/')) {
return false
}
return true
}
Expand Up @@ -2,6 +2,7 @@ import postcss from 'postcss'
import webpack from 'webpack'
import { ConfigurationContext } from '../../../utils'
import { getClientStyleLoader } from './client'
import { cssFileResolve } from './file-resolve'

export function getGlobalCssLoader(
ctx: ConfigurationContext,
Expand Down Expand Up @@ -29,6 +30,9 @@ export function getGlobalCssLoader(
sourceMap: true,
// Next.js controls CSS Modules eligibility:
modules: false,
url: cssFileResolve,
import: (url: string, _: any, resourcePath: string) =>
cssFileResolve(url, resourcePath),
},
})

Expand Down
Expand Up @@ -2,6 +2,7 @@ import postcss from 'postcss'
import webpack from 'webpack'
import { ConfigurationContext } from '../../../utils'
import { getClientStyleLoader } from './client'
import { cssFileResolve } from './file-resolve'
import { getCssModuleLocalIdent } from './getCssModuleLocalIdent'

export function getCssModuleLoader(
Expand Down Expand Up @@ -30,6 +31,9 @@ export function getCssModuleLoader(
sourceMap: true,
// Use CJS mode for backwards compatibility:
esModule: false,
url: cssFileResolve,
import: (url: string, _: any, resourcePath: string) =>
cssFileResolve(url, resourcePath),
modules: {
// Do not transform class names (CJS mode backwards compatibility):
exportLocalsConvention: 'asIs',
Expand Down
31 changes: 31 additions & 0 deletions test/integration/css-fixtures/unresolved-css-url/global.css
@@ -0,0 +1,31 @@
p {
background-image: url('/vercel.svg');
}

p:nth-child(1) {
background-image: url(/vercel.svg);
}

/* p:nth-child(2) {
background-image: url('./vercel.svg');
}
p:nth-child(3) {
background-image: url(./vercel.svg);
} */

p:nth-child(4) {
background-image: url('./public/vercel.svg');
}

p:nth-child(5) {
background-image: url(./public/vercel.svg);
}

div {
background-image: url('https://vercel.com/vercel.svg');
}

div:nth-child(1) {
background-image: url('https://vercel.com/vercel.svg');
}
31 changes: 31 additions & 0 deletions test/integration/css-fixtures/unresolved-css-url/global.scss
@@ -0,0 +1,31 @@
.p {
background-image: url('/vercel.svg');
}

.p:nth-child(1) {
background-image: url(/vercel.svg);
}

// .p:nth-child(2) {
// background-image: url('./vercel.svg');
// }

// .p:nth-child(3) {
// background-image: url(./vercel.svg);
// }

p:nth-child(4) {
background-image: url('./public/vercel.svg');
}

p:nth-child(5) {
background-image: url(./public/vercel.svg);
}

.div {
background-image: url('https://vercel.com/vercel.svg');
}

.div:nth-child(1) {
background-image: url('https://vercel.com/vercel.svg');
}
@@ -0,0 +1,6 @@
import '../global.css'
import '../global.scss'

export default function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
@@ -0,0 +1,5 @@
import styles from './another.module.scss'

export default function Page() {
return <p className={styles.first}>Hello from index</p>
}
@@ -0,0 +1,31 @@
.first {
background-image: url('/vercel.svg');
}

.first:nth-child(1) {
background-image: url(/vercel.svg);
}

// .first:nth-child(2) {
// background-image: url('./vercel.svg');
// }

// .first:nth-child(3) {
// background-image: url(./vercel.svg);
// }

.first:nth-child(4) {
background-image: url('../public/vercel.svg');
}

.first:nth-child(5) {
background-image: url(../public/vercel.svg);
}

.another {
background-image: url('https://vercel.com/vercel.svg');
}

.another:nth-child(1) {
background-image: url('https://vercel.com/vercel.svg');
}
@@ -0,0 +1,5 @@
import styles from './index.module.css'

export default function Page() {
return <p className={styles.first}>Hello from index</p>
}
@@ -0,0 +1,31 @@
.first {
background-image: url('/vercel.svg');
}

.first:nth-child(1) {
background-image: url(/vercel.svg);
}

/* .first:nth-child(2) {
background-image: url('./vercel.svg');
}
.first:nth-child(3) {
background-image: url(./vercel.svg);
} */

.first:nth-child(4) {
background-image: url('../public/vercel.svg');
}

.first:nth-child(5) {
background-image: url(../public/vercel.svg);
}

.another {
background-image: url('https://vercel.com/vercel.svg');
}

.another:nth-child(1) {
background-image: url('https://vercel.com/vercel.svg');
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 33 additions & 0 deletions test/integration/css/test/index.test.js
Expand Up @@ -1532,4 +1532,37 @@ describe('CSS Support', () => {
tests()
})
})

describe('should handle unresolved files gracefully', () => {
const workDir = join(fixturesDir, 'unresolved-css-url')

it('should build correctly', async () => {
await remove(join(workDir, '.next'))
const { code } = await nextBuild(workDir)
expect(code).toBe(0)
})

it('should have correct file references in CSS output', async () => {
const cssFiles = await readdir(join(workDir, '.next/static/css'))

for (const file of cssFiles) {
if (file.endsWith('.css.map')) continue

const content = await readFile(
join(workDir, '.next/static/css', file),
'utf8'
)
console.log(file, content)

// if it is the combined global CSS file there are double the expected
// results
const howMany = content.includes('p{') ? 4 : 2

expect(content.match(/\(\/vercel\.svg/g).length).toBe(howMany)
// expect(content.match(/\(vercel\.svg/g).length).toBe(howMany)
expect(content.match(/\(\/_next\/static\/media/g).length).toBe(2)
expect(content.match(/\(https:\/\//g).length).toBe(howMany)
}
})
})
})

0 comments on commit ec2ffb4

Please sign in to comment.