You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

195 lines
5.8 KiB

4 years ago
  1. # PostCSS Plugin Guidelines
  2. A PostCSS plugin is a function that receives and, usually,
  3. transforms a CSS AST from the PostCSS parser.
  4. The rules below are *mandatory* for all PostCSS plugins.
  5. See also [ClojureWerkz’s recommendations] for open source projects.
  6. [ClojureWerkz’s recommendations]: http://blog.clojurewerkz.org/blog/2013/04/20/how-to-make-your-open-source-project-really-awesome/
  7. ## 1. API
  8. ### 1.1 Clear name with `postcss-` prefix
  9. The plugin’s purpose should be clear just by reading its name.
  10. If you wrote a transpiler for CSS 4 Custom Media, `postcss-custom-media`
  11. would be a good name. If you wrote a plugin to support mixins,
  12. `postcss-mixins` would be a good name.
  13. The prefix `postcss-` shows that the plugin is part of the PostCSS ecosystem.
  14. This rule is not mandatory for plugins that can run as independent tools,
  15. without the user necessarily knowing that it is powered by
  16. PostCSS — for example, [RTLCSS] and [Autoprefixer].
  17. [Autoprefixer]: https://github.com/postcss/autoprefixer
  18. [RTLCSS]: https://rtlcss.com/
  19. ### 1.2. Do one thing, and do it well
  20. Do not create multitool plugins. Several small, one-purpose plugins bundled into
  21. a plugin pack is usually a better solution.
  22. For example, [`postcss-preset-env`] contains many small plugins,
  23. one for each W3C specification. And [`cssnano`] contains a separate plugin
  24. for each of its optimization.
  25. [`postcss-preset-env`]: https://preset-env.cssdb.org/
  26. [`cssnano`]: https://github.com/ben-eb/cssnano
  27. ### 1.3. Do not use mixins
  28. Preprocessors libraries like Compass provide an API with mixins.
  29. PostCSS plugins are different.
  30. A plugin cannot be just a set of mixins for [`postcss-mixins`].
  31. To achieve your goal, consider transforming valid CSS
  32. or using custom at-rules and custom properties.
  33. [`postcss-mixins`]: https://github.com/postcss/postcss-mixins
  34. ### 1.4. Create plugin by `postcss.plugin`
  35. By wrapping your function in this method,
  36. you are hooking into a common plugin API:
  37. ```js
  38. module.exports = postcss.plugin('plugin-name', opts => {
  39. return (root, result) => {
  40. // Plugin code
  41. }
  42. })
  43. ```
  44. ## 2. Processing
  45. ### 2.1. Plugin must be tested
  46. A CI service like [Travis] is also recommended for testing code in
  47. different environments. You should test in (at least) Node.js [active LTS](https://github.com/nodejs/LTS) and current stable version.
  48. [Travis]: https://travis-ci.org/
  49. ### 2.2. Use asynchronous methods whenever possible
  50. For example, use `fs.writeFile` instead of `fs.writeFileSync`:
  51. ```js
  52. postcss.plugin('plugin-sprite', opts => {
  53. return (root, result) => {
  54. return new Promise((resolve, reject) => {
  55. const sprite = makeSprite()
  56. fs.writeFile(opts.file, sprite, err => {
  57. if (err) return reject(err)
  58. resolve()
  59. })
  60. })
  61. }
  62. })
  63. ```
  64. ### 2.3. Set `node.source` for new nodes
  65. Every node must have a relevant `source` so PostCSS can generate
  66. an accurate source map.
  67. So if you add a new declaration based on some existing declaration, you should
  68. clone the existing declaration in order to save that original `source`.
  69. ```js
  70. if (needPrefix(decl.prop)) {
  71. decl.cloneBefore({ prop: '-webkit-' + decl.prop })
  72. }
  73. ```
  74. You can also set `source` directly, copying from some existing node:
  75. ```js
  76. if (decl.prop === 'animation') {
  77. const keyframe = createAnimationByName(decl.value)
  78. keyframes.source = decl.source
  79. decl.root().append(keyframes)
  80. }
  81. ```
  82. ### 2.4. Use only the public PostCSS API
  83. PostCSS plugins must not rely on undocumented properties or methods,
  84. which may be subject to change in any minor release. The public API
  85. is described in [API docs].
  86. [API docs]: http://api.postcss.org/
  87. ## 3. Errors
  88. ### 3.1. Use `node.error` on CSS relevant errors
  89. If you have an error because of input CSS (like an unknown name
  90. in a mixin plugin) you should use `node.error` to create an error
  91. that includes source position:
  92. ```js
  93. if (typeof mixins[name] === 'undefined') {
  94. throw decl.error('Unknown mixin ' + name, { plugin: 'postcss-mixins' })
  95. }
  96. ```
  97. ### 3.2. Use `result.warn` for warnings
  98. Do not print warnings with `console.log` or `console.warn`,
  99. because some PostCSS runner may not allow console output.
  100. ```js
  101. if (outdated(decl.prop)) {
  102. result.warn(decl.prop + ' is outdated', { node: decl })
  103. }
  104. ```
  105. If CSS input is a source of the warning, the plugin must set the `node` option.
  106. ## 4. Documentation
  107. ### 4.1. Document your plugin in English
  108. PostCSS plugins must have their `README.md` wrote in English. Do not be afraid
  109. of your English skills, as the open source community will fix your errors.
  110. Of course, you are welcome to write documentation in other languages;
  111. just name them appropriately (e.g. `README.ja.md`).
  112. ### 4.2. Include input and output examples
  113. The plugin's `README.md` must contain example input and output CSS.
  114. A clear example is the best way to describe how your plugin works.
  115. The first section of the `README.md` is a good place to put examples.
  116. See [postcss-opacity](https://github.com/iamvdo/postcss-opacity) for an example.
  117. Of course, this guideline does not apply if your plugin does not
  118. transform the CSS.
  119. ### 4.3. Maintain a changelog
  120. PostCSS plugins must describe the changes of all their releases
  121. in a separate file, such as `CHANGELOG.md`, `History.md`, or [GitHub Releases].
  122. Visit [Keep A Changelog] for more information about how to write one of these.
  123. Of course, you should be using [SemVer].
  124. [Keep A Changelog]: http://keepachangelog.com/
  125. [GitHub Releases]: https://help.github.com/articles/creating-releases/
  126. [SemVer]: http://semver.org/
  127. ### 4.4. Include `postcss-plugin` keyword in `package.json`
  128. PostCSS plugins written for npm must have the `postcss-plugin` keyword
  129. in their `package.json`. This special keyword will be useful for feedback about
  130. the PostCSS ecosystem.
  131. For packages not published to npm, this is not mandatory, but is recommended
  132. if the package format can contain keywords.