mirror of
				https://github.com/fooflington/selfdefined.git
				synced 2025-10-31 14:18:32 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			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.
 | 
