196 lines
5.8 KiB
Markdown
196 lines
5.8 KiB
Markdown
# PostCSS Plugin Guidelines
|
||
|
||
A PostCSS plugin is a function that receives and, usually,
|
||
transforms a CSS AST from the PostCSS parser.
|
||
|
||
The rules below are *mandatory* for all PostCSS plugins.
|
||
|
||
See also [ClojureWerkz’s recommendations] for open source projects.
|
||
|
||
[ClojureWerkz’s recommendations]: http://blog.clojurewerkz.org/blog/2013/04/20/how-to-make-your-open-source-project-really-awesome/
|
||
|
||
## 1. API
|
||
|
||
### 1.1 Clear name with `postcss-` prefix
|
||
|
||
The plugin’s purpose should be clear just by reading its name.
|
||
If you wrote a transpiler for CSS 4 Custom Media, `postcss-custom-media`
|
||
would be a good name. If you wrote a plugin to support mixins,
|
||
`postcss-mixins` would be a good name.
|
||
|
||
The prefix `postcss-` shows that the plugin is part of the PostCSS ecosystem.
|
||
|
||
This rule is not mandatory for plugins that can run as independent tools,
|
||
without the user necessarily knowing that it is powered by
|
||
PostCSS — for example, [RTLCSS] and [Autoprefixer].
|
||
|
||
[Autoprefixer]: https://github.com/postcss/autoprefixer
|
||
[RTLCSS]: https://rtlcss.com/
|
||
|
||
### 1.2. Do one thing, and do it well
|
||
|
||
Do not create multitool plugins. Several small, one-purpose plugins bundled into
|
||
a plugin pack is usually a better solution.
|
||
|
||
For example, [`postcss-preset-env`] contains many small plugins,
|
||
one for each W3C specification. And [`cssnano`] contains a separate plugin
|
||
for each of its optimization.
|
||
|
||
[`postcss-preset-env`]: https://preset-env.cssdb.org/
|
||
[`cssnano`]: https://github.com/ben-eb/cssnano
|
||
|
||
### 1.3. Do not use mixins
|
||
|
||
Preprocessors libraries like Compass provide an API with mixins.
|
||
|
||
PostCSS plugins are different.
|
||
A plugin cannot be just a set of mixins for [`postcss-mixins`].
|
||
|
||
To achieve your goal, consider transforming valid CSS
|
||
or using custom at-rules and custom properties.
|
||
|
||
[`postcss-mixins`]: https://github.com/postcss/postcss-mixins
|
||
|
||
### 1.4. Create plugin by `postcss.plugin`
|
||
|
||
By wrapping your function in this method,
|
||
you are hooking into a common plugin API:
|
||
|
||
```js
|
||
module.exports = postcss.plugin('plugin-name', opts => {
|
||
return (root, result) => {
|
||
// Plugin code
|
||
}
|
||
})
|
||
```
|
||
|
||
## 2. Processing
|
||
|
||
### 2.1. Plugin must be tested
|
||
|
||
A CI service like [Travis] is also recommended for testing code in
|
||
different environments. You should test in (at least) Node.js [active LTS](https://github.com/nodejs/LTS) and current stable version.
|
||
|
||
[Travis]: https://travis-ci.org/
|
||
|
||
### 2.2. Use asynchronous methods whenever possible
|
||
|
||
For example, use `fs.writeFile` instead of `fs.writeFileSync`:
|
||
|
||
```js
|
||
postcss.plugin('plugin-sprite', opts => {
|
||
return (root, result) => {
|
||
|
||
return new Promise((resolve, reject) => {
|
||
const sprite = makeSprite()
|
||
fs.writeFile(opts.file, sprite, err => {
|
||
if (err) return reject(err)
|
||
resolve()
|
||
})
|
||
})
|
||
|
||
}
|
||
})
|
||
```
|
||
|
||
### 2.3. Set `node.source` for new nodes
|
||
|
||
Every node must have a relevant `source` so PostCSS can generate
|
||
an accurate source map.
|
||
|
||
So if you add a new declaration based on some existing declaration, you should
|
||
clone the existing declaration in order to save that original `source`.
|
||
|
||
```js
|
||
if (needPrefix(decl.prop)) {
|
||
decl.cloneBefore({ prop: '-webkit-' + decl.prop })
|
||
}
|
||
```
|
||
|
||
You can also set `source` directly, copying from some existing node:
|
||
|
||
```js
|
||
if (decl.prop === 'animation') {
|
||
const keyframe = createAnimationByName(decl.value)
|
||
keyframes.source = decl.source
|
||
decl.root().append(keyframes)
|
||
}
|
||
```
|
||
|
||
### 2.4. Use only the public PostCSS API
|
||
|
||
PostCSS plugins must not rely on undocumented properties or methods,
|
||
which may be subject to change in any minor release. The public API
|
||
is described in [API docs].
|
||
|
||
[API docs]: http://api.postcss.org/
|
||
|
||
## 3. Errors
|
||
|
||
### 3.1. Use `node.error` on CSS relevant errors
|
||
|
||
If you have an error because of input CSS (like an unknown name
|
||
in a mixin plugin) you should use `node.error` to create an error
|
||
that includes source position:
|
||
|
||
```js
|
||
if (typeof mixins[name] === 'undefined') {
|
||
throw decl.error('Unknown mixin ' + name, { plugin: 'postcss-mixins' })
|
||
}
|
||
```
|
||
|
||
### 3.2. Use `result.warn` for warnings
|
||
|
||
Do not print warnings with `console.log` or `console.warn`,
|
||
because some PostCSS runner may not allow console output.
|
||
|
||
```js
|
||
if (outdated(decl.prop)) {
|
||
result.warn(decl.prop + ' is outdated', { node: decl })
|
||
}
|
||
```
|
||
|
||
If CSS input is a source of the warning, the plugin must set the `node` option.
|
||
|
||
## 4. Documentation
|
||
|
||
### 4.1. Document your plugin in English
|
||
|
||
PostCSS plugins must have their `README.md` wrote in English. Do not be afraid
|
||
of your English skills, as the open source community will fix your errors.
|
||
|
||
Of course, you are welcome to write documentation in other languages;
|
||
just name them appropriately (e.g. `README.ja.md`).
|
||
|
||
### 4.2. Include input and output examples
|
||
|
||
The plugin's `README.md` must contain example input and output CSS.
|
||
A clear example is the best way to describe how your plugin works.
|
||
|
||
The first section of the `README.md` is a good place to put examples.
|
||
See [postcss-opacity](https://github.com/iamvdo/postcss-opacity) for an example.
|
||
|
||
Of course, this guideline does not apply if your plugin does not
|
||
transform the CSS.
|
||
|
||
### 4.3. Maintain a changelog
|
||
|
||
PostCSS plugins must describe the changes of all their releases
|
||
in a separate file, such as `CHANGELOG.md`, `History.md`, or [GitHub Releases].
|
||
Visit [Keep A Changelog] for more information about how to write one of these.
|
||
|
||
Of course, you should be using [SemVer].
|
||
|
||
[Keep A Changelog]: http://keepachangelog.com/
|
||
[GitHub Releases]: https://help.github.com/articles/creating-releases/
|
||
[SemVer]: http://semver.org/
|
||
|
||
### 4.4. Include `postcss-plugin` keyword in `package.json`
|
||
|
||
PostCSS plugins written for npm must have the `postcss-plugin` keyword
|
||
in their `package.json`. This special keyword will be useful for feedback about
|
||
the PostCSS ecosystem.
|
||
|
||
For packages not published to npm, this is not mandatory, but is recommended
|
||
if the package format can contain keywords.
|