aboutsummaryrefslogtreecommitdiff
path: root/node_modules/postcss/docs/guidelines/plugin.md
blob: 4814b0fab4e14f5338f3a628532c4074872925f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# 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, [cssnext] and [Autoprefixer].

[Autoprefixer]: https://github.com/postcss/autoprefixer
[cssnext]:      http://cssnext.io/

### 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, [cssnext] contains many small plugins,
one for each W3C specification. And [cssnano] contains a separate plugin
for each of its optimization.

[cssnext]: http://cssnext.io/
[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', function (opts) {
    return function (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', function (opts) {
    return function (root, result) {

        return new Promise(function (resolve, reject) {
            var sprite = makeSprite();
            fs.writeFile(opts.file, function (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 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' ) {
    var 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` written 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.