import curry from 'next/dist/compiled/lodash.curry' import { webpack } from 'next/dist/compiled/webpack/webpack' import MiniCssExtractPlugin from '../../../plugins/mini-css-extract-plugin' import { loader, plugin } from '../../helpers' import { ConfigurationContext, ConfigurationFn, pipe } from '../../utils' import { getCssModuleLoader, getGlobalCssLoader } from './loaders' import { getCustomDocumentError, getGlobalImportError, getGlobalModuleImportError, 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)$/ // RegExps for Style Sheets const regexCssGlobal = /(? file fns.push( loader({ oneOf: [ { test: [regexCssGlobal, regexSassGlobal], use: { loader: 'error-loader', options: { reason: getGlobalImportError(), }, }, }, ], }) ) if (ctx.isClient) { // Automatically transform references to files (i.e. url()) into URLs // e.g. url(./logo.svg) fns.push( loader({ oneOf: [ { // This should only be applied to CSS files issuer: regexLikeCss, // Exclude extensions that webpack handles by default exclude: [ /\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/, /\.webpack\[[^\]]+\]$/, ], use: { // `file-loader` always emits a URL reference, where `url-loader` // might inline the asset as a data URI loader: require.resolve('next/dist/compiled/file-loader'), options: { // Hash the file for immutable cacheability name: 'static/media/[name].[hash].[ext]', }, }, }, ], }) ) } if (ctx.isClient && ctx.isProduction) { // Extract CSS as CSS file(s) in the client-side production bundle. fns.push( plugin( // @ts-ignore webpack 5 compat new MiniCssExtractPlugin({ experimentalUseImportModule: true, filename: 'static/css/[contenthash].css', chunkFilename: 'static/css/[contenthash].css', // Next.js guarantees that CSS order "doesn't matter", due to imposed // restrictions: // 1. Global CSS can only be defined in a single entrypoint (_app) // 2. CSS Modules generate scoped class names by default and cannot // include Global CSS (:global() selector). // // While not a perfect guarantee (e.g. liberal use of `:global()` // selector), this assumption is required to code-split CSS. // // If this warning were to trigger, it'd be unactionable by the user, // but likely not valid -- so we disable it. ignoreOrder: true, }) ) ) } const fn = pipe(...fns) return fn(config) })