From 4fd39d91707271f42dceefb06e7a812921605b5b Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Sat, 4 Dec 2021 19:42:16 +0100 Subject: [PATCH] Revert "Lazy-load postcss (#31762)" This reverts commit 92b397f2b7c742abb11669efc580d3fd8c438ddc. --- .gitignore | 3 +- packages/next/build/webpack-config.ts | 3 + .../build/webpack/config/blocks/css/index.ts | 255 ++++++++---------- .../config/blocks/css/loaders/global.ts | 7 +- .../config/blocks/css/loaders/modules.ts | 7 +- .../blocks/css/overrideCssConfiguration.ts | 42 +++ .../webpack/config/blocks/css/plugins.ts | 54 ++-- .../webpack/loaders/css-loader/src/index.js | 162 ++--------- .../webpack/loaders/css-loader/src/utils.js | 126 +++++++++ .../loaders/postcss-loader/src/index.js | 5 +- packages/next/server/config-shared.ts | 1 - .../css-customization/test/index.test.js | 18 +- 12 files changed, 339 insertions(+), 344 deletions(-) create mode 100644 packages/next/build/webpack/config/blocks/css/overrideCssConfiguration.ts diff --git a/.gitignore b/.gitignore index a1e1b057fd451f..a610b8f09ae7cc 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,6 @@ test/node_modules # logs & pids *.log pids -*.cpuprofile # coverage .nyc_output @@ -42,4 +41,4 @@ test-timings.json .now # Cache -*.tsbuildinfo +*.tsbuildinfo \ No newline at end of file diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index c50df8b8c0340c..d4bc3a66016d16 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -33,6 +33,7 @@ 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,6 +1891,8 @@ 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 61576638150f9f..a9b9f6106e298b 100644 --- a/packages/next/build/webpack/config/blocks/css/index.ts +++ b/packages/next/build/webpack/config/blocks/css/index.ts @@ -11,123 +11,80 @@ import { getLocalModuleImportError, } from './messages' import { getPostCssPlugins } from './plugins' +import postcss from 'postcss' -// RegExps for all Style Sheet variants -export const regexLikeCss = /\.(css|scss|sass)$/ - -// RegExps for Style Sheets -const regexCssGlobal = /(? -export async function lazyPostCSS( - rootDirectory: string, - supportedBrowsers: string[] | 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) - } + creator.process = function (css: any, processOpts: any, pluginOpts: any) { + return postcss([creator(pluginOpts)]).process(css, processOpts) + } - return creator - } + 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+-)/) +// @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] - } + if (match) { + return match[0] + } - return '' - }, + 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+-/, '') - }, - } + /** + * 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, - disablePostcssPresetEnv - ) +// RegExps for all Style Sheet variants +export const regexLikeCss = /\.(css|scss|sass)$/ - return { - postcss, - postcssWithPlugins: postcss(postCssPlugins), - } - })() - } +// RegExps for Style Sheets +const regexCssGlobal = /(? - lazyPostCSS( - ctx.rootDirectory, - ctx.supportedBrowsers, - ctx.experimental.disablePostcssPresetEnv - ) - const sassPreprocessors: webpack.RuleSetUseItem[] = [ // First, process files with `sass-loader`: this inlines content, and // compiles away the proprietary syntax. @@ -174,14 +124,31 @@ export const css = curry(async function css( }, ] - const fns: ConfigurationFn[] = [] + const fns: ConfigurationFn[] = [ + loader({ + oneOf: [ + { + // Impossible regex expression + test: /a^/, + loader: 'noop-loader', + options: { __next_css_remove: true }, + }, + ], + }), + ] + + 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( loader({ oneOf: [ - markRemovable({ + { test: regexLikeCss, // Use a loose regex so we don't have to crawl the file system to // find the real file name (if present). @@ -192,7 +159,7 @@ export const css = curry(async function css( reason: getCustomDocumentError(), }, }, - }), + }, ], }) ) @@ -202,7 +169,7 @@ export const css = curry(async function css( fns.push( loader({ oneOf: [ - markRemovable({ + { // CSS Modules should never have side effects. This setting will // allow unused CSS to be removed from the production build. // We ensure this by disallowing `:global()` CSS at the top-level @@ -216,8 +183,8 @@ export const css = curry(async function css( and: [ctx.rootDirectory], not: [/node_modules/], }, - use: getCssModuleLoader(ctx, lazyPostCSSInitalizer), - }), + use: getCssModuleLoader(ctx, postCssPlugins), + }, ], }) ) @@ -225,7 +192,7 @@ export const css = curry(async function css( loader({ oneOf: [ // Opt-in support for Sass (using .scss or .sass extensions). - markRemovable({ + { // Sass Modules should never have side effects. This setting will // allow unused Sass to be removed from the production build. // We ensure this by disallowing `:global()` Sass at the top-level @@ -239,12 +206,8 @@ export const css = curry(async function css( and: [ctx.rootDirectory], not: [/node_modules/], }, - use: getCssModuleLoader( - ctx, - lazyPostCSSInitalizer, - sassPreprocessors - ), - }), + use: getCssModuleLoader(ctx, postCssPlugins, sassPreprocessors), + }, ], }) ) @@ -253,7 +216,7 @@ export const css = curry(async function css( fns.push( loader({ oneOf: [ - markRemovable({ + { test: [regexCssModules, regexSassModules], use: { loader: 'error-loader', @@ -261,7 +224,7 @@ export const css = curry(async function css( reason: getLocalModuleImportError(), }, }, - }), + }, ], }) ) @@ -270,10 +233,10 @@ export const css = curry(async function css( fns.push( loader({ oneOf: [ - markRemovable({ + { test: [regexCssGlobal, regexSassGlobal], use: require.resolve('next/dist/compiled/ignore-loader'), - }), + }, ], }) ) @@ -281,7 +244,7 @@ export const css = curry(async function css( fns.push( loader({ oneOf: [ - markRemovable({ + { // A global CSS import always has side effects. Webpack will tree // shake the CSS without this option if the issuer claims to have // no side-effects. @@ -303,8 +266,8 @@ export const css = curry(async function css( and: [ctx.rootDirectory], not: [/node_modules/], }, - use: getGlobalCssLoader(ctx, lazyPostCSSInitalizer), - }), + use: getGlobalCssLoader(ctx, postCssPlugins), + }, ], }) ) @@ -313,7 +276,7 @@ export const css = curry(async function css( fns.push( loader({ oneOf: [ - markRemovable({ + { // A global CSS import always has side effects. Webpack will tree // shake the CSS without this option if the issuer claims to have // no side-effects. @@ -321,15 +284,15 @@ export const css = curry(async function css( sideEffects: true, test: regexCssGlobal, issuer: { and: [ctx.customAppFile] }, - use: getGlobalCssLoader(ctx, lazyPostCSSInitalizer), - }), + use: getGlobalCssLoader(ctx, postCssPlugins), + }, ], }) ) fns.push( loader({ oneOf: [ - markRemovable({ + { // A global Sass import always has side effects. Webpack will tree // shake the Sass without this option if the issuer claims to have // no side-effects. @@ -337,12 +300,8 @@ export const css = curry(async function css( sideEffects: true, test: regexSassGlobal, issuer: { and: [ctx.customAppFile] }, - use: getGlobalCssLoader( - ctx, - lazyPostCSSInitalizer, - sassPreprocessors - ), - }), + use: getGlobalCssLoader(ctx, postCssPlugins, sassPreprocessors), + }, ], }) ) @@ -354,7 +313,7 @@ export const css = curry(async function css( fns.push( loader({ oneOf: [ - markRemovable({ + { test: [regexCssGlobal, regexSassGlobal], issuer: { and: [/node_modules/] }, use: { @@ -363,7 +322,7 @@ export const css = curry(async function css( reason: getGlobalModuleImportError(), }, }, - }), + }, ], }) ) @@ -373,7 +332,7 @@ export const css = curry(async function css( fns.push( loader({ oneOf: [ - markRemovable({ + { test: [regexCssGlobal, regexSassGlobal], use: { loader: 'error-loader', @@ -381,7 +340,7 @@ export const css = curry(async function css( reason: getGlobalImportError(), }, }, - }), + }, ], }) ) @@ -392,7 +351,7 @@ export const css = curry(async function css( fns.push( loader({ oneOf: [ - markRemovable({ + { // This should only be applied to CSS files issuer: regexLikeCss, // Exclude extensions that webpack handles by default @@ -405,7 +364,7 @@ export const css = curry(async function css( // `asset/resource` always emits a URL reference, where `asset` // might inline the asset as a data URI type: 'asset/resource', - }), + }, ], }) ) 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 8d55c0cca5bd9f..e57b84af6a3861 100644 --- a/packages/next/build/webpack/config/blocks/css/loaders/global.ts +++ b/packages/next/build/webpack/config/blocks/css/loaders/global.ts @@ -1,11 +1,13 @@ +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, - postcss: any, + postCssPlugins: AcceptedPlugin[], preProcessors: readonly webpack.RuleSetUseItem[] = [] ): webpack.RuleSetUseItem[] { const loaders: webpack.RuleSetUseItem[] = [] @@ -25,7 +27,6 @@ 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, @@ -40,7 +41,7 @@ export function getGlobalCssLoader( loaders.push({ loader: require.resolve('../../../../loaders/postcss-loader/src'), options: { - postcss, + postcss: postcss(postCssPlugins), }, }) 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 94ebceb727f3c8..f7ed65c8a4f513 100644 --- a/packages/next/build/webpack/config/blocks/css/loaders/modules.ts +++ b/packages/next/build/webpack/config/blocks/css/loaders/modules.ts @@ -1,12 +1,14 @@ +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, - postcss: any, + postCssPlugins: AcceptedPlugin[], preProcessors: readonly webpack.RuleSetUseItem[] = [] ): webpack.RuleSetUseItem[] { const loaders: webpack.RuleSetUseItem[] = [] @@ -26,7 +28,6 @@ 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, @@ -56,7 +57,7 @@ export function getCssModuleLoader( loaders.push({ loader: require.resolve('../../../../loaders/postcss-loader/src'), options: { - postcss, + postcss: postcss(postCssPlugins), }, }) diff --git a/packages/next/build/webpack/config/blocks/css/overrideCssConfiguration.ts b/packages/next/build/webpack/config/blocks/css/overrideCssConfiguration.ts new file mode 100644 index 00000000000000..7cd34d1f021128 --- /dev/null +++ b/packages/next/build/webpack/config/blocks/css/overrideCssConfiguration.ts @@ -0,0 +1,42 @@ +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 1cecc6bed2f49b..f554e1137bc4cf 100644 --- a/packages/next/build/webpack/config/blocks/css/plugins.ts +++ b/packages/next/build/webpack/config/blocks/css/plugins.ts @@ -88,46 +88,40 @@ async function loadPlugin( } function getDefaultPlugins( - supportedBrowsers: string[] | undefined, - disablePostcssPresetEnv: boolean -): any[] { + supportedBrowsers: string[] | undefined +): CssPluginCollection { return [ require.resolve('next/dist/compiled/postcss-flexbugs-fixes'), - 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) + [ + 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, + }, + }, + ], + ] } export async function getPostCssPlugins( dir: string, supportedBrowsers: string[] | undefined, - disablePostcssPresetEnv: boolean = false + defaults: boolean = false ): Promise { - let config = await findConfig<{ plugins: CssPluginCollection }>( - dir, - 'postcss' - ) + let config = defaults + ? null + : await findConfig<{ plugins: CssPluginCollection }>(dir, 'postcss') if (config == null) { - config = { - plugins: getDefaultPlugins(supportedBrowsers, disablePostcssPresetEnv), - } + config = { plugins: getDefaultPlugins(supportedBrowsers) } } 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 eae004f556ea7a..32ceb4c5facf5a 100644 --- a/packages/next/build/webpack/loaders/css-loader/src/index.js +++ b/packages/next/build/webpack/loaders/css-loader/src/index.js @@ -2,135 +2,28 @@ 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 { icssParser, importParser, urlParser } from './plugins' +import { + normalizeOptions, + shouldUseModulesPlugins, + shouldUseImportPlugin, + shouldUseURLPlugin, + shouldUseIcssPlugin, + getPreRequester, + getExportCode, + getFilter, + getImportCode, + getModuleCode, + getModulesPlugins, + normalizeSourceMap, + sort, +} from './utils' 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() @@ -149,25 +42,6 @@ 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 d3e1198e5fcf02..462de89eeaa560 100644 --- a/packages/next/build/webpack/loaders/css-loader/src/utils.js +++ b/packages/next/build/webpack/loaders/css-loader/src/utils.js @@ -81,6 +81,130 @@ 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 @@ -508,6 +632,7 @@ function isDataUrl(url) { export { isDataUrl, + normalizeOptions, shouldUseModulesPlugins, shouldUseImportPlugin, shouldUseURLPlugin, @@ -515,6 +640,7 @@ 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 2e9dc8dc99062f..f43533fcdb2922 100644 --- a/packages/next/build/webpack/loaders/postcss-loader/src/index.js +++ b/packages/next/build/webpack/loaders/postcss-loader/src/index.js @@ -56,16 +56,13 @@ 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(() => - postcssWithPlugins.process(root || content, processOptions) + options.postcss.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 d7270c1612a872..1f17a95efba082 100644 --- a/packages/next/server/config-shared.ts +++ b/packages/next/server/config-shared.ts @@ -125,7 +125,6 @@ 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 6d90eee87b7883..b99eabfcf5e496 100644 --- a/test/integration/css-customization/test/index.test.js +++ b/test/integration/css-customization/test/index.test.js @@ -240,7 +240,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 failed because of webpack errors/) + expect(stderr).toMatch(/Build error occurred/) }) }) @@ -260,7 +260,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 failed because of webpack errors/) + expect(stderr).toMatch(/Build error occurred/) }) }) @@ -277,7 +277,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 failed because of webpack errors/) + expect(stderr).toMatch(/Build error occurred/) }) }) @@ -292,7 +292,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 failed because of webpack errors/) + expect(stderr).toMatch(/Build error occurred/) }) }) @@ -309,7 +309,7 @@ describe('Bad CSS Customization Array (5)', () => { expect(stderr).toMatch( /Your custom PostCSS configuration must export a `plugins` key./ ) - expect(stderr).toMatch(/Build failed because of webpack errors/) + expect(stderr).toMatch(/Build error occurred/) }) }) @@ -326,7 +326,7 @@ describe('Bad CSS Customization Array (6)', () => { expect(stderr).toMatch( /Your custom PostCSS configuration must export a `plugins` key./ ) - expect(stderr).toMatch(/Build failed because of webpack errors/) + expect(stderr).toMatch(/Build error occurred/) }) }) @@ -343,7 +343,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 failed because of webpack errors/) + expect(stderr).toMatch(/Build error occurred/) }) }) @@ -360,7 +360,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 failed because of webpack errors/) + expect(stderr).toMatch(/Build error occurred/) }) }) @@ -377,6 +377,6 @@ describe('Bad CSS Customization Function', () => { expect(stderr).toMatch( /Your custom PostCSS configuration may not export a function/ ) - expect(stderr).toMatch(/Build failed because of webpack errors/) + expect(stderr).toMatch(/Build error occurred/) }) })