feat(webpack): support passing function as postcssOptions (#19495)

This commit is contained in:
Olga Bulat 2023-06-09 16:47:03 +03:00 committed by GitHub
parent f842c75ff2
commit 3e4284e8f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 150 additions and 7 deletions

View File

@ -154,7 +154,7 @@ export default class PostcssConfig {
* @param postcssOptions
* @returns {{ postcssOptions: { plugins?: unknown, order?: string, preset?: any} }}
*/
normalize (postcssOptions) {
normalize (postcssOptions, warnAboutTopLevelDeprecation = true) {
// TODO: Remove in Nuxt 3
if (Array.isArray(postcssOptions)) {
consola.warn('Using an Array as `build.postcss` will be deprecated in Nuxt 3. Please switch to the object' +
@ -168,12 +168,19 @@ export default class PostcssConfig {
return { postcssOptions: {} }
}
if (postcssOptions.postcssOptions && typeof postcssOptions.postcssOptions === 'function') {
consola.warn('Using a Function as `build.postcss.postcssOptions` is not yet supported in Nuxt 2.16.2')
return { postcssOptions: {} }
const postcssOptionsFn = postcssOptions.postcssOptions
return {
postcssOptions: (loaderContext) => {
const result = this.normalize(postcssOptionsFn(loaderContext), false)
if (result) {
return result.postcssOptions
}
}
}
}
if (!('postcssOptions' in postcssOptions)) {
if (Object.keys(postcssOptions).length > 0) {
consola.warn('Using the top-level properties in `build.postcss` will be deprecated in Nuxt 3. Please move' +
if (Object.keys(postcssOptions).length > 0 && warnAboutTopLevelDeprecation) {
consola.warn('Using the top-level properties in `build.postcss` will be deprecated in Nuxt 3. Please move ' +
'the settings to `postcss.postcssOptions`')
}
postcssOptions = { postcssOptions }
@ -211,7 +218,7 @@ export default class PostcssConfig {
/**
* Load plugins from postcssOptions
* @param {{ postcssOptions: {plugins?: unknown, order?: string | function}}} postcssOptions
* @param {{ postcssOptions: {plugins?: unknown, order?: string | function }}} postcssOptions
*/
loadPlugins (postcssOptions) {
const { plugins, order } = postcssOptions.postcssOptions
@ -252,7 +259,7 @@ export default class PostcssConfig {
if (Array.isArray(postcssOptions.postcssOptions.plugins)) {
defaults(postcssOptions.postcssOptions.plugins, this.defaultPostcssOptions.plugins)
} else {
} else if (typeof postcssOptions.postcssOptions !== 'function') {
// Merge all plugins and use preset for setting up postcss-preset-env
if (postcssOptions.postcssOptions.preset) {
if (!postcssOptions.postcssOptions.plugins) {

View File

@ -0,0 +1,55 @@
import { join } from 'node:path'
import PostcssConfig from '../src/utils/postcss'
describe('webpack: postcss', () => {
const getConfigWithPostcssConfig = config =>
new PostcssConfig({
options: {
dev: false,
srcDir: join(__dirname),
rootDir: join(__dirname),
modulesDir: []
},
nuxt: {
resolver: {
requireModule: plugin => opts => [plugin, opts]
}
},
buildOptions: {
postcss: config
}
})
test('should have the right default configuration', () => {
// Use the default postcss config: stage 2
// https://cssdb.org/#staging-process
const pluginConfig = Object.fromEntries(
getConfigWithPostcssConfig({ postcssOptions: {} }).config().postcssOptions.plugins
)
expect(pluginConfig).toMatchInlineSnapshot(`
{
"cssnano": {
"preset": [
"default",
{
"minifyFontValues": {
"removeQuotes": false,
},
},
],
},
"postcss-import": {
"resolve": [Function],
},
"postcss-preset-env": {},
"postcss-url": {},
}
`)
})
test('can pass a function through', () => {
// Use the default postcss config: stage 2
// https://cssdb.org/#staging-process
const options = getConfigWithPostcssConfig({ postcssOptions: () => ({ preset: { stage: 2 } }) }).config().postcssOptions
expect(typeof options).toBe('function')
})
})

View File

@ -0,0 +1,32 @@
import { getPort, loadFixture, Nuxt } from '../utils'
let port
const url = route => 'http://localhost:' + port + route
let nuxt = null
describe('postcss configuration as function', () => {
beforeAll(async () => {
const options = await loadFixture('postcss-function')
nuxt = new Nuxt(options)
await nuxt.ready()
port = await getPort()
await nuxt.server.listen(port, '0.0.0.0')
})
for (const path of ['/css', '/postcss']) {
test(path, async () => {
const window = await nuxt.server.renderAndGetWindow(url(path))
const headHtml = window.document.head.innerHTML
expect(headHtml.replace(/\s+/g, '').replace(/;}/g, '}')).toContain('div.red{background-color:blue}.red{color:red}')
const element = window.document.querySelector('.red')
expect(element).not.toBe(null)
expect(element.textContent).toContain('This is red')
expect(element.className).toBe('red')
// t.is(window.getComputedStyle(element).color, 'red')
})
}
})

View File

@ -0,0 +1,16 @@
const createData = async () => {
await new Promise(resolve => setTimeout(resolve, 500))
return {
build: {
postcss: {
postcssOptions: () => ({
plugins: [
['postcss-preset-env', { features: { 'custom-selectors': true } }]
]
})
}
}
}
}
export default createData

View File

@ -0,0 +1,15 @@
<template>
<div class="red">
This is red
</div>
</template>
<style>
@custom-selector :--red div.red;
:--red {
background-color: blue;
}
.red {
color: red;
}
</style>

View File

@ -0,0 +1,15 @@
<template>
<div class="red">
This is red
</div>
</template>
<style lang="postcss">
@custom-selector :--red div.red;
:--red {
background-color: blue;
}
.red {
color: red;
}
</style>

View File

@ -0,0 +1,3 @@
import { buildFixture } from '../../utils/build'
buildFixture('postcss-function')