diff --git a/.gitignore b/.gitignore index a610b8f09ae7c..a1e1b057fd451 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ test/node_modules # logs & pids *.log pids +*.cpuprofile # coverage .nyc_output @@ -41,4 +42,4 @@ test-timings.json .now # Cache -*.tsbuildinfo \ No newline at end of file +*.tsbuildinfo diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 36b04d85ebdc3..33becc9406aae 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -33,7 +33,6 @@ import { NextConfigComplete } from '../server/config-shared' import { finalizeEntrypoint } from './entries' import * as Log from './output/log' import { build as buildConfiguration } from './webpack/config' -import { __overrideCssConfiguration } from './webpack/config/blocks/css/overrideCssConfiguration' import MiddlewarePlugin from './webpack/plugins/middleware-plugin' import BuildManifestPlugin from './webpack/plugins/build-manifest-plugin' import { JsConfigPathsPlugin } from './webpack/plugins/jsconfig-paths-plugin' @@ -1890,8 +1889,6 @@ export default async function getBaseWebpackConfig( (e) => (e as any).__next_css_remove !== true ) } - } else if (!config.future.strictPostcssConfiguration) { - await __overrideCssConfiguration(dir, supportedBrowsers, webpackConfig) } // Inject missing React Refresh loaders so that development mode is fast: diff --git a/packages/next/build/webpack/config/blocks/css/index.ts b/packages/next/build/webpack/config/blocks/css/index.ts index a9b9f6106e298..4b0219dbaeb7b 100644 --- a/packages/next/build/webpack/config/blocks/css/index.ts +++ b/packages/next/build/webpack/config/blocks/css/index.ts @@ -11,69 +11,6 @@ import { getLocalModuleImportError, } from './messages' import { getPostCssPlugins } from './plugins' -import postcss from 'postcss' - -// @ts-ignore backwards compat -postcss.plugin = function postcssPlugin(name, initializer) { - function creator(...args: any) { - let transformer = initializer(...args) - transformer.postcssPlugin = name - // transformer.postcssVersion = new Processor().version - return transformer - } - - let cache: any - Object.defineProperty(creator, 'postcss', { - get() { - if (!cache) cache = creator() - return cache - }, - }) - - creator.process = function (css: any, processOpts: any, pluginOpts: any) { - return postcss([creator(pluginOpts)]).process(css, processOpts) - } - - return creator -} - -// @ts-ignore backwards compat -postcss.vendor = { - /** - * Returns the vendor prefix extracted from an input string. - * - * @param {string} prop String with or without vendor prefix. - * - * @return {string} vendor prefix or empty string - * - * @example - * postcss.vendor.prefix('-moz-tab-size') //=> '-moz-' - * postcss.vendor.prefix('tab-size') //=> '' - */ - prefix: function prefix(prop: any) { - const match = prop.match(/^(-\w+-)/) - - if (match) { - return match[0] - } - - return '' - }, - - /** - * Returns the input string stripped of its vendor prefix. - * - * @param {string} prop String with or without vendor prefix. - * - * @return {string} String name without vendor prefixes. - * - * @example - * postcss.vendor.unprefixed('-moz-tab-size') //=> 'tab-size' - */ - unprefixed: function unprefixed(prop: any) { - return prop.replace(/^-\w+-/, '') - }, -} // RegExps for all Style Sheet variants export const regexLikeCss = /\.(css|scss|sass)$/ @@ -86,6 +23,99 @@ const regexCssModules = /\.module\.css$/ const regexSassGlobal = /(? +export async function lazyPostCSS( + rootDirectory: string, + supportedBrowsers: string[] | undefined, + strictPostcssConfiguration: boolean | undefined, + disablePostcssPresetEnv: boolean | undefined +) { + if (!postcssInstancePromise) { + postcssInstancePromise = (async () => { + const postcss = require('postcss') + // @ts-ignore backwards compat + postcss.plugin = function postcssPlugin(name, initializer) { + function creator(...args: any) { + let transformer = initializer(...args) + transformer.postcssPlugin = name + // transformer.postcssVersion = new Processor().version + return transformer + } + + let cache: any + Object.defineProperty(creator, 'postcss', { + get() { + if (!cache) cache = creator() + return cache + }, + }) + + creator.process = function ( + css: any, + processOpts: any, + pluginOpts: any + ) { + return postcss([creator(pluginOpts)]).process(css, processOpts) + } + + return creator + } + + // @ts-ignore backwards compat + postcss.vendor = { + /** + * Returns the vendor prefix extracted from an input string. + * + * @param {string} prop String with or without vendor prefix. + * + * @return {string} vendor prefix or empty string + * + * @example + * postcss.vendor.prefix('-moz-tab-size') //=> '-moz-' + * postcss.vendor.prefix('tab-size') //=> '' + */ + prefix: function prefix(prop: any) { + const match = prop.match(/^(-\w+-)/) + + if (match) { + return match[0] + } + + return '' + }, + + /** + * Returns the input string stripped of its vendor prefix. + * + * @param {string} prop String with or without vendor prefix. + * + * @return {string} String name without vendor prefixes. + * + * @example + * postcss.vendor.unprefixed('-moz-tab-size') //=> 'tab-size' + */ + unprefixed: function unprefixed(prop: any) { + return prop.replace(/^-\w+-/, '') + }, + } + + const postCssPlugins = await getPostCssPlugins( + rootDirectory, + supportedBrowsers, + strictPostcssConfiguration, + disablePostcssPresetEnv + ) + + return { + postcss, + postcssWithPlugins: postcss(postCssPlugins), + } + })() + } + + return postcssInstancePromise +} + export const css = curry(async function css( ctx: ConfigurationContext, config: webpack.Configuration @@ -96,6 +126,14 @@ export const css = curry(async function css( ...sassOptions } = ctx.sassOptions + const lazyPostCSSInitalizer = () => + lazyPostCSS( + ctx.rootDirectory, + ctx.supportedBrowsers, + ctx.future.strictPostcssConfiguration, + ctx.experimental.disablePostcssPresetEnv + ) + const sassPreprocessors: webpack.RuleSetUseItem[] = [ // First, process files with `sass-loader`: this inlines content, and // compiles away the proprietary syntax. @@ -137,12 +175,6 @@ export const css = curry(async function css( }), ] - const postCssPlugins = await getPostCssPlugins( - ctx.rootDirectory, - ctx.supportedBrowsers, - !ctx.future.strictPostcssConfiguration - ) - // CSS cannot be imported in _document. This comes before everything because // global CSS nor CSS modules work in said file. fns.push( @@ -183,7 +215,7 @@ export const css = curry(async function css( and: [ctx.rootDirectory], not: [/node_modules/], }, - use: getCssModuleLoader(ctx, postCssPlugins), + use: getCssModuleLoader(ctx, lazyPostCSSInitalizer), }, ], }) @@ -206,7 +238,11 @@ export const css = curry(async function css( and: [ctx.rootDirectory], not: [/node_modules/], }, - use: getCssModuleLoader(ctx, postCssPlugins, sassPreprocessors), + use: getCssModuleLoader( + ctx, + lazyPostCSSInitalizer, + sassPreprocessors + ), }, ], }) @@ -266,7 +302,7 @@ export const css = curry(async function css( and: [ctx.rootDirectory], not: [/node_modules/], }, - use: getGlobalCssLoader(ctx, postCssPlugins), + use: getGlobalCssLoader(ctx, lazyPostCSSInitalizer), }, ], }) @@ -284,7 +320,7 @@ export const css = curry(async function css( sideEffects: true, test: regexCssGlobal, issuer: { and: [ctx.customAppFile] }, - use: getGlobalCssLoader(ctx, postCssPlugins), + use: getGlobalCssLoader(ctx, lazyPostCSSInitalizer), }, ], }) @@ -300,7 +336,11 @@ export const css = curry(async function css( sideEffects: true, test: regexSassGlobal, issuer: { and: [ctx.customAppFile] }, - use: getGlobalCssLoader(ctx, postCssPlugins, sassPreprocessors), + use: getGlobalCssLoader( + ctx, + lazyPostCSSInitalizer, + sassPreprocessors + ), }, ], }) diff --git a/packages/next/build/webpack/config/blocks/css/loaders/global.ts b/packages/next/build/webpack/config/blocks/css/loaders/global.ts index e57b84af6a386..8d55c0cca5bd9 100644 --- a/packages/next/build/webpack/config/blocks/css/loaders/global.ts +++ b/packages/next/build/webpack/config/blocks/css/loaders/global.ts @@ -1,13 +1,11 @@ -import { AcceptedPlugin } from 'postcss' import { webpack } from 'next/dist/compiled/webpack/webpack' import { ConfigurationContext } from '../../../utils' import { getClientStyleLoader } from './client' import { cssFileResolve } from './file-resolve' -import postcss from 'postcss' export function getGlobalCssLoader( ctx: ConfigurationContext, - postCssPlugins: AcceptedPlugin[], + postcss: any, preProcessors: readonly webpack.RuleSetUseItem[] = [] ): webpack.RuleSetUseItem[] { const loaders: webpack.RuleSetUseItem[] = [] @@ -27,6 +25,7 @@ export function getGlobalCssLoader( loaders.push({ loader: require.resolve('../../../../loaders/css-loader/src'), options: { + postcss, importLoaders: 1 + preProcessors.length, // Next.js controls CSS Modules eligibility: modules: false, @@ -41,7 +40,7 @@ export function getGlobalCssLoader( loaders.push({ loader: require.resolve('../../../../loaders/postcss-loader/src'), options: { - postcss: postcss(postCssPlugins), + postcss, }, }) diff --git a/packages/next/build/webpack/config/blocks/css/loaders/modules.ts b/packages/next/build/webpack/config/blocks/css/loaders/modules.ts index f7ed65c8a4f51..94ebceb727f3c 100644 --- a/packages/next/build/webpack/config/blocks/css/loaders/modules.ts +++ b/packages/next/build/webpack/config/blocks/css/loaders/modules.ts @@ -1,14 +1,12 @@ -import { AcceptedPlugin } from 'postcss' import { webpack } from 'next/dist/compiled/webpack/webpack' import { ConfigurationContext } from '../../../utils' import { getClientStyleLoader } from './client' import { cssFileResolve } from './file-resolve' import { getCssModuleLocalIdent } from './getCssModuleLocalIdent' -import postcss from 'postcss' export function getCssModuleLoader( ctx: ConfigurationContext, - postCssPlugins: AcceptedPlugin[], + postcss: any, preProcessors: readonly webpack.RuleSetUseItem[] = [] ): webpack.RuleSetUseItem[] { const loaders: webpack.RuleSetUseItem[] = [] @@ -28,6 +26,7 @@ export function getCssModuleLoader( loaders.push({ loader: require.resolve('../../../../loaders/css-loader/src'), options: { + postcss, importLoaders: 1 + preProcessors.length, // Use CJS mode for backwards compatibility: esModule: false, @@ -57,7 +56,7 @@ export function getCssModuleLoader( loaders.push({ loader: require.resolve('../../../../loaders/postcss-loader/src'), options: { - postcss: postcss(postCssPlugins), + postcss, }, }) diff --git a/packages/next/build/webpack/config/blocks/css/overrideCssConfiguration.ts b/packages/next/build/webpack/config/blocks/css/overrideCssConfiguration.ts deleted file mode 100644 index 7cd34d1f02112..0000000000000 --- a/packages/next/build/webpack/config/blocks/css/overrideCssConfiguration.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { webpack } from 'next/dist/compiled/webpack/webpack' -import { getPostCssPlugins } from './plugins' -import postcss from 'postcss' - -export async function __overrideCssConfiguration( - rootDirectory: string, - supportedBrowsers: string[] | undefined, - config: webpack.Configuration -) { - const postCssPlugins = await getPostCssPlugins( - rootDirectory, - supportedBrowsers - ) - - function patch(rule: webpack.RuleSetRule) { - if ( - rule.options && - typeof rule.options === 'object' && - typeof rule.options.postcssOptions === 'object' - ) { - rule.options.postcssOptions.plugins = postCssPlugins - } else if ( - rule.options && - typeof rule.options === 'object' && - typeof rule.options.postcss !== 'undefined' - ) { - rule.options.postcss = postcss(postCssPlugins) - } else if (Array.isArray(rule.oneOf)) { - rule.oneOf.forEach(patch) - } else if (Array.isArray(rule.use)) { - rule.use.forEach((u) => { - if (typeof u === 'object') { - patch(u) - } - }) - } - } - - config.module?.rules?.forEach((entry) => { - patch(entry) - }) -} diff --git a/packages/next/build/webpack/config/blocks/css/plugins.ts b/packages/next/build/webpack/config/blocks/css/plugins.ts index f554e1137bc4c..025ad3ea9caec 100644 --- a/packages/next/build/webpack/config/blocks/css/plugins.ts +++ b/packages/next/build/webpack/config/blocks/css/plugins.ts @@ -88,40 +88,46 @@ async function loadPlugin( } function getDefaultPlugins( - supportedBrowsers: string[] | undefined -): CssPluginCollection { + supportedBrowsers: string[] | undefined, + disablePostcssPresetEnv: boolean +): any[] { return [ require.resolve('next/dist/compiled/postcss-flexbugs-fixes'), - [ - require.resolve('next/dist/compiled/postcss-preset-env'), - { - browsers: supportedBrowsers ?? ['defaults'], - autoprefixer: { - // Disable legacy flexbox support - flexbox: 'no-2009', - }, - // Enable CSS features that have shipped to the - // web platform, i.e. in 2+ browsers unflagged. - stage: 3, - features: { - 'custom-properties': false, - }, - }, - ], - ] + disablePostcssPresetEnv + ? false + : [ + require.resolve('next/dist/compiled/postcss-preset-env'), + { + browsers: supportedBrowsers ?? ['defaults'], + autoprefixer: { + // Disable legacy flexbox support + flexbox: 'no-2009', + }, + // Enable CSS features that have shipped to the + // web platform, i.e. in 2+ browsers unflagged. + stage: 3, + features: { + 'custom-properties': false, + }, + }, + ], + ].filter(Boolean) } export async function getPostCssPlugins( dir: string, supportedBrowsers: string[] | undefined, - defaults: boolean = false + defaults: boolean = false, + disablePostcssPresetEnv: boolean = false ): Promise { let config = defaults ? null : await findConfig<{ plugins: CssPluginCollection }>(dir, 'postcss') if (config == null) { - config = { plugins: getDefaultPlugins(supportedBrowsers) } + config = { + plugins: getDefaultPlugins(supportedBrowsers, disablePostcssPresetEnv), + } } if (typeof config === 'function') { diff --git a/packages/next/build/webpack/loaders/css-loader/src/index.js b/packages/next/build/webpack/loaders/css-loader/src/index.js index 32ceb4c5facf5..eae004f556ea7 100644 --- a/packages/next/build/webpack/loaders/css-loader/src/index.js +++ b/packages/next/build/webpack/loaders/css-loader/src/index.js @@ -2,28 +2,135 @@ MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ -import postcss from 'postcss' - import CssSyntaxError from './CssSyntaxError' import Warning from '../../postcss-loader/src/Warning' -import { icssParser, importParser, urlParser } from './plugins' -import { - normalizeOptions, - shouldUseModulesPlugins, - shouldUseImportPlugin, - shouldUseURLPlugin, - shouldUseIcssPlugin, - getPreRequester, - getExportCode, - getFilter, - getImportCode, - getModuleCode, - getModulesPlugins, - normalizeSourceMap, - sort, -} from './utils' +// import { icssParser, importParser, urlParser } from './plugins' import { stringifyRequest } from '../../../stringify-request' +const moduleRegExp = /\.module\.\w+$/i + +function getModulesOptions(rawOptions, loaderContext) { + const { resourcePath } = loaderContext + + if (typeof rawOptions.modules === 'undefined') { + const isModules = moduleRegExp.test(resourcePath) + + if (!isModules) { + return false + } + } else if ( + typeof rawOptions.modules === 'boolean' && + rawOptions.modules === false + ) { + return false + } + + let modulesOptions = { + compileType: rawOptions.icss ? 'icss' : 'module', + auto: true, + mode: 'local', + exportGlobals: false, + localIdentName: '[hash:base64]', + localIdentContext: loaderContext.rootContext, + localIdentHashPrefix: '', + // eslint-disable-next-line no-undefined + localIdentRegExp: undefined, + namedExport: false, + exportLocalsConvention: 'asIs', + exportOnlyLocals: false, + } + + if ( + typeof rawOptions.modules === 'boolean' || + typeof rawOptions.modules === 'string' + ) { + modulesOptions.mode = + typeof rawOptions.modules === 'string' ? rawOptions.modules : 'local' + } else { + if (rawOptions.modules) { + if (typeof rawOptions.modules.auto === 'boolean') { + const isModules = + rawOptions.modules.auto && moduleRegExp.test(resourcePath) + + if (!isModules) { + return false + } + } else if (rawOptions.modules.auto instanceof RegExp) { + const isModules = rawOptions.modules.auto.test(resourcePath) + + if (!isModules) { + return false + } + } else if (typeof rawOptions.modules.auto === 'function') { + const isModule = rawOptions.modules.auto(resourcePath) + + if (!isModule) { + return false + } + } + + if ( + rawOptions.modules.namedExport === true && + typeof rawOptions.modules.exportLocalsConvention === 'undefined' + ) { + modulesOptions.exportLocalsConvention = 'camelCaseOnly' + } + } + + modulesOptions = { ...modulesOptions, ...(rawOptions.modules || {}) } + } + + if (typeof modulesOptions.mode === 'function') { + modulesOptions.mode = modulesOptions.mode(loaderContext.resourcePath) + } + + if (modulesOptions.namedExport === true) { + if (rawOptions.esModule === false) { + throw new Error( + 'The "modules.namedExport" option requires the "esModules" option to be enabled' + ) + } + + if (modulesOptions.exportLocalsConvention !== 'camelCaseOnly') { + throw new Error( + 'The "modules.namedExport" option requires the "modules.exportLocalsConvention" option to be "camelCaseOnly"' + ) + } + } + + return modulesOptions +} + +function normalizeOptions(rawOptions, loaderContext) { + if (rawOptions.icss) { + loaderContext.emitWarning( + new Error( + 'The "icss" option is deprecated, use "modules.compileType: "icss"" instead' + ) + ) + } + + const modulesOptions = getModulesOptions(rawOptions, loaderContext) + + return { + url: typeof rawOptions.url === 'undefined' ? true : rawOptions.url, + import: typeof rawOptions.import === 'undefined' ? true : rawOptions.import, + modules: modulesOptions, + // TODO remove in the next major release + icss: typeof rawOptions.icss === 'undefined' ? false : rawOptions.icss, + sourceMap: + typeof rawOptions.sourceMap === 'boolean' + ? rawOptions.sourceMap + : loaderContext.sourceMap, + importLoaders: + typeof rawOptions.importLoaders === 'string' + ? parseInt(rawOptions.importLoaders, 10) + : rawOptions.importLoaders, + esModule: + typeof rawOptions.esModule === 'undefined' ? true : rawOptions.esModule, + } +} + export default async function loader(content, map, meta) { const rawOptions = this.getOptions() @@ -42,6 +149,25 @@ export default async function loader(content, map, meta) { throw error } + const { postcss } = await rawOptions.postcss() + + const { + shouldUseModulesPlugins, + shouldUseImportPlugin, + shouldUseURLPlugin, + shouldUseIcssPlugin, + getPreRequester, + getExportCode, + getFilter, + getImportCode, + getModuleCode, + getModulesPlugins, + normalizeSourceMap, + sort, + } = require('./utils') + + const { icssParser, importParser, urlParser } = require('./plugins') + const replacements = [] const exports = [] diff --git a/packages/next/build/webpack/loaders/css-loader/src/utils.js b/packages/next/build/webpack/loaders/css-loader/src/utils.js index 462de89eeaa56..d3e1198e5fcf0 100644 --- a/packages/next/build/webpack/loaders/css-loader/src/utils.js +++ b/packages/next/build/webpack/loaders/css-loader/src/utils.js @@ -81,130 +81,6 @@ function getFilter(filter, resourcePath) { } } -const moduleRegExp = /\.module\.\w+$/i - -function getModulesOptions(rawOptions, loaderContext) { - const { resourcePath } = loaderContext - - if (typeof rawOptions.modules === 'undefined') { - const isModules = moduleRegExp.test(resourcePath) - - if (!isModules) { - return false - } - } else if ( - typeof rawOptions.modules === 'boolean' && - rawOptions.modules === false - ) { - return false - } - - let modulesOptions = { - compileType: rawOptions.icss ? 'icss' : 'module', - auto: true, - mode: 'local', - exportGlobals: false, - localIdentName: '[hash:base64]', - localIdentContext: loaderContext.rootContext, - localIdentHashPrefix: '', - // eslint-disable-next-line no-undefined - localIdentRegExp: undefined, - namedExport: false, - exportLocalsConvention: 'asIs', - exportOnlyLocals: false, - } - - if ( - typeof rawOptions.modules === 'boolean' || - typeof rawOptions.modules === 'string' - ) { - modulesOptions.mode = - typeof rawOptions.modules === 'string' ? rawOptions.modules : 'local' - } else { - if (rawOptions.modules) { - if (typeof rawOptions.modules.auto === 'boolean') { - const isModules = - rawOptions.modules.auto && moduleRegExp.test(resourcePath) - - if (!isModules) { - return false - } - } else if (rawOptions.modules.auto instanceof RegExp) { - const isModules = rawOptions.modules.auto.test(resourcePath) - - if (!isModules) { - return false - } - } else if (typeof rawOptions.modules.auto === 'function') { - const isModule = rawOptions.modules.auto(resourcePath) - - if (!isModule) { - return false - } - } - - if ( - rawOptions.modules.namedExport === true && - typeof rawOptions.modules.exportLocalsConvention === 'undefined' - ) { - modulesOptions.exportLocalsConvention = 'camelCaseOnly' - } - } - - modulesOptions = { ...modulesOptions, ...(rawOptions.modules || {}) } - } - - if (typeof modulesOptions.mode === 'function') { - modulesOptions.mode = modulesOptions.mode(loaderContext.resourcePath) - } - - if (modulesOptions.namedExport === true) { - if (rawOptions.esModule === false) { - throw new Error( - 'The "modules.namedExport" option requires the "esModules" option to be enabled' - ) - } - - if (modulesOptions.exportLocalsConvention !== 'camelCaseOnly') { - throw new Error( - 'The "modules.namedExport" option requires the "modules.exportLocalsConvention" option to be "camelCaseOnly"' - ) - } - } - - return modulesOptions -} - -function normalizeOptions(rawOptions, loaderContext) { - if (rawOptions.icss) { - loaderContext.emitWarning( - new Error( - 'The "icss" option is deprecated, use "modules.compileType: "icss"" instead' - ) - ) - } - - const modulesOptions = getModulesOptions(rawOptions, loaderContext) - - return { - url: typeof rawOptions.url === 'undefined' ? true : rawOptions.url, - import: typeof rawOptions.import === 'undefined' ? true : rawOptions.import, - modules: modulesOptions, - // TODO remove in the next major release - icss: typeof rawOptions.icss === 'undefined' ? false : rawOptions.icss, - sourceMap: - typeof rawOptions.sourceMap === 'boolean' - ? rawOptions.sourceMap - : loaderContext.sourceMap, - importLoaders: - typeof rawOptions.importLoaders === 'string' - ? parseInt(rawOptions.importLoaders, 10) - : rawOptions.importLoaders, - esModule: - typeof rawOptions.esModule === 'undefined' ? true : rawOptions.esModule, - } -} - function shouldUseImportPlugin(options) { if (options.modules.exportOnlyLocals) { return false @@ -632,7 +508,6 @@ function isDataUrl(url) { export { isDataUrl, - normalizeOptions, shouldUseModulesPlugins, shouldUseImportPlugin, shouldUseURLPlugin, @@ -640,7 +515,6 @@ export { normalizeUrl, requestify, getFilter, - getModulesOptions, getModulesPlugins, normalizeSourceMap, getPreRequester, diff --git a/packages/next/build/webpack/loaders/postcss-loader/src/index.js b/packages/next/build/webpack/loaders/postcss-loader/src/index.js index f43533fcdb292..2e9dc8dc99062 100644 --- a/packages/next/build/webpack/loaders/postcss-loader/src/index.js +++ b/packages/next/build/webpack/loaders/postcss-loader/src/index.js @@ -56,13 +56,16 @@ export default async function loader(content, sourceMap, meta) { loaderSpan.setAttribute('astUsed', 'true') } + // Initializes postcss with plugins + const { postcssWithPlugins } = await options.postcss() + let result try { result = await loaderSpan .traceChild('postcss-process') .traceAsyncFn(() => - options.postcss.process(root || content, processOptions) + postcssWithPlugins.process(root || content, processOptions) ) } catch (error) { if (error.file) { diff --git a/packages/next/server/config-shared.ts b/packages/next/server/config-shared.ts index b15a32f39117a..b2be0bcefbb23 100644 --- a/packages/next/server/config-shared.ts +++ b/packages/next/server/config-shared.ts @@ -126,6 +126,7 @@ export type NextConfig = { [key: string]: any } & { crossOrigin?: false | 'anonymous' | 'use-credentials' swcMinify?: boolean experimental?: { + disablePostcssPresetEnv?: boolean removeConsole?: | boolean | { diff --git a/test/integration/css-customization/test/index.test.js b/test/integration/css-customization/test/index.test.js index 7b5abbdf02ed4..0468d5e4da3f4 100644 --- a/test/integration/css-customization/test/index.test.js +++ b/test/integration/css-customization/test/index.test.js @@ -208,7 +208,7 @@ describe('Bad CSS Customization Array (1)', () => { expect(stderr).toMatch( /A PostCSS Plugin was passed as an array but did not provide its configuration \('postcss-trolling'\)/ ) - expect(stderr).toMatch(/Build error occurred/) + expect(stderr).toMatch(/Build failed because of webpack errors/) }) }) @@ -228,7 +228,7 @@ describe('Bad CSS Customization Array (2)', () => { expect(stderr).toMatch( /To disable 'postcss-trolling', pass false, otherwise, pass true or a configuration object./ ) - expect(stderr).toMatch(/Build error occurred/) + expect(stderr).toMatch(/Build failed because of webpack errors/) }) }) @@ -245,7 +245,7 @@ describe('Bad CSS Customization Array (3)', () => { expect(stderr).toMatch( /A PostCSS Plugin must be provided as a string. Instead, we got: '5'/ ) - expect(stderr).toMatch(/Build error occurred/) + expect(stderr).toMatch(/Build failed because of webpack errors/) }) }) @@ -260,7 +260,7 @@ describe('Bad CSS Customization Array (4)', () => { const { stderr } = await nextBuild(appDir, [], { stderr: true }) expect(stderr).toMatch(/An unknown PostCSS plugin was provided \(5\)/) - expect(stderr).toMatch(/Build error occurred/) + expect(stderr).toMatch(/Build failed because of webpack errors/) }) }) @@ -277,7 +277,7 @@ describe('Bad CSS Customization Array (5)', () => { expect(stderr).toMatch( /Your custom PostCSS configuration must export a `plugins` key./ ) - expect(stderr).toMatch(/Build error occurred/) + expect(stderr).toMatch(/Build failed because of webpack errors/) }) }) @@ -294,7 +294,7 @@ describe('Bad CSS Customization Array (6)', () => { expect(stderr).toMatch( /Your custom PostCSS configuration must export a `plugins` key./ ) - expect(stderr).toMatch(/Build error occurred/) + expect(stderr).toMatch(/Build failed because of webpack errors/) }) }) @@ -311,7 +311,7 @@ describe('Bad CSS Customization Array (7)', () => { expect(stderr).toMatch( /A PostCSS Plugin was passed as an array but did not provide its configuration \('postcss-trolling'\)/ ) - expect(stderr).toMatch(/Build error occurred/) + expect(stderr).toMatch(/Build failed because of webpack errors/) }) }) @@ -328,7 +328,7 @@ describe('Bad CSS Customization Array (8)', () => { expect(stderr).toMatch( /A PostCSS Plugin was passed as a function using require\(\), but it must be provided as a string/ ) - expect(stderr).toMatch(/Build error occurred/) + expect(stderr).toMatch(/Build failed because of webpack errors/) }) }) @@ -345,6 +345,6 @@ describe('Bad CSS Customization Function', () => { expect(stderr).toMatch( /Your custom PostCSS configuration may not export a function/ ) - expect(stderr).toMatch(/Build error occurred/) + expect(stderr).toMatch(/Build failed because of webpack errors/) }) })