From 861ab1aa88be75e3f140a1f61819667da5660d09 Mon Sep 17 00:00:00 2001 From: Michel Kraemer Date: Sat, 6 Nov 2021 11:07:13 +0100 Subject: [PATCH 1/2] Fix disabling of built-in CSS support if there is a custom loader Fixes #30647 --- packages/next/build/webpack-config.ts | 23 +++++++++---- .../build/webpack/config/blocks/css/index.ts | 28 +++++++++------- .../css-customization/test/index.test.js | 32 +++++++++++++++++++ .../next.config.js | 20 ++++++++++++ .../pages/index.js | 10 ++++++ .../styles/index.css | 3 ++ 6 files changed, 97 insertions(+), 19 deletions(-) create mode 100644 test/integration/css-fixtures/custom-configuration-loader/next.config.js create mode 100644 test/integration/css-fixtures/custom-configuration-loader/pages/index.js create mode 100644 test/integration/css-fixtures/custom-configuration-loader/styles/index.css diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 71174550d9c0f..3a760f027303c 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -1888,13 +1888,22 @@ export default async function getBaseWebpackConfig( if (webpackConfig.module?.rules.length) { // Remove default CSS Loader - webpackConfig.module.rules = webpackConfig.module.rules.filter( - (r) => - !( - typeof r.oneOf?.[0]?.options === 'object' && - r.oneOf[0].options.__next_css_remove === true - ) - ) + webpackConfig.module.rules.forEach((r) => { + if (Array.isArray(r.oneOf)) { + let i = 0 + while (i < r.oneOf.length) { + let o: any = r.oneOf[i]?.options + if ( + typeof o === 'object' && + typeof o.__next_css_remove === 'number' + ) { + // Remove all CSS-related entries + r.oneOf.splice(i, o.__next_css_remove) + } + i++ + } + } + }) } if (webpackConfig.plugins?.length) { // Disable CSS Extraction Plugin diff --git a/packages/next/build/webpack/config/blocks/css/index.ts b/packages/next/build/webpack/config/blocks/css/index.ts index a9b9f6106e298..ced6c02d11c84 100644 --- a/packages/next/build/webpack/config/blocks/css/index.ts +++ b/packages/next/build/webpack/config/blocks/css/index.ts @@ -124,18 +124,7 @@ export const css = curry(async function css( }, ] - const fns: ConfigurationFn[] = [ - loader({ - oneOf: [ - { - // Impossible regex expression - test: /a^/, - loader: 'noop-loader', - options: { __next_css_remove: true }, - }, - ], - }), - ] + const fns: ConfigurationFn[] = [] const postCssPlugins = await getPostCssPlugins( ctx.rootDirectory, @@ -395,6 +384,21 @@ export const css = curry(async function css( ) } + fns.unshift( + loader({ + oneOf: [ + { + // Impossible regex expression + test: /a^/, + loader: 'noop-loader', + // Record the number of entries we need to remove if built-in CSS + // support is disabled + options: { __next_css_remove: fns.length + 1 }, + }, + ], + }) + ) + const fn = pipe(...fns) return fn(config) }) diff --git a/test/integration/css-customization/test/index.test.js b/test/integration/css-customization/test/index.test.js index 7b5abbdf02ed4..b99eabfcf5e49 100644 --- a/test/integration/css-customization/test/index.test.js +++ b/test/integration/css-customization/test/index.test.js @@ -142,6 +142,38 @@ describe('CSS Customization Array', () => { }) }) +describe('CSS Customization custom loader', () => { + const appDir = join(fixturesDir, 'custom-configuration-loader') + + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + + it('should compile successfully', async () => { + const { code, stdout, stderr } = await nextBuild(appDir, [], { + stdout: true, + stderr: true, + }) + expect(code).toBe(0) + expect(stderr).toMatch(/Built-in CSS support is being disabled/) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it(`should've applied style`, async () => { + const pagesFolder = join(appDir, '.next/static/chunks/pages') + + const files = await readdir(pagesFolder) + const indexFiles = files.filter((f) => /^index.+\.js$/.test(f)) + + expect(indexFiles.length).toBe(1) + const indexContent = await readFile( + join(pagesFolder, indexFiles[0]), + 'utf8' + ) + expect(indexContent).toMatch(/\.my-text\.jsx-[0-9a-z]+ {color:red}/) + }) +}) + describe('Bad CSS Customization', () => { const appDir = join(fixturesDir, 'bad-custom-configuration') diff --git a/test/integration/css-fixtures/custom-configuration-loader/next.config.js b/test/integration/css-fixtures/custom-configuration-loader/next.config.js new file mode 100644 index 0000000000000..c2286a6e1d124 --- /dev/null +++ b/test/integration/css-fixtures/custom-configuration-loader/next.config.js @@ -0,0 +1,20 @@ +const config = { + webpack: (config, { defaultLoaders }) => { + config.module.rules.push({ + test: /\.css$/, + use: [ + defaultLoaders.babel, + { + loader: require('styled-jsx/webpack').loader, + options: { + type: (fileName, options) => options.query.type || 'scoped', + }, + }, + ], + }) + + return config + }, +} + +module.exports = config diff --git a/test/integration/css-fixtures/custom-configuration-loader/pages/index.js b/test/integration/css-fixtures/custom-configuration-loader/pages/index.js new file mode 100644 index 0000000000000..e86f5eb6905f0 --- /dev/null +++ b/test/integration/css-fixtures/custom-configuration-loader/pages/index.js @@ -0,0 +1,10 @@ +import styles from '../styles/index.css' + +export default function Home() { + return ( + <> +
This text should be red.
+ + + ) +} diff --git a/test/integration/css-fixtures/custom-configuration-loader/styles/index.css b/test/integration/css-fixtures/custom-configuration-loader/styles/index.css new file mode 100644 index 0000000000000..167caa35ea86e --- /dev/null +++ b/test/integration/css-fixtures/custom-configuration-loader/styles/index.css @@ -0,0 +1,3 @@ +.my-text { + color: red; +} From 8e1933151842ec6c6770ec3272025596c0eaf424 Mon Sep 17 00:00:00 2001 From: Michel Kraemer Date: Mon, 15 Nov 2021 23:30:50 +0100 Subject: [PATCH 2/2] Use non-enumerable symbol to mark CSS loaders that can be removed --- packages/next/build/webpack-config.ts | 17 +---- .../build/webpack/config/blocks/css/index.ts | 74 +++++++++---------- 2 files changed, 41 insertions(+), 50 deletions(-) diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index fcd7811c241ac..ecd2e8cb6097a 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -1868,21 +1868,12 @@ export default async function getBaseWebpackConfig( } if (webpackConfig.module?.rules.length) { - // Remove default CSS Loader + // Remove default CSS Loaders webpackConfig.module.rules.forEach((r) => { if (Array.isArray(r.oneOf)) { - let i = 0 - while (i < r.oneOf.length) { - let o: any = r.oneOf[i]?.options - if ( - typeof o === 'object' && - typeof o.__next_css_remove === 'number' - ) { - // Remove all CSS-related entries - r.oneOf.splice(i, o.__next_css_remove) - } - i++ - } + r.oneOf = r.oneOf.filter( + (o) => (o as any)[Symbol.for('__next_css_remove')] !== true + ) } }) } diff --git a/packages/next/build/webpack/config/blocks/css/index.ts b/packages/next/build/webpack/config/blocks/css/index.ts index ced6c02d11c84..18991bd7d17ca 100644 --- a/packages/next/build/webpack/config/blocks/css/index.ts +++ b/packages/next/build/webpack/config/blocks/css/index.ts @@ -86,6 +86,21 @@ const regexCssModules = /\.module\.css$/ const regexSassGlobal = /(?