postcss-nesting plugin versus preset-env nesting for lean builds with CSS Nesting spec compliance
0 reputation · 07 Oct 2023, 08:19 UTC
0 reputation · 07 Oct 2023, 08:19 UTC
PostCSS core does not transform nesting. Nesting is provided by postcss-nesting or by the nesting feature inside postcss-preset-env, and the two approaches differ in pipeline weight and spec handling.
The goal is a deterministic nesting transform that follows the CSS Nesting Module without adding unnecessary feature transforms to the build. The constraint is build overhead and configuration stability: a dedicated plugin offers fine-grained options such as noIsPseudoSelector, while preset-env bundles nesting with other future CSS features and is stage-gated.
An unresolved decision is how starter kits and teams should choose between a minimal dedicated plugin and a single preset pipeline, and how to avoid inconsistent defaults when both mechanisms are present.
Which approach produces identical flat CSS output for the same nested source under current spec rules? Does preset-env nesting with an explicit stage pin provide the same :is() pseudo-class handling as postcss-nesting with its options? How should a config prevent duplicate nesting transformations when preset-env and postcss-nesting are both available in the dependency graph?
31775 reputation · 07 Oct 2023, 10:11 UTC
Both postcss‑nesting and the nesting feature of postcss‑preset‑env implement the CSS Nesting Module. When the same source is fed through a single implementation, the flattened CSS is identical, provided that no other preset features alter selector handling. The difference lies in the surrounding feature set and in the configuration knobs that control :is() wrappers.
The CSS Nesting Module requires that every nested selector be wrapped in :is(). postcss‑nesting follows this rule by default. It exposes a noIsPseudoSelector option whose default is false; setting it to true removes the :is() wrapper. postcss‑preset‑env applies the same logic when the nesting feature is enabled (which is the default when the preset stage is 2 or higher). Therefore, with noIsPseudoSelector: false and a preset stage of 2, both plugins generate the same :is() wrappers.
In postcss‑preset‑env the nesting module is part of stage 2. If the preset is configured with stage: 1 or stage: 0, the nesting transform is omitted entirely, which would cause silent differences when switching between the two approaches. Pinning the preset to stage 2 (or higher) guarantees that the nesting transform is applied.
PostCSS runs plugins in the order they appear in the plugins array. If both postcss‑nesting and postcss‑preset‑env (with nesting enabled) are present, the nesting transform will be applied twice, producing duplicate rules or overriding earlier output. The safest strategy is to use only one implementation:
postcss‑preset‑env and disable its nesting feature with features: { nesting: false } if you prefer the dedicated plugin.
postcss‑nesting entirely and rely on postcss‑preset‑env with the default nesting enabled.
If you must include both for other reasons, be sure to place postcss‑nesting after postcss‑preset‑env and remember that it will still re‑apply the nesting logic, so the output will differ from a single‑plugin build.
/* postcss-nesting only */
module.exports = {
plugins: [require('postcss-nesting')]
};
/* postcss-preset-env with nesting enabled (stage 2) */
module.exports = {
plugins: [
require('postcss-preset-env')({
stage: 2,
features: { nesting: true }
})
]
};
/* postcss-preset-env with nesting disabled, using postcss-nesting */
module.exports = {
plugins: [
require('postcss-preset-env')({
stage: 2,
features: { nesting: false }
}),
require('postcss-nesting')
]
};
npm install postcss-nesting postcss-preset-env --save-dev
input.css:
.a {
color: red;
.b {
color: blue;
}
}
npx postcss input.css -o out-nesting.css
npx postcss input.css -o out-preset.css --config preset-config.js
# Use a diff tool or a simple string comparison to confirm identical rule sets
.b rules to detect duplication.
Do you need additional future CSS features (e.g., container queries, custom media) that are bundled with postcss‑preset‑env? If so, a single preset configuration may be preferable. If the goal is a minimal dependency footprint, the dedicated postcss‑nesting plugin is the leaner choice.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.