nuxt
nuxt copied to clipboard
feat(postcss-loader): support passing in a function for postcss definition
Issue
Postcssconfig can either be an object (already supported) or a function which gets passed in the loadercontext. But nuxt does not support passing in a function currently.
Why
Passing in a function allows more complex uses cases, e.g. by applying different postcss steps for different ressources. (see also https://github.com/webpack-contrib/postcss-loader#function)
Solution
This approach adds a new "postcssConfig" option to the "postcss" nuxt config. Either this is the regular postcssConfig, or it is a function. see https://webpack.js.org/loaders/postcss-loader/#postcssoptions (only works with postcss@8, because postcss-loader >= 4.0 is required, and postcss7 nuxt setup conflicts with this version of postcss-loader)
e.g. nuxt.config.js.
module.exports = {
build: {
postcss: {
postcssOptions: loaderContext => {
// e.g. do something else with ".sss" files
if (/\.sss$/.test(loaderContext.resourcePath)) {
return {
parser: 'sugarss',
plugins: [['postcss-short', { prefix: 'x' }], 'postcss-preset-env']
};
}
return {
plugins: [['postcss-short', { prefix: 'x' }], 'postcss-preset-env']
};
}
}
}
};
this closes #7015
Types of changes
- [x] New feature (a non-breaking change which adds functionality)
Description
If postcss config is a function, we execute the custom function, but we also apply the default config of nuxt. Therefore we can assure that the config has a minimum default.
Checklist:
- [x] My change requires a change to the documentation. The postcss option can also have a function.
- [ ] I have updated the documentation accordingly. (PR: #)
- [ ] I have added tests to cover my changes (if not applicable, please state why) nope, as this is a advanced use case, I'm not quite sure where to add a appropiat test or if there is even a test really needed?
- [x] All new and existing tests are passing.
@simllll Since linked issue is related to postcss < 8 (current) shall we support same feature in postcss.js
util?
hi @clarkdo, thanks for your review. Actually your comment was pretty much the same as my first implementation, but as @pi0 stated correctly, this will loose some magic nuxt can do for us. E.g. execute, preset,.. because "postcss" is defined with a function, and you cannot define additional properties to it.
Therefore I was thinking how we could make this "better". By adding a new config option, which is used as postcssOptions if defined. (either a functino or an object), but everything stays the same when this option is not defined.
export default {
build: {
postcss: {
... all nuxt options like before,
postcssOptions: {} <-- optional a postcssOptions, which is then passed to postcss-loader
}
}
}
the nice thing on this is, that it's also easy possible to describe what are nuxt special options, and what are postcss "native" options, and they also can not conflict.
Sorry, I did't follow all of your discussions carefully, I'm just thinking build.postcs
and build.postcss.postcssOptions
are having same functionalities and conflicts like:
export default {
build: {
postcss: {
plugins: {
'postcss-short': { prefix: 'x' }
},
postcssOptions: {
plugins: [
['postcss-short': { prefix: 'x' }]
]
}
}
}
And it will be much harder to deal with things like order and options of plugins:
export default {
build: {
postcss: {
preset: {
stage: 2
},
postcssOptions: {
plugins: [
['postcss-preset-env': { stage: 1 }]
]
}
}
}
And also postcss-loader
and postcss
are all only suporting either funciton or object of postcssOptions
, I think funciton postcssOptions
is for advanced usage which user will set up everything inside the function, it may be better to align to their official solution.
cc @pi0
As far as I understand, there are two concercn about using the "postcss" parameter as a function.
First, we are actually talking aobut the postcss-loader here, which has an object as input, see:
(https://www.npmjs.com/package/postcss-loader)
one of the options is postcssOptions.
so putting a function here directly, would break two things: 1.) you cannot pass anything to the loader anymore 2.) custom options for nuxt can not be handled anymore.
therefore I would still suggest adding an additional "options" property, and would make them actually the same like postcss-loader has it already.
I see both points :)
- To ensure extendibility with nuxt/loader-specific options, we need a namespace like
postcss
- For DX and not breaking current config, we should support
options.build.postcss.plugins
andoptions.build.postcssOptions().plugins
We can always return a function to pass to loader for postcssOptions
:
- When called, if user provided postcssOptions is function, call it with context we have
- Merge new
postcssOptions
with top level options and applying defaults/normalization
Config types would be like this:
// type for build.postcss
interface NuxtPostcssOptions extends PostCSSOptions {
execute: Boolean
sourceMap: Boolean
postcssOptions: PostCSSOptions | ((ctx: any) => PostCSSOptions)
}
Just to clarify, are we gonna support ?
export default {
build: {
postcss: {
// puglins and preset here can be from user or our default config
plugins: {
'postcss-import': {},
'postcss-url': {},
cssnano: true
},
preset: {
stage: 2,
...
},
postcssOptions: {
plugins: [
['postcss-import': { prefix: 'x' }],
['postcss-short': { prefix: 'x' }],
['postcss-url': {}],
['postcss-preset-env': { ... }]
]
}
}
}
}
What the finial config will be like in this case ?
therefore I would still suggest adding an additional "options" property, and would make them actually the same like postcss-loader has it already.
I agree with the additional "options" property, what I concern is we should remove postcss.plugins
and postcss.preset
for avoiding too much confusion and conflicts like above code.
I agree with @clarkdo , to make things future proof I would suggest deprecating the old "root" options for plugins
at least. Right now I've implemented followign logic:
- everything works like before
- except if you set "postcssOptions", it is used instead of the "root" for the "postcssOption" that is passed to the loader.
see here https://github.com/nuxt/nuxt.js/pull/8899/files#diff-9613feda5d5173514c3656904bb88e5a8545c01dcacdc2e6c74cf476435a60e3R175 for the function method and here https://github.com/nuxt/nuxt.js/pull/8899/files#diff-9613feda5d5173514c3656904bb88e5a8545c01dcacdc2e6c74cf476435a60e3R185 for the object variant
Following up on @clarkdo's example, this means:
export default {
build: {
postcss: {
// puglins and preset here can be from user or our default config
plugins: { // <-- this is NOT used in this case
'postcss-import': {},
'postcss-url': {},
cssnano: true
},
preset: {
stage: 2,
...
},
postcssOptions: {
plugins: [ // <-- ONLY this one is used, but regardless if function or object, defaults are applied
['postcss-import': { prefix: 'x' }],
['postcss-short': { prefix: 'x' }],
['postcss-url': {}],
['postcss-preset-env': { ... }]
]
}
}
}
}
As this still blocks us from upgrading to postcss8, is there anything to help to get this thing going? :)
any news on this?
@pi0 hs created a module for postcss 8 https://github.com/nuxt/postcss8 , what do you think moving the logic to the module as a new feature?
@clarkdo I was just looking into the postcss8 module, but it only adapts some configs, it hasn't included the webpack (webpack/src/utils/postcss-v8.js) configuration, therefore adding it to the module is not possible in my opinion, it needs to be part of the webpack postcss-v8.js implementation.
Codecov Report
Merging #8899 (61753fd) into dev (88ea02c) will decrease coverage by
0.12%
. The diff coverage is0.00%
.
@@ Coverage Diff @@
## dev #8899 +/- ##
==========================================
- Coverage 65.10% 64.97% -0.13%
==========================================
Files 94 94
Lines 4098 4106 +8
Branches 1121 1124 +3
==========================================
Hits 2668 2668
- Misses 1152 1157 +5
- Partials 278 281 +3
Flag | Coverage Δ | |
---|---|---|
unittests | 64.97% <0.00%> (-0.13%) |
:arrow_down: |
Flags with carried forward coverage won't be shown. Click here to find out more.
Impacted Files | Coverage Δ | |
---|---|---|
packages/webpack/src/utils/postcss-v8.js | 1.03% <0.00%> (-0.10%) |
:arrow_down: |
Continue to review full report at Codecov.
Legend - Click here to learn more
Δ = absolute <relative> (impact)
,ø = not affected
,? = missing data
Powered by Codecov. Last update 88ea02c...61753fd. Read the comment docs.
Any chance to get this into nuxt2 or/and nuxt 3? :) I'm eager to find out due to the reason that the approach we are using right now (external postcss file) produces a warning that this will not be possible in nuxt 3...
I was just looking into the postcss8 module, but it only adapts some configs, it hasn't included the webpack (webpack/src/utils/postcss-v8.js) configuration, therefore adding it to the module is not possible in my opinion, it needs to be part of the webpack postcss-v8.js implementation.
We can change webpack config in module and it's acutally doing by some modules, I think we can leverage build.exntend in nuxt.config to call the customized function you defined for postcss and change the postcss-loader options.
i love this
Hi, What's the status of this PR? It's really desired especially after support of external postcss config file is dropped on Nuxt@3
@simllll Would you like to update this PR now that we've updated to PostCSS 8 natively in 2.16? 🙏
@simllll, @danielroe, can we do anything to make this PR land? This would unblock our migration to Nuxt 2.16 (and to Nuxt 3 in the future) by fixing the issue I described in #19482
@obulat I suspect @simllll would not mind if you would like to open a new PR incorporating the work here and resolving merge conflicts. I would of course merge it crediting you both.
Yes, absolute fine to me, no worries :-) i would do it myself, unfortunately couldn't find time yet and the issue itself is not relevant anymore to us... ;-)
implemented in https://github.com/nuxt/nuxt/pull/19495