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