Compare Versions - postcss
npm / postcss / Compare Versions
- Fixed
Processor#version.
- Improved source map annotation cleaning performance (by CodeAnt AI).
- Fixed
ContainerWithChildrentype discriminating (by @Goodwine).
- Fixed
package.json→exportscompatibility with some tools (by @JounQin).
- Fixed Parcel compatibility issue (by @git-sumitchaudhary).
- Added more details to
Unknown worderror (by @hiepxanh). - Fixed types (by @romainmenke).
- Fixed docs (by @catnipan).
- Fixed end position of rules with semicolon (by @romainmenke).
- Fixed backwards compatibility for complex cases (by @romainmenke).
PostCSS 8.5 brought API to work better with non-CSS sources like HTML, Vue.js/Svelte sources or CSS-in-JS.
@romainmenke during his work on Stylelint added Input#document in additional to Input#css.
root.source.input.document //=> "<p>Hello</p>
// <style>
// p {
// color: green;
// }
// </style>"
root.source.input.css //=> "p {
// color: green;
// }"
Thanks to Sponsors
This release was possible thanks to our community.
If your company wants to support the sustainability of front-end infrastructure or wants to give some love to PostCSS, you can join our supporters by:
- Tidelift with a Spotify-like subscription model supporting all projects from your lock file.
- Direct donations at GitHub Sponsors or Open Collective.
- Fixed custom syntax without
source.offset(by @romainmenke).
- Fixed position calculation in error/warnings methods (by @romainmenke).
- Removed debug code.
- Fixed
Cannot read properties of undefined (reading 'before').
- Removed unnecessary fix which could lead to infinite loop.
- Another way to fix
markClean is not a functionerror.
- Fixed
markClean is not a functionerror.
- Fixed CSS syntax error on long minified files (by @varpstar).
- Fixed types (by @nex3 and @querkmachine).
- Cleaned up RegExps (by @bluwy).
- Moved to getter/setter in nodes types to help Sass team (by @nex3).
- Fixed
CssSyntaxErrortypes (by @romainmenke).
- Fixed
endIndex: 0in errors and warnings (by @romainmenke).
- Fixed
original.column are not numberserror in another case.
- Fixed
original.column are not numberserror on broken previous source map.
- Avoid
!innode.parent.nodestype. - Allow to pass
undefinedto node adding method to simplify types.
- Fixed
AtRule#nodestype (by @tim-we). - Cleaned up code (by @DrKiraDmitry).
- Fixed
NoWorkResultbehavior difference with normal mode (by @romainmenke). - Fixed
NoWorkResultusage conditions (by @ahmdammarr).
- Fixed
postcss().process()types (by @ferreira-tb).
- Fixed
\rparsing to fix CVE-2023-44270.
- Improved source map performance (by @romainmenke).
- Fixed
Node#source.offset(by @idoros). - Fixed docs (by @coliff).
- Fixed
Root.source.endfor better source map (by @romainmenke). - Fixed
Result.roottypes whenprocess()has no parser.
- Fixed
Containerclone methods types.
- Fixed clone methods types.
- Improve stringify performance (by @romainmenke).
- Fixed docs (by @vikaskaliramna07).
- Fixed
Plugintypes.
- Fixed warnings in TypeDoc.
- Fixed TypeScript support with
node16(by @remcohaszing).
- Fixed
Input#errortypes (by @hudochenkov).
- Fixed source map generation for childless at-rules like
@layer.
- Fixed whitespace preserving after AST transformations (by @romainmenke).
- Fixed an error on
absolute: truewith emptysourceContent(by @KingSora).
- Fixed
Node.before()unexpected behavior (by @romainmenke). - Added TOC to docs (by @muddv).
- Fixed
RootAST migration.
- Fixed AST normalization after using custom parser with old PostCSS AST.
- Print “old plugin API” warning only if plugin was used (by @zardoy).
- Fixed
append()error after using.parent(by @thecrypticace).
- Fixed
package.fundingto have same value between all PostCSS packages.
- Fixed
Declaration#raws.valuetype.
- Fixed
package.fundingURL format.
- Fixed
package.funding(by @mondeja).
- Fixed end position in empty Custom Properties.
- Fixed
Node#warn()type (by @ybiquitous). - Fixed comment removal in values after
,.
- Prevented comment removing when it change meaning of CSS.
- Fixed parsing space in last semicolon-less CSS Custom Properties.
- Fixed comment cleaning in CSS Custom Properties with space.
- Fixed throwing an error on
.rootaccess for plugin-less case.
- Fixed
rawstypes to make object extendable (by @43081j). - Moved from Yarn 1 to pnpm.
- Fixed absolute path in source map on zero plugins mode.
- Fixed
this.css.replace is not a functionerror.
- Fixed previous source map support in zero plugins mode.
- Fixed
Stringifiertypes (by @43081j).
PostCSS 8.4 brought ranges for warnings and errors, smaller node_modules size, lazy parsing to avoid PostCSS does nothing warning, and TypeScript fixes.
Thanks to Sponsors
This release was possible thanks to our community.
If your company wants to support the sustainability of front-end infrastructure or wants to give some love to PostCSS, you can join our supporters by:
- Tidelift with a Spotify-like subscription model supporting all projects from your lock file.
- Direct donations in PostCSS & Autoprefixer Open Collective.
Rages for Errors and Warnings
@adalinesimonian, the author of amazing Stylelint extension for VS Code, added ranges to errors and warnings.
result.warn(msg, { index }) // One character warning at index
result.warn(msg, { endIndex }) // Starts at node start, ends at endIndex
result.warn(msg, { index, endIndex }) // Starts at index, ends at endIndex
result.warn(msg, { start }) // Starts at start, ends at node end
result.warn(msg, { end }) // Starts at node start, ends at end
result.warn(msg, { start, end }) // Starts at start, ends at end
result.warn(msg, { word }) // Starts at word location, ends at word index + length
It will improve DX in the IDE extension.
Lazy Parsing
Previously, we found that many tools run PostCSS even if the developer didn’t pass any PostCSS plugins. Parsing is the most expensive step in CSS processing. It led to a waste of resources without any reason.
We tried to resolve the problem by adding a PostCSS does nothing warning. But it didn’t force tool authors to be more careful with user’s resources.
If PostCSS sees that tool call it without passing plugins (or changing parser/stringifier), PostCSS will not parse CSS (until toll will call Result#root). In 8.4, @bogdan0083 (with the help of @WilhelmYakunin) tries to solve the problem in another way. It allows us to save resources and remove the PostCSS does nothing warning.
// No plugins, we do not parse CSS
let result = await postcss().process(css, { from })
result.css // Is the same string passed to process()
result.map // Special 1-to-1 source map
result.root // CSS will parsed only here
Install Size Reduction
With ≈60M weekly downloads, PostCSS has responsibility for the world’s resource spending.
Together with @7rulnik we reduced source-map-js size. It is transitive dependency of PostCSS.
In 8.4, we moved to a fixed version of source-map-js, which reduced the postcss size in your node_modules from ≈1 MB to 0.3 MB. With the huge popularity of PostCSS, it will free a lot of resources on our CIs.
Migration from Jest to uvu
@kimoofey refactored all tests from the popular Jest framework to small and fast uvu.
It will not affect end-users. However, it reduced our node_modules size by 33 MB and made tests twice faster (yarn install & yarn unit: 24 → 13 seconds).
TypeScript Fixes
- Added
Processortypes. - Added
Stringifiertypes (by @43081j). - Fixed types
RootandDocumentin result values (by @43081j). - Fixed
Node#walkRules()types (by @hudochenkov).
Other Changes
- Fixed docs (by @paulshryock).
- Fixed
Maximum call stackissue of some source maps (by @yetingli).
- Replaced
nanocolorstopicocolors. - Reduced package size.
- Update
nanocolors.
- Replaced
colorettetonanocolors. - Added bug field to package.json (by @coliff).
- Improved docs (by @camelpunch and @paulshryock).
- Fixed column in
missed semicolonerror (by @Gusted).
- Fixed broken AST detection.
- Fixed broken AST detection.
- Fixed broken AST on
postcssdependency duplication in custom parsers.
- Update changelog.
- Fixed false positives
PostCSS does nothingwarning onsyntaxoption.
PostCSS 8.3 improved source map parsing performance, added Node#assign() shortcut, and experimental Document node to AST.
Thanks to Sponsors
This release was possible thanks to our community.
If your company wants to support the sustainability of front-end infrastructure or wants to give some love to PostCSS, you can join our supporters by:
- Tidelift with a Spotify-like subscription model supporting all projects from your lock file.
- Direct donations in PostCSS & Autoprefixer Open Collective.
Source Map Performance
Because PostCSS needs synchronous API, we can’t move from the old `source-map 0.6 to 0.7 (many other open-source projects too).
@7rulnik forked source-map 0.6 to source-map-js and back-ported performance improvements from 0.7. In 8.3 we switched from source-map to this source-map-js fork.
You map see 4x performance improvements in parsing map from processing step before PostCSS (for instance, Sass).
Document Nodes
Thanks to @gucong3000, PostCSS already parse CSS from HTML and JS files (CSS-in-JS templates and objects).
But his plugin need big updates. @hudochenkov from stylelint team decided to create new parsers for styles inside CSS-in-JS, HTML, and Markdown.
He suggested adding new Document node type to PostCSS AST to keep multiple Root nodes inside and JS/HTML/Markdown code blocks between these style blocks.
const document = htmlParser(
'<html><style>a{color:black}</style><style>b{z-index:2}</style>'
)
document.type //=> 'document'
document.nodes.length //=> 2
document.nodes[0].type //=> 'root'
This is an experimental feature. Some aspects of this node could change within minor or patch version releases.
Node#assign() Shortcut
The creator of famous postcss-preset-env and many other PostCSS tools, @jonathantneal suggested a nice shortcut to change multiple properties in the node:
decl.assign({ prop: 'word-wrap', value: 'break-word' })
- Fixed
listtype definitions (by @n19htz).
- Removed
source-mapfrom client-side bundle (by @barak007).
- Fixed ReDoS vulnerabilities in source map parsing (by @yetingli).
- Fixed
package.jsonexports.
- Fixed
DEP0148warning in Node.js 16. - Fixed docs (by @semiromid).
- Fixed ReDoS vulnerabilities in source map parsing.
- Fixed webpack 5 support (by @barak007).
- Fixed docs (by @roelandmoors).
- Exported
NodeErrorOptionstype (by @realityking)
- Fixed browser builds in webpack 5 (by @mattcompiles).
- Fixed browser builds in webpack 5 (by @mattcompiles).
- Fixed
Maximum call stack size exceededinNode#toJSON. - Fixed docs (by @inokawa).
- Fixed escaped characters handling in
list.split(by @nex3).
- Added plugin name to
postcss.plugin()warning (by @Alphy11). - Fixed docs (by @billcolumbia).
- Fixed
JSON.stringify(Node[])support (by @mischnic).
- Fixed CSS-in-JS support (by @43081j).
- Fixed plugin types (by @ludofischer).
- Fixed
Result#warn()types.
- Fixed
Node#toJSON()andpostcss.fromJSON()(by @mischnic).
PostCSS 8.2 added a new API to serialize and deserialize CSS AST to JSON.
import { parse, fromJSON } from 'postcss'
let root = parse('a{}', { from: 'input.css' })
let json = root.toJSON()
// save to file, send by network, etc
let root2 = fromJSON(json)
Thanks to @mischnic for his work.
- Fixed parser performance regression.
- Fixed broken AST after moving nodes in visitor API.
- Fixed Autoprefixer regression.
- Added PostCSS update suggestion on unknown event in plugin.
- Fixed
LazyResulttype export (by @yyx990803). - Fixed
LazyResulttype compatibility withPromise(by @antonk52).
- Reduced dependencies number (by @TrySound).
- Fixed
LazyResulttype compatibility withPromise(by @ludofischer). - Fixed HTTPS links in documentation.
- Fix
importsupport in TypeScript (by @remcohaszing).
- Reverted
package.exportsNode.js 15 fix.
- Fixed Node.js 15 warning (by @ShenHongFei).
- Fixed TypeScript definition (by @Arthie).
- Added
package.types.
- Fix API docs (by @Arthie).
- Improve plugin guide (by @yunusga).
- Prepare code base for Deno support (by @oscarotero).
PostCSS 8.1 fixed the new visitor API from the 8.0 release.
We fixed Root and RootExit re-calling on children's changes. And now visitors will visit the parent again if nested children were changed.
We added Once and OnceExit events, which will not be called again on node changes. You can use them to lint files or collect statistics:
module.exports = {
postcssPlugin: 'postcss-linter',
OnceExit (root) {
lint(root)
}
}
module.exports.postcss = true
We updated Migration guide according to new changes.
- Replace prototype in PostCSS 7 nodes instead of recreating them.
- Added missed
Transformerto exported types (by @pmdartus).
- Fix
8.0.7regression on PostCSS 7 nodes converting (by @adamwathan)
- Fixed compatibility issue with mixin AST with PostCSS 7 and 8 nodes.
- Added migration guide translation to Chinese to the warning.
- Fixed child adding methods in
Container.
- Update changelog.
- Fixed
Cannot read property 'line' of nullerror. - Fixed source map support for declarations.
- Fixed client-side bundling support.
- Fix plugin packs support.
- Updated
Processor#version.
PostCSS 8.0 brings new plugin API, node_modules size reduction, better source map support, and CSS parser improvements.
Check out a day-by-day diary of PostCSS 8.0 development process.
See Migration Guides for end-users and for plugin developers.
Thanks to Sponsors
With more than 100 M downloads per month, it becomes hard to support PostCSS in free time. For instance, getting the 8.0 release ready took 4 months of work.
This release was possible thanks to out community. Tailwind CSS, De Voorhoede, InVision AG, Brainbow, and many individual contributions.
If your company wants to support the sustainability of front-end infrastructure or just wants to give some love to PostCSS, you can join our supporters by:
- Tidelift with a Spotify-like subscription model and supporting all projects from your lock file.
- Direct donations in PostCSS & Autoprefixer Open Collective.
Breaking Changes
We try to avoid any breaking changes for end-users:
- PostCSS 8 dropped Node.js 6.x, 8.x, 11.x, and 13.x versions support. All these versions have no security updates anymore.
- We now serve ES6+ sources in the npm package without Babel compilation. If you are creating tools like CodePen and put PostCSS into the client-side JS bundle, you may need to run Babel on
node_modules/postcssfor old browsers. - We removed rarely used
postcss.vendorAPI.
New Plugin API
The biggest change in PostCSS 8 is a new plugin API. Thanks to @BondarenkoAlex for big help in creating a new API.
module.exports = () => {
return {
postcssPlugin: 'postcss-will-change',
Declaration: {
'will-change': (decl, { Declaration }) => {
decl.cloneBefore(
new Declaration({ prop: 'backface-visibility', value: 'hidden' })
)
}
}
}
}
module.exports.postcss = true
We know that rewriting old plugins will take time, but the new API will improve the end-user’s experience and make life easier for plugin developers:
- With new API, all plugins can share a single scan of the CSS tree. It makes CSS processing up to 20% faster.
- Because npm often duplicates dependencies, you may have many
postcssduplicates in yournode_modules. New API fixes this problem. - Plugins will re-visit changed nodes to reduce compatibility issues between plugins. Now the order of plugins in your PostCSS config will be less important.
- New API is close to Babel’s visitor API.
These resources will help plugin developers in API migration:
- The Migration Guide
- Writing a PostCSS Plugin
- We have a Gitter chat open for all questions related to plugin migration.
PostCSS development guidelines were also changed:
- Now it is prohibited to create own AST on top of PostCSS AST classes since it could lead to painful bugs due to the usage private APIs.
- Plugins and runners must have
postcssinpeerDependencies.
New Website without React
Previously PostCSS used a React-based framework for the project's website. Since we have a static website, we decided to migrate to a React-free framework and got good performance improvements:
- 360 → 20 ms for Max Potential First Input Delay
- 3.3 → 1.5 seconds for First CPU Idle
- 3.3 → 1.5 seconds for Time to Interactive
Check out postcss.org and new API docs that feature the awesome alchemy-inspired design by @okonet.
We also removed Google Analytics tracking scripts and encourage other open source projects to be an example in caring about user’s privacy and performance.
Parser Improvments
Did you know that all examples below are valid CSS?
:root {
--empty: ;
--JSON: [1, "2", {"three": {"a":1}}, [4]];
--javascript: function(rule) { console.log(rule) };
}
@supports (--element(".minwidth", { "minWidth": 300 })) {
[--self] {
background: greenyellow;
}
}
Now PostCSS parses even those rare edge cases correctly. Thanks to Tailwind CSS and Prettier teams for adding more cases to our CSS parser tests collection.
Note that now --roundMixin: { border-radius: 8px } will be parsed as a Declaration with the { border-radius: 8px } value.
Better Source Map Support
We have added support for two new source map formats: Index map and JSON (data:application/json).
PostCSS 8 is now much closer to the source map spec. Thanks to the Google team for reports:
- We now treat
sourcesin map as URLs instead of file paths. - We now resolve
sourcesrelative to map file, not CSS file.
A few source map APIs were added:
opts.maps.absolute = trueoption for absolute paths in source map.opts.maps.annotation = (file, root) => urlfor a dynamic path to source map.Node#origin()now returnsposition.urlin addition toposition.filefor compatibility with absolute URLs in source map’ssources.
API Changes
We have added ES modules support and now we export all classes from the main entry:
import { CssSyntaxError, parse } from "postcss"
@graberzz added Node#source.offset in addition to line and column.
CSS Custom Properties and Sass-like $-variables now have a special Declaration#variable mark:
const root = parse(`
:root {
--propery: value;
}
$variable: value
`)
root.first.first.variable //=> true
root.last.variable //=> true
TypeScript
PostCSS now has a first-class TypeScript support:
- We moved API docs from JSDoc to TypeDoc. Check out our new API docs.
- We are using check-dts to test types with special unit tests.
- We keep types in separate files for better readability.
- With the new structure and test system, we fixed many small issues in types.
Other Changes
- Fixed calling
replaceWithwith input replaced node (by @josephkaptur). - Reduce dependencies by replacing
chalktocolorette. - Added
Declaration#valueauto-conversion to string to prevent plugin’s bugs. - Fixed building PostCSS with Rollup (by @MapGrid) because of circular dependencies.
- Moved unknown source from counter to random IDs:
<input css 9M4X8l>:10:6. - Removed docs from the npm package.
- Reduce package size.
- Backport
nanocolorstopicocolorsmigration.
- Update
Processor#version.
- Backport
chalktonanocolorsmigration.
- Backport ReDoS vulnerabilities from PostCSS 8.
- Add migration guide link to PostCSS 8 error text.
- Fix compatibility with
postcss-scss2.
- Add error message for PostCSS 8 plugins.
- Fix error message (by @admosity).
- Use only the latest source map annotation (by @emzoumpo).
- Fix TypeScript definition (by @nex3)
- Update
Processor#version.
- Fix TypeScript definition (by @nex3).
- Fix TypeScript definition (by @nex3).
- Fix TypeScript definition (by @nex3)
- Fix absolute path support for Windows (by @tomrav)
- Fix TypeScript definition (by @keithamus).
- Update
Processor#version.
- Add funding link for
npm fund.
- Revert passing
nodesproperty to node constructor.
- Allow to pass PostCSS’s nodes in
nodesproperty to node constructor.
- Fix passing
nodesproperty to node constructor.
- Fix TypeScript type definitions (by @buschtoens).
- Fix TypeScript type definitions (by @bmatcuk and @buschtoens).
- Revert Custom Properties fix until PostCSS 8.0.
- Fix Custom Properties support (by @isolovev).
- Fix tokenizer for
postcss-less(by @mattlyons0)
- Fix parsing regression in 7.0.12 for comments between property and value.
- Fix parsing broken CSS with two words in declaration property.
- Fix source maps on declaration semicolon (by @mischnic).
- Fix source maps (by @mischnic).
- Increase stringifing performance for non-raws AST.
- Fix TypeScript definitions (by @aoberoi).
- Use
support-colors6.0.
- Extend
ErrorinCssSyntaxError.
- Fix parsing files with BOM (by @vkrol).
- Reduce npm package size (by @pgilad).
- Fix safe parser regression.
- Fix tokenizer extendability (by @shellscape).
- Fix warning text (by @rapzo).
- Fix JSDoc (by @straker).
PostCSS 7.0 dropped Node.js 4 support and brought small features.
Breaking Changes
We removed Node.js 4 and Node.js 9 support since it doesn’t have security updates anymore.
We removed IE and “dead” browsers (without security updates) from Babel’s Browserslist. Don't worry, PostCSS still generate IE-compatible code. These changes affect websites which run PostCSS on client-side like CodePen.
last 2 version
not dead
not Explorer 11
not ExplorerMobile 11
node 10
node 8
node 6
New Features
@nikhilgaba added cute thing for plugin developers. If an error was happened in Container#walk() circle, PostCSS will show in stack trace CSS node, which causes this error:
TypeError: Cannot read property '0' of undefined
at /home/ai/Dev/test/app.css:10:4
at plugin (plugin.js:2:4)
at runPostCSS (runner.js:2:1)
@igorkamyshev added finally method to LazyResult to make it compatible with the latest Promise API.
Other Changes
- Client-side size was reduced by Size Limit feedback.
- Add warning on calling PostCSS without plugins and syntax options.
- Fix parsing nested at-rules without semicolon, params, and spaces.
- Fix docs (by @kschiffer and @tivac).
- Fix
Node#prevandNode#nexton missed parent.
- Rename Chinese docs to fix yarnpkg.com issue.
- Better error message on
nullas input CSS.
- Fix TypeScript definitions for source maps (by @hzlmn).
- Fix
sourcefield in TypeScript definitions (by @sylvainpolletvillard).
- Use primitive object in TypeScript definitions (by @sylvainpolletvillard).
- Fix parsing comment in selector between word tokens (by @hzlmn).
- Fix warning text (by @mhkeller).
- Add warning about missed
fromoption onprocess().then()call. - Add IE 10 support.
- Fix TypeScript definitions (by @jedmao).
- Fix TypeScript definitions for case of multiple PostCSS versions in
node_modules(by @chriseppstein). - Use
source-map0.6.
- Don’t copy
*hack to declaration indent.
- Add upper case
!IMPORTANTsupport.
- Reduce PostCSS size in webpack bundle.
- Improve error message for plugin with old PostCSS (by @igoradamenko).
- Fix Node.js 4.2.2 support.
Fix base64 decoding for old Node.js and browser.
- Fix
endposition in at-rule without semicolon (by @hzlmn).
- Move Babel config from
package.jsonfornode_modulescompiling cases.
- Fix escape sequences parsing (by @hzlmn).
- Added ability to force disable colors with an environment variable.
- Improved color detection of some terminal apps.
- Keep
raws.beforeon movingRootchildren to newRoot.
- Fix parser extensibility to use it in Safe Parser.
PostCSS 6.0 drops support for Node.js 0.12, cleans the raws API, adds support for @apply, and uses less memory.
Breaking Changes
Node.js stopped 0.12 support in January 01. So PostCSS dropped Node.js 0.12 from all tests. Please update your Node.js version to 4.0 or 7.0.
In 6.0 we fixed our mistakes in API design. First, if node already had a parent, insert methods (append, insertAfter, etc) will not clone it anymore. In 6.0 inserts methods will remove inserted node from previous parent:
parent1.nodes.length //=> 3
parent2.append(parent1.nodes[0])
parent1.nodes.length //=> 2
Now, moveTo, moveAfter & moveBefore are deprecated because regular insert methods have this move behavior.
Also Node#clone now returns the exact copy of a node. In 6.0 it no longer cleans raws.
node.raws.before //=> "\n "
const clone = node.clone()
clone.raws.before //=> "\n "
Every PostCSS plugin has plugin.process shortcut. In 6.0 we split process and plugin options in this shortcut:
const plugin = postcss.plugin('postcss-awesome', colors => {
…
})
plugin.process(css, { from: 'app.css' }, colors).css
In the new major release, we finally remove all deprecated methods from PostCSS 4.0. It should not be a big problem because we show deprecated warnings for them for 2 years. Most of the plugins updated their API.
New Methods and Properties
Since we removed deprecated methods from PostCSS 4.0, in 6.0 we were free to add before() and after() shortcuts, similar to DOM API methods.
node1.before(node2)
// is equal too
node1.parent.insertBefore(node1, node2)
Chrome 51 started to support “native CSS mixins” from @tabatkins spec under the flag:
:root {
--clearfix: {
display: table;
clear: both;
content: '';
};
}
.box:after{
@apply --clearfix;
}
PostCSS 5.0 could parse it pretty well, but in some cases, it lost the semicolon after a mixin definition. In PostCSS 6.0 parser we covered this case, and node rules have Rule#raws.ownSemicolon for their own semicolon.
Stream Parser
In PostCSS 5.0 tokenizing and parsing were separated steps. As a result, we wrote all tokens into memory between steps. It worked well most of the time, but had a large memory usage when parsing really big CSS files (more than 25 MB).
In 6.0 @hzlmn rewrote parser, and now parser and tokenizer work together (stream parser). As a result, we put only a few of the latest tokens in memory. So 6.0 will use less memory.
Package Size
We care about node_modules size problem. So in 6.0 @lahmatiy and @h0tc0d3 removed js-base64 dependency to use native Node.js and Browsers ways to base64 encoding.
Also, PostCSS was moved to babel-preset-env. Instead of regular babel, it will compile only necessary parts of ES6. So build in npm packages will be cleaner. Current browserslist config for babel-preset-env is last 1 version and node 4.
Other Changes
- Fix error message on single
:in CSS. - Move tests to Jest.
- Clean up test (by @gkal19).
- Add
postcss-sasssuggestion to syntax error on.sassinput.
- Better error on wrong argument in node constructor.
- Fix TypeScript definitions (by @bumbleblym).
- Fix browser bundle building in webpack (by @janschoenherr).
- Do not add comment to important raws.
- Fix JSDoc (by @Semigradsky)
- Fix typo in deprecation message (by @garetmckinley).
- Fix TypeScript definitions (by @jedmao)
- Fix TypeScript definitions (by @jedmao)
- Update TypeScript definitions (by @jedmao).
- Fix error message (by @ben-eb).
- Better error message on syntax object in plugins list.
- Fix
postcss.vendorfor values with spaces (by @gucong3000).
- Better error message on unclosed string (by @ben-eb).
- Improve terminal CSS syntax highlight (by @lydell).
- Better color highlight in syntax error code frame.
- Fix color highlight support in old systems.
- Update
Processor#version.
- Fix source map path for CSS without from option (by @mlocati).
PostCSS 5.2 contains parser fix and better syntax error output.
Syntax Errors
In previous versions syntax errors were very simple:
@andreypopp did great work and now main webpack’s loaders have same output on syntax error. Unification is good, so we decided to use same output for PostCSS errors too.
First, we added line numbers to code frame. Then we increased lines count. @andreypopp added syntax highlight. And finally @lydell fix output for tab indent and some other edge cases.
So right now PostCSS syntax errors are similar to Babel and webpack errors:
Highlight CSS
PostCSS 5.2 has CSS syntax highlight for syntax error. But you can use our highlighter in your terminal tool too:
const highlight = require('postcss/lib/terminal-highlight');
console.log(highlight('a { color: black }'))
Parser Fixes
PostCSS 5.2 has new [ and ] tokens to parse [attr=;] { } correctly.
- Suggests SCSS/Less parsers on parse errors depends on file extension.
- Fix TypeScript definitions (by @lexich).
PostCSS 5.1 brings few improvements for source maps and JSDoc.
Source Map
@markfinger improved source map support for new cases. He added absolute URI support in from/to options and added new map.from options for better control.
Some plugin developers forget to set correct Node#source for nodes. @TrySound add some help for developers. Now PostCSS will set <no source> source for sourceless nodes.
@montmanu add function value support for map.prev option.
JSDoc
We moved all API docs close to source and now PostCSS has JSDoc comments for every public method and property.
I hope it will make plugin development easy: API docs become better and some IDE will show docs in autocomplete.
You can check latest API on api.postcss.org.
Other
- Move tests from Mocha/Chai to AVA.
- Add declaration value type check in shortcut creating (by @gucong3000).
Result#warnnow returns new created warning.- Don’t call plugin creator in
postcss.plugincall. - Add source maps to PostCSS ES5 build.
- Clean npm package from unnecessary docs.
- Fix support with input source map with
utf8encoding name.
- Fix between raw value parsing (by @davidtheclark)
- Update TypeScript definitions (by @jedmao)
- Clean fake node.source after
append(string).
- Fix indent-based syntaxes support.
- Parse new lines according W3C CSS syntax specification.
- Fix options argument in
Node#warn(by @ben-eb). - Fix TypeScript definitions (by @jedmao).
- Fix CSS syntax error position on unclosed quotes.
- Fix
Node#clone()onnullvalue somewhere in node.
- Allow to use PostCSS in webpack bundle without JSON loader.
- Fix
indexandwordoptions inWarning#toString(by @TrySound). - Fix input source content loading in errors.
- Fix map options on using
LazyResultas input CSS. - 100% test coverage.
- Use Babel 6.
- Allow passing a previous map with no mappings (by @papandreou).
- Increase plugins performance by 1.5 times.
- Fix warning from nodes without source.
- Fix source map type detection (by @asan).
- Fixed a missed step in
5.0.7that caused the module to be published as ES6 code.
- PostCSS now requires that node 0.12 is installed via the
enginesproperty in package.json (by @leftstick).
- Fix parsing nested at-rule without semicolon (by @mahtd).
- Trim
Declaration#value(by @TrySound).
- Fix multi-tokens property parsing (by @mahtd).
- Fix start position in
Root#source. - Fix source map annotation, when CSS uses
\r\n(by @MohammadYounes).
- Fix
url()parsing. - Fix using
selectorsinRuleconstructor. - Add start source to
Rootnode.
- Fix
remove(index)to be compatible with 4.x plugin.
- Fix PostCSS 4.x plugins compatibility.
- Fix type definition loading (by @jedmao).
PostCSS 5.0 brings custom syntax and fixes plugin API.
It is a biggest release in project history. But do not worry, we have only few very rare breaking changes.
Breaking Changes
safeoption was removed and Safe Parse was moved to separated project.
Useparser: require('postcss-safe-parser')instead.- Node.js 0.10 is not officially supported anymore. However, PostCSS should still work, if you install and load the es6-promise polyfill.
Node#toStringdoes not includebeforespace symbols for root nodes.- Very rare returning new
Rootplugin API was removed.
Custom Syntaxes
Now PostCSS can transform styles in any syntax, not only in CSS. It is important for cases:
- We have many tools like CSSfmt or Stylelint, which works directly with sources. So now, they will be able to work with SCSS by postcss-scss.
- Now we can use shorter syntax for PostCS-only solutions. For example,
// one line commentswith SCSS parser or SugarSS with Stylus/Sass like syntax. - CSS-in-JS solutions like React Style Autoprefix or Styling now can directly convert JS object to PostCSS AST without stringifing and reparsing.
PostCSS 5.0 has 3 new options:
parserto change input parser. For example, to use Safe Parser in online demo tool.stringifierto change output content generator.syntaxto change both parser and stringifier.
Because some syntax can return non-CSS value, Result now has content alias.
import scss from 'postcss-scss';
postcss().process(source, { syntax: scss }).then( (result) => {
result.content // SCSS-to-SCSS transforms
});
postcss().process(source, { parser: scss }).then( (result) => {
result.css // Compile SCSS one-line comments
});
We wrote good docs about developing new syntax for PostCSS. If you will have any questions, ask in our Gitter chat.
API Changes
In 5.0 we change nodes API to make it clear and more familiar to DOM or jQuery API. Do not worry, old methods are still work, just show a deprecated message.
If your plugin is built with PostCSS 5.0, it will have plugin.process(css) shortcut to work as separated tool:
import nested from `postcss-nested`;
nested.process(css).then( result => console.log(result.css) );
@jedmao renamed eachInside, eachDecl, eachRule, eachAtRule and eachComment to walk, walkDecls, walkRules, walkAtRules and walkComments. So recursive behaviour is more clear.
@ben-eb with @jonathantneal made API more common with DOM API:
- Method
removedeletes node itself andremoveChildremoves child from container. - Method
Node#replacewas removed in favor ofreplaceWith. - Insert methods now support multiple arguments with nodes.
All whitespace symbols properties now called “raw” and located in Node#raws object, so custom parser can add own custom raw properties. Node#style and cleanStyles methods were renamed to raw and cleanRaws:
if ( decl.raw('before').match(/\n/) ) {
decl.raws.before = '';
}
Messages
PostCSS ecosystem now has one of the best CSS linters — Stylelint. So we make warning/error API much better.
First, In 5.0 we have smarter color support detection by @sindresorhus supports-color.
Second, we add word and index options to errors and warnings methods to highlight special word in bad node.
Third, we now have Node#warn shortcut to add warnings:
export default postcss.plugin('postcss-important-hater', () => {
return (css, result) => {
css.walkDecls( (decl) => {
if ( decl.important ) {
decl.warn(result, '!important is bad', { word: '!important' });
}
});
};
});
// title.sass:2:15 !important is bad
// .title
// color: black !important
// ^
TypeScript and Windows
@jedmao made PostCSS really enterprise ready solution :).
First, he fix all tests on Windows and added AppVeyor CI to test every commit on Windows.
Second, he made really big job and added type definitions for TypeScript. For example, Visual Studio will show nice autocompletion with documentation:

Do not worry, PostCSS itself is still ES7 project.
Other Changes
- Deprecate
CssSyntaxError#generatedin favor ofinput. - Deprecate
Root#prevMapin favor ofRoot.source.input.map. - Add stringifier option to
Node#toString. Rule#selectorssetter detects separators.- Add
postcss.stringifymethod. - Throw descriptive errors for incorrectly formatted plugins.
- Add docs to npm release.
- Fix
url()parsing.
- Fix errors without stack trace.
- Allow asynchronous plugins to change processor plugins list (by @ben-eb)
- Fix for plugins packs defined by
postcss.plugin.
- Fix input inlined source maps with UTF-8 encoding.
- Update Promise polyfill.
- Fix error message on wrong plugin format.
- Fix Promise behavior on sync plugin errors.
- Automatically fill
pluginfield inCssSyntaxError. - Fix warning message (by @ben-eb).
- Speed up
node.clone().
- Accepts
Processorinstance inpostcss()constructor too.
- Speed up
postcss.list(by @TrySound).
- Fix Promise behavior on parsing error.
- Parse at-words in declaration values.
- Fix Promise polyfill dependency (by @antyakushev and @silvenon)
- Add Promise polyfill for node.js 0.10 and IE.
- List helpers can be accessed independently
var space = postcss.list.space.
- Show deprecated message only once.
PostCSS 4.1 brings async plugins support and messages API.
Asynchronous Plugins
PostCSS 4.1 allows plugins to operate asynchronously, by returning a Promise.
module.exports = postcss.plugin('postcss-read', function (opt) {
return function (css) {
return new Promise(function (resolve, reject) {
fs.readFile(opt.file, function (err, content) {
if ( err ) {
reject(err);
} else {
css.append(content);
resolve();
}
});
});
};
});
Note, that PostCSS still runs plugins one-by-one to avoid conflicts.
Messages API
Result instance now has messages array for plugin communications.
Main usage of this messages API is a warnings with Result#warn() and Result#warnings() shortcuts:
var plugin = postcss.plugin('postcss-important-linter', function () {
return function (css, result) {
css.eachDecl(function (decl) {
if ( decl.important ) {
result.warn('Try to avoid !important', { node: decl });
}
});
}
});
postcss([plugin]).process(css).then(function (result) {
result.warnings().forEach(function (msg) {
console.warn(msg.toString());
});
});
With postcss-messages you can see all plugins warnings.
Plugin API
4.1 release contains postcss.plugin() function:
var postcss = require('postcss');
module.exports = postcss.plugin('postcss-plugin-name', function (opts) {
return function (css) {
// Process css
};
});
It creates a plugin with a standard API:
plugin.postcssPlugin //=> "postcss-plugin-name"
plugin.postcssVersion //=> "4.1.0"
postcss([ plugin ]) // with default options
postcss([ plugin({ prop: 'color' }) ]) // with options
Also node.error() now accepts plugin option:
if ( !variables[name] ) {
throw decl.error('Unknown variable ' + name, { plugin: 'postcss-vars' });
}
Guidelines
As PostCSS grows, it is time to take care of its ecosystem.
As first step we made the Guidelines for PostCSS runners, like gulp-postcss or postcss-cli.
The guidelines for plugin developers will be published next month. Stay tuned with @PostCSS.
Other Changes
- Insert nodes by CSS string.
- Show version warning message on error from an outdated plugin.
- Send
Resultinstance to plugins as the second argument. - Add
CssSyntaxError#showSourceCode(). - Add
postcss.listandpostcss.vendoraliases. - Parse wrong closing bracket.
- Add
Processor#version. - Parse
!importantstatement with spaces and comments inside (by @ben-eb). - Throw an error on declaration without
proporvalue(by @philip-peterson). - Fix source map mappings position.
- Add indexed source map support.
- Always set
error.generated. - Clean all source map annotation comments.
- Remove
babelfrom released package dependencies (by @zertosh).
- Fix error message on double colon in declaration.
- Fix indent detection in some rare cases.
- Faster API with 6to5 Loose mode.
- Fix indexed source maps support.
- Do not copy IE hacks to code style.
- Add
source.inputtoRoottoo.
PostCSS 4.0 brings new APIs for plugin developers.
New Methods
cloneBefore()andcloneAfter()shortcuts to clone node and insert clone before or after current one.moveTo(rule),moveBefore(node)andmoveAfter(node)to remove node from current parent and append to other parent or insert before/after other node.replaceWith(other)to replace node with other node.rule.removeAll()to remove all children from rule.next(),prev()androot()to travel between nodes.replaceValues(regexp, callback)to replace some string in all declarations values.
Iteration with Filter
Methods eachDecl() and eachAtRule() now have optional first argument with string or regexp to filter declarations by property or at-rules by name:
css.eachDecl(/background(|-image)/, function (decl) {
inlineImage(decl);
});
css.eachAtRule('keyframes', function (atrule) {
atrule.removeSelf();
});
Custom Syntax Errors
If CSS use wrong syntax of your plugin (for example, wrong variable name for variables plugin) now you can throw a custom syntax error with source map support:
if ( wrongName ) {
throw node.error('Wrong variable name');
}
//=> CssSyntaxError: popup.css:45:5: Bad variable syntax
// var-name: 1
// ^
Also error object is a best way to create warning:
if ( notSupported ) {
var error = node.error('This property is not supported in IE');
console.warn( error.toString() );
}
PostCSS syntax error output now contains class name to be like other node.js errors.
Indentations
PostCSS 4.0 has a lot of fixes in CSS whitespaces support. For example, it will change indentation, when you move rule to other node. So plugins like postcss-nested now will return readable output.
API Changes
Container#childswas renamed tonodes.PostCSS#processorswas renamed toplugins.Node#source.filewas moved tosource.input.file.
Other Changes
- You can use object shortcut to create and append rule and at-rule:
root.append({ selector: 'a' })androot.append({ name: 'encoding', params: '"utf-8"' }).
- Fix IE filter parsing with multiple commands.
- Safer way to consume PostCSS object as plugin (by @MoOx).
- Fix missing semicolon when comment comes after last declaration.
- Fix Safe Mode declaration parsing on unclosed blocks.
- Fix parser to support difficult cases with backslash escape and brackets.
- Add
CssSyntaxError#stack(by @MoOx).
- Fix Safe Mode on unknown word before declaration.
- Increase tokenizer speed (by @lahmatiy).
- Fix empty comment parsing.
- Fix
Root#normalizein some inserts.
- Fix Rhino JS runtime support.
- Typo in deprecated warning (by @MoOx).
PostCSS 3.0 now has the fastest JavaScript-based CSS parser.
Performance
Unlike most CSS parsers, PostCSS preserves whitespace. So historically PostCSS did not have the best performance of them all. But for PostCSS 3.0 we've decided to focus on the performance issues.
- @Termina1 added good benchmarks in order to have feedback for performance optimizations.
- We've moved from ES6 Transpiler to 6to5 compiler. Unfortunately, Transpiler had a side effect to Node.js perfomance.
- Our old parser was already too complicated. So we split it in two steps: tokenizing and parsing. As a result, parser become much simpler — and ready for hardcore optimizations.
- @Termina1 added quick space check and faster
map. - @brainopia went even further and rewrote tokenizer to use char codes instead of strings. Also he added fast jumps for finding a closed quote or bracket.
As result, the PostCSS parser is now 6 times faster. Current benchmark on bootstrap.css (Fedora 20, node 0.10.32, i7-3517U, 8 GB RAM, SSD):
PostCSS 3: 23 ms
CSSOM: 28 ms (1.2 times slower)
Mensch: 47 ms (2.0 times slower)
Rework: 62 ms (2.7 times slower)
Stylecow: 122 ms (5.3 times slower)
PostCSS 2: 141 ms (6.1 times slower)
Gonzales PE: 162 ms (7.0 times slower)
Gonzales: 175 ms (7.5 times slower)
Nested Rules
Old PostCSS 2 could not parse @page at-rule, because it did contain a mix of at-rules and declarations:
@page {
margin-top: 10px;
@bottom-center { ... /* page number */}
}
PostCSS 3.0 can now parse declarations, rules and at-rules inside any parent node. As a result, we can support custom at-rules with any type of content inside (declarations, rules or mix of declarations and rules):
@sprite-config {
padding: 5px;
}
Another benefit is that you now can write plugins like postcss-nested.
API Changes
- Child nodes array is now in
Container#childsproperty.declsandrulesproperties are now deprecated and will be removed in the 3.1 release. map.inlineandmap.sourcesContentproperties are now enabled by default, since it is now the most popular way to use maps.
Other Changes
- Fix iterators (
each,insertAfter) on child array changes. - Use previous source map to show origin source of the CSS syntax error.
- Use code style for manually added rules from existing rules.
- Use
fromoption from previous source mapfilefield. - Set
tovalue tofromiftooption is missing. - Use better node source name if
fromoption is missing. - Show a syntax error when
;is missing between declarations. - Allow to pass
PostCSSinstance or list of plugins touse()method. - Allow to pass
Resultinstance toprocess()method. - Do not remove previous
sourceMappingURLcomment onmap.annotation: false. - Fix source map generation for nodes without source.
- Fix next child
beforeifRootfirst child got removed.
- Fix map generation for nodes without source (by @josiahsavary).
- Fix source map with BOM marker support (by @MohammadYounes).
- Fix source map paths (by @MohammadYounes).
- Fix
prepend()on emptyRoot.
- Allow to use object shortcut in
use()with functions likeautoprefixer.
- Add shortcut to set processors in
use()via object with.postcssproperty.
This release adds Node#replace() shortcut and uses GNU style for syntax error messages.
Replace Nodes
@jonathanong suggested good shortcut to replace one node to another (or several other nodes). For example, you can write @import loader:
css.eachAtRule(function (rule) {
if ( rule.name != 'import' ) return;
var file = readFileFromRule(rule);
var content = fs.readFileSync(file);
var root = postcss.parse(content, { from: file });
rule.replace(root);
});
GNU Style for Syntax Errors
Old PostCSS’s errors was like Can't parse CSS: Unexpected { in decls at line 2:1 in a.css.
But GNU Coding Standards had good recommendations for syntax error messages. Rework, CoffeeScript and other tools already use it. Also some tools can find this format in output and they will open your text editor on this line.
PostCSS 2.2 now uses GNU style for syntax errors:
a.css:2:1 Unexpected { in decls
Also CssSyntaxError now has reason property to build your own error messages in end-user interfaces (in previous example it will be "Unexpected { in decls").
PostCSS Organization
PostCSS repository was moved to postcss GitHub organiztion, which will host official plugins.
- Allow to miss
toandfromoptions for inline source maps. - Add
Node#source.idif file name is unknown. - Better detect splitter between rules in CSS concatenation tools.
- Automatically clone node in insert methods.
PostCSS 2.1 has new ES6 compiler and show syntax error source.
ES6 Transpiler
PostCSS 2.0 used Traceur to compile ES6 sources to pure JS. Traceur is very powerful, but require to add special runtime JS file to build. Runtime was very big, had side effects and some problems in Browserify and Rhino.
New PostCSS 2.1 uses ES6 Transpiler. It hasn’t runtime, doesn’t change system classes and very small and easy to use. Also it has line-to-line input/output mapping to make debug easier.
Source Line in Syntax Error
By @jonathanong idea CSS syntax error messages now include broken source line:
> postcss.parse('a {\n b { }\n}')
Can't parse CSS: Unexpected { in decls at line 2:5
a {
b { }
^
}
PostCSS will try to detect environment and use colors in error output if they are supported.
Logo
And now PostCSS has own logo. It is alchemist symbol of philosopher’s stone, which can process lead into gold.
PostCSS 2.0 was rewritten from CoffeeScript to ES6, contains Safe Mode and is more friendly to new developers.
ES6
PostCSS was written on CoffeeScript to have clean and readable code. But many developers afraid CoffeeScript, because of very different syntax.
I think, that it is very important to be able to read your framework sources. To be more friendly to developers PostCSS was rewritten to ES6.
If you use npm you will not see any changes. PostCSS releases contain only compiled pure JS from Traceur. But now you can read PostCSS sources without the knowledge of CoffeeScript syntax.
Testing
PostCSS should not fall on some legacy CSS with hacks. So we have not only unit tests, but also test all releases with real world CSS from Twitter, GitHub, Bootstrap and Habrahabr.
But this sites have good written code. PostCSS 2 are also tested with Browserhacks examples and contains few parser fixes to pass all CSS hacks from there.
Safe Mode
PostCSS 2.0 had special Safe Mode, which try to fix broken CSS. For example, it will parse a { as a {}. It will be useful for live input tool (like Autoprefixer interactive demo) or to parse old legacy code.
postcss.parse('a {'); // will throw "Unclosed block"
postcss.parse('a {', { safe: true }); // will return CSS root for a {}
Raw Properties
PostCSS used getter and setter for selector, value, etc properties. They confused new users, because getters was not showed, when you inspect node in console.
PostCSS 2 is more friendly to new developers and use only regular properties without any magic.
This release improved source map API and allowed to use PostCSS with multiple inputs, like in file concatenation tools.
Source Map API Changes
@lydell suggested great plan to clean up source map options. Now all map options will be inside map object.
inlineMap: truewas renamed tomap: { inline: true }.mapAnnotation: falsewas renamed tomap: { annotation: false }.- Previous source map should be set to separated option
map: { prev: prevMap }instead of oldmap: prevMap.
There is map: 'inline' shortcut if you want to set only map: { inline: true }. Old options are deprecated and will print warnings.
Also there are two API improvements for plugin’s popular needs:
- Map can contain origin CSS source, if you set
map: { sourcesContent: true }option. - You can change result map path by
map: { annotation: '../maps/app.css.map' }option. Note that path inannotationmust be relative to output CSS file.
Result API Changes
By @dantman idea, process(css, opts) and toResult(opts) methods now return lazy result object, so CSS will not be stringified until you access to result.css or result.map properties:
var result1 = processor.process(css1);
var result2 = processor.process(css2);
// We need to concat this files, so we doesn’t need to stringify content yet
result1.root.append( result2.root );
result1.css // Now output CSS will be stringified
result1.map // Source map will be generated only now
// and will include map from result2
Also Result#map will return SourceMapGenerator object (from Mozilla’s source-map) instead of string. It will allow to change something in generated map:
var result = processor.process(css, { map: true });
result.map.applySourceMap(otherMap, 'undetected.css');
console.log('map: ' + result.map) // SourceMapGenerator has toString() method,
// so old code should work
result.map.toJSON().file // But also you can access to generated map properties
Styles Concatenation
PostCSS now tracks previous source map in every node. So, when you move any node from one root to another, it will take previous map:
root1 = postcss.parse(css1, { map: { prev: prev1 } });
root2 = postcss.parse(css2, { map: { prev: prev2 } });
root1.append( root2.rules[0] );
root.toResult().map // will include prev1 and prev2 maps
Also all methods to add node (append, prepend, insertBefore, insertAfter) now accept arrays and Root node:
root1.append( root2 );
root1.append( root3.rules[1].rules );
Other Changes
- PostCSS is written on CoffeeScript, so you wasn’t be able to use latest unreleased versions from GitHub. Now code contains special hack and you can use latest PostCSS by
"postcss": "ai/postcss"in your npm’spackage.json. Rootnode now hasprevMapproperty with information about previous map. Mostly for internal usage, but maybe you will need it.- PostCSS will try to autodetect previous source map file only if input CSS contains annotation comment with map path.
Node#source.filenow contains absolute path. It is also part of work to support style concatenation, when you can generate different roots from different paths.Declaration#clone()will cleanbetweenstyle too to use style from new place.
- Allow to use
RootorResultas first argument inprocess(). - Save parsed AST to
Result#root.
- Better space symbol detect to read UTF-8 BOM correctly.
- Remove source map hacks by using new Mozilla’s
source-map(by @lydell).
- Add URI encoding support for inline source maps.
- Fix relative paths from previous source map.
- Safer space split in
Rule#selectors(by @lydell).