{"id":241179,"date":"2016-05-03T07:19:33","date_gmt":"2016-05-03T14:19:33","guid":{"rendered":"http:\/\/css-tricks.com\/?p=241179"},"modified":"2017-04-10T18:00:46","modified_gmt":"2017-04-11T01:00:46","slug":"want-make-postcss-plugin","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/want-make-postcss-plugin\/","title":{"rendered":"So you want to make a PostCSS plugin"},"content":{"rendered":"

The following is a guest post by Marcus Tis\u00e4ter<\/a>. I think there are a lot of us out there that find PostCSS kind of fascinating. Especially from the perspective of potentially being able to write our own plugins, in JavaScript, that transform CSS in any way we want. But where to begin? How do you do a good job? Marcus explains.<\/em><\/p>\n

<\/p>\n

You may have heard people say that making a PostCSS plugin is easy. But how do you get started? Don’t worry, that’s exactly what we’re going to go through in this article. Then beyond that, we’ll show you what to do once you’re done with your plugin and what it looks like to be a responsible<\/em> PostCSS plugin developer. <\/p>\n

Best practices, here we come.<\/p>\n

How do I start?<\/h3>\n

All it takes is a few lines of JavaScript to get something magical happening in PostCSS. The best way to start is with the official PostCSS-plugin-boilerplate<\/a>. This starter kit includes a initial setup script, a couple npm dependencies, and boilerplate code for your PostCSS plugin; it also provides you with a file to write tests in AVA<\/a> (a test runner) and some documentation to get you going.<\/p>\n

The snippet down below is the most essential part to understand from the plugin. It’s a wrapping function in a method that you are hooking up into the plugin API.<\/p>\n

\/\/ You have to require the shell itself, PostCSS. \r\nvar postcss = require('postcss');\r\n\r\nmodule.exports = postcss.plugin('pluginname', function (opts) {\r\n\r\n  opts = opts || {};\r\n\r\n  \/\/ Work with options here\r\n\r\n  return function (css, result) {\r\n    \/\/ Transform the CSS AST\r\n  };\r\n\r\n});<\/code><\/pre>\n

First, we need to understand what PostCSS gives us out of the box. PostCSS by itself does nothing<\/em>; it’s just a surrounding wrapper for your plugin. The PostCSS core contains a parser that generates a CSS AST (Abstract Syntax Tree), which is a representation of a node tree that parses strings of CSS. When we change something inside the CSS Abstract Syntax Tree, PostCSS will still represent it as a root node but stringify the syntax tree back into a CSS string.<\/p>\n

\"\"<\/figure>\n

Let’s write a really simple PostCSS plugin. We can call it PostCSS-backwards. PostCSS-backwards will let you reverse CSS declaration values backwards. color: dlog<\/code> would reverse to color: gold<\/code> and vice versa. <\/p>\n

var postcss = require('postcss');\r\n\r\nmodule.exports = postcss.plugin('postcss-backwards', function (opts) {\r\n  opts = opts || {};\r\n  return function (css, result) {\r\n\r\n    \/\/ Runs through all of the nodes (declorations) in the file\r\n    css.walkDecls(declaration => { \r\n      declaration.value = declaration.value.split('').reverse().join(''); \r\n    });\r\n\r\n  };\r\n});<\/code><\/pre>\n

Of course, this is just a silly example. It’s not useful and nobody would ever use this. More importantly, this would be bad for the PostCSS plugin ecosystem. We’ll talk more about that later.<\/p>\n

Before we jump into the actual PostCSS API, I would like you to take look at one of my absolute favorite PostCSS plugins, PostCSS Focus<\/a>. PostCSS Focus adds a :focus<\/code> selector to every :hover<\/code> in your stylesheet. This is great for improving accessibility, as :focus<\/code> styles are often forgotten and should almost always be paired with :hover<\/code> styles. <\/p>\n

Have a look at the code marked with a few comments of how this plugin is made.<\/p>\n

var postcss = require('postcss');\r\n\r\nmodule.exports = postcss.plugin('postcss-focus', function () {\r\n  return function (css) {\r\n\r\n    \/\/ Callback for each rule node.\r\n    css.walkRules(function (rule) { \r\n\r\n      \/\/ Match the individual rule selector \r\n      if ( rule.selector.indexOf(':hover') !== -1 ) { \r\n\r\n         \/\/ Array to contain the rule\u2019s individual selector.\r\n        var focuses = []; \r\n        rule.selectors.forEach(function (selector) { \r\n\r\n           \/\/ Passes all declaration values within the match of hover replacing those values with the returned result of focus.\r\n          if ( selector.indexOf(':hover') !== -1 ) {\r\n\r\n            focuses.push(selector.replace(\/:hover\/g, ':focus')); \r\n          }\r\n\r\n        });\r\n\r\n        \/\/ Checks if array contain values\r\n        if ( focuses.length ) { \r\n          \/\/ Concat the original rules with the new duplicated :focus rules \r\n          \/\/ Groups of selectors are automatically split with commas.\r\n          rule.selectors = rule.selectors.concat(focuses);\r\n        }\r\n      }\r\n    });\r\n  };\r\n});<\/code><\/pre>\n

Get to know the PostCSS API<\/h3>\n

The PostCSS API<\/a> is the fastest and most accurate CSS parser that I have ever used. The documentation behind it is very well written and covers everything you need to know in order for you to master it. The API provides various amounts of functions, classes, common methods, and modules to use. There are methods that you might already be familiar with like, prepend<\/code><\/a>, append<\/code><\/a>, clone<\/code><\/a>, cloneAfter<\/code><\/a> or replaceWith<\/code><\/a>. You can compare it to the DOM(Document Object Model) API<\/a>, being able to manipulate CSS. It’s the same ideology. <\/p>\n

If you can’t get what you want done with the PostCSS API directly, you can extend your plugin with so-called helper tools. Tools like selector, value and dimension parsers or function and property resolvers. The Function resolver<\/a> is one of the more popular ones. It’s a tool made for exposing JavaScript functions. <\/p>\n

Other extendable tools to use:<\/h4>\n