Skip to content

Commit

Permalink
feat(css): add strictPostcssConfiguration flag (#20914)
Browse files Browse the repository at this point in the history
This pull request adds `future.strictPostcssConfiguration`, allowing users to opt-into the more strict PostCSS configuration loading.

This stricter PostCSS configuration loading ensures that CSS can be cached across builds.
  • Loading branch information
Timer committed Jan 11, 2021
1 parent 16ff439 commit d0e2854
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 5 deletions.
3 changes: 2 additions & 1 deletion packages/next/build/webpack-config.ts
Expand Up @@ -1208,6 +1208,7 @@ export default async function getBaseWebpackConfig(
assetPrefix: config.assetPrefix || '',
sassOptions: config.sassOptions,
productionBrowserSourceMaps: config.productionBrowserSourceMaps,
future: config.future,
})

let originalDevtool = webpackConfig.devtool
Expand Down Expand Up @@ -1330,7 +1331,7 @@ export default async function getBaseWebpackConfig(
(e) => (e as any).__next_css_remove !== true
)
}
} else {
} else if (!config.future.strictPostcssConfiguration) {
await __overrideCssConfiguration(dir, !dev, webpackConfig)
}

Expand Down
5 changes: 1 addition & 4 deletions packages/next/build/webpack/config/blocks/css/index.ts
Expand Up @@ -78,10 +78,7 @@ export const css = curry(async function css(
const postCssPlugins = await getPostCssPlugins(
ctx.rootDirectory,
ctx.isProduction,
// TODO: In the future, we should stop supporting old CSS setups and
// unconditionally inject ours. When that happens, we should remove this
// function argument.
true
!ctx.future.strictPostcssConfiguration
)

// CSS cannot be imported in _document. This comes before everything because
Expand Down
4 changes: 4 additions & 0 deletions packages/next/build/webpack/config/index.ts
@@ -1,4 +1,5 @@
import webpack from 'webpack'
import { NextConfig } from '../../../next-server/server/config'
import { base } from './blocks/base'
import { css } from './blocks/css'
import { ConfigurationContext, pipe } from './utils'
Expand All @@ -13,6 +14,7 @@ export async function build(
assetPrefix,
sassOptions,
productionBrowserSourceMaps,
future,
}: {
rootDirectory: string
customAppFile: string | null
Expand All @@ -21,6 +23,7 @@ export async function build(
assetPrefix: string
sassOptions: any
productionBrowserSourceMaps: boolean
future: NextConfig['future']
}
): Promise<webpack.Configuration> {
const ctx: ConfigurationContext = {
Expand All @@ -37,6 +40,7 @@ export async function build(
: '',
sassOptions,
productionBrowserSourceMaps,
future,
}

const fn = pipe(base(ctx), css(ctx))
Expand Down
3 changes: 3 additions & 0 deletions packages/next/build/webpack/config/utils.ts
@@ -1,4 +1,5 @@
import webpack from 'webpack'
import { NextConfig } from '../../../next-server/server/config'

export type ConfigurationContext = {
rootDirectory: string
Expand All @@ -14,6 +15,8 @@ export type ConfigurationContext = {

sassOptions: any
productionBrowserSourceMaps: boolean

future: NextConfig['future']
}

export type ConfigurationFn = (
Expand Down
6 changes: 6 additions & 0 deletions packages/next/next-server/server/config.ts
Expand Up @@ -31,6 +31,11 @@ export type NextConfig = { [key: string]: any } & {
redirects?: () => Promise<Redirect[]>

trailingSlash?: boolean

future: {
strictPostcssConfiguration: boolean
excludeDefaultMomentLocales: boolean
}
}

const defaultConfig: NextConfig = {
Expand Down Expand Up @@ -83,6 +88,7 @@ const defaultConfig: NextConfig = {
scriptLoader: false,
},
future: {
strictPostcssConfiguration: false,
excludeDefaultMomentLocales: false,
},
serverRuntimeConfig: {},
Expand Down
33 changes: 33 additions & 0 deletions test/integration/css-customization/test/index.test.js
Expand Up @@ -108,6 +108,39 @@ describe('Legacy Next-CSS Customization', () => {
})
})

describe('Custom CSS Customization via Webpack', () => {
const appDir = join(fixturesDir, 'custom-configuration-webpack')

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(stdout).toMatch(/Compiled successfully/)
expect(stderr).not.toMatch(
/Built-in CSS support is being disabled due to custom CSS configuration being detected/
)
})

it(`should've compiled and prefixed`, async () => {
const cssFolder = join(appDir, '.next/static/css')

const files = await readdir(cssFolder)
const cssFiles = files.filter((f) => /\.css$/.test(f))

expect(cssFiles.length).toBe(1)
const cssContent = await readFile(join(cssFolder, cssFiles[0]), 'utf8')
expect(cssContent.replace(/\/\*.*?\*\//g, '').trim()).toMatchInlineSnapshot(
`"@media (480px <= width < 768px){::placeholder{color:green}}.video{max-width:400px;max-height:300px}"`
)
})
})

describe('CSS Customization Array', () => {
const appDir = join(fixturesDir, 'custom-configuration-arr')

Expand Down
@@ -0,0 +1,36 @@
module.exports = {
onDemandEntries: {
maxInactiveAge: 1000 * 60 * 60,
},
webpack(config) {
modifyLoaderConfig(
config.module.rules,
[/(?<!\.module)\.css$/, /\.module\.css$/],
(rule) => {
if (!Array.isArray(rule.use)) return
rule.use.forEach((u) => {
if (u.options.postcssOptions) {
u.options.postcssOptions.plugins = [
require('postcss-short-size')({
// Add a prefix to test that configuration is passed
prefix: 'xyz',
}),
]
}
})
}
)

return config
},
future: { strictPostcssConfiguration: true },
}

function modifyLoaderConfig(rules, regexes, cb) {
rules.forEach((rule) => {
if (rule.oneOf) return modifyLoaderConfig(rule.oneOf, regexes, cb)
regexes.forEach((regex) => {
if (rule.test && rule.test.toString() === regex.toString()) cb(rule)
})
})
}
@@ -0,0 +1,12 @@
import React from 'react'
import App from 'next/app'
import '../styles/global.css'

class MyApp extends App {
render() {
const { Component, pageProps } = this.props
return <Component {...pageProps} />
}
}

export default MyApp
@@ -0,0 +1,3 @@
export default function Home() {
return <div />
}
@@ -0,0 +1,11 @@
/* this should pass through untransformed */
@media (480px <= width < 768px) {
::placeholder {
color: green;
}
}

/* this should be transformed to width/height */
.video {
-xyz-max-size: 400px 300px;
}

0 comments on commit d0e2854

Please sign in to comment.