PostCSS プラグインガイドライン

PostCSS プラグインは、PostCSS パーサーから CSS AST を受け取り、通常は変換する関数です。

以下のルールは、すべての PostCSS プラグインで必須です。

オープンソースプロジェクトについては、ClojureWerkz の推奨事項も参照してください。

1. API

1.1 postcss- 接頭辞が付いた明確な名前

プラグインの目的は、名前を読んだだけで明確であるべきです。CSS 4 Custom Media のトランスパイラを作成した場合、postcss-custom-media は良い名前です。ミックスインをサポートするプラグインを作成した場合、postcss-mixins は良い名前です。

接頭辞 postcss- は、プラグインが PostCSS エコシステムの一部であることを示します。

このルールは、ユーザーが PostCSS を使用していることを必ずしも知らなくても、独立したツールとして実行できるプラグインには必須ではありません。たとえば、RTLCSSAutoprefixer などです。

1.2. 1つのことをうまくやる

多機能プラグインを作成しないでください。いくつかの小さな、単一目的のプラグインをプラグインパックにバンドルする方が、通常は良い解決策です。

たとえば、postcss-preset-env には、W3C 仕様ごとに1つの小さなプラグインが多数含まれています。また、cssnano には、それぞれの最適化のための個別のプラグインが含まれています。

1.3. ミックスインを使用しない

Compass のようなプリプロセッサライブラリは、ミックスインを備えた API を提供します。

PostCSS プラグインは異なります。プラグインは、postcss-mixins のための単なるミックスインのセットではいけません。

目標を達成するには、有効な CSS を変換するか、カスタム at-rules とカスタムプロパティを使用することを検討してください。

1.4. postcsspeerDependencies に指定する

異なるプラグインで異なる postcss バージョンを使用すると、AST が壊れる可能性があります。異なるプラグインが異なるノード作成者(postcss.decl() など)を使用する可能性があります。

{
  "peerDependencies": {
    "postcss": "^8.0.0"
  }
}

postcss をインポートしない方が良いでしょう。

- const { list, decl } = require('postcss')
  module.exports = opts => {
    postcssPlugin: 'postcss-name',
-   Once (root) {
+   Once (root, { list, decl }) {
      // Plugin code
    }
  }
  module.exports.postcss = true

1.5. plugin.postcssPlugin にプラグイン名を設定する

プラグイン名は、エラーメッセージと警告で使用されます。

module.exports = opts => {
  return {
    postcssPlugin: 'postcss-name',
    Once (root) {
      // Plugin code
    }
  }
}
module.exports.postcss = true

2. 処理

2.1. プラグインはテスト済みであること

Travis のような CI サービスは、異なる環境でコードをテストするためにも推奨されます。少なくとも Node.js の アクティブな LTS と現在の安定バージョンでテストする必要があります。

2.2. 可能な限り非同期メソッドを使用する

たとえば、fs.writeFileSync の代わりに fs.writeFile を使用します。

let { readFile } = require('fs').promises

module.exports = opts => {
  return {
    postcssPlugin: 'plugin-inline',
    async Decl (decl) {
      const imagePath = findImage(decl)
      if (imagePath) {
        let imageFile = await readFile(imagePath)
        decl.value = replaceUrl(decl.value, imageFile)
      }
    }
  }
}
module.exports.postcss = true

2.3. 高速な Node のスキャンを使用する

特定のノードタイプを購読する方が、walk* メソッドを呼び出すよりもはるかに高速です。

  module.exports = {
    postcssPlugin: 'postcss-example',
-   Once (root) {
-     root.walkDecls(decl => {
-       // Slow
-     })
-   }
+   Declaration (decl) {
+     // Faster
+   }
  }
  module.exports.postcss = true

しかし、どの宣言のプロパティまたは at-rule の名前が必要かを知っていれば、スキャンをさらに高速化できます。

  module.exports = {
    postcssPlugin: 'postcss-example',
-   Declaration (decl) {
-     if (decl.prop === 'color') {
-       // Faster
-     }
-   }
+   Declaration: {
+     color: decl => {
+       // The fastest
+     }
+   }
  }
  module.exports.postcss = true

2.4. 新しいノードに node.source を設定する

すべてのノードは、関連する source を持っている必要があります。そうすることで、PostCSS は正確なソースマップを生成できます。

そのため、既存の宣言に基づいて新しい宣言を追加する場合は、元の source を保存するために、既存の宣言を複製する必要があります。

if (needPrefix(decl.prop)) {
  decl.cloneBefore({ prop: '-webkit-' + decl.prop })
}

既存のノードからコピーして、source を直接設定することもできます。

if (decl.prop === 'animation') {
  const keyframe = createAnimationByName(decl.value)
  keyframes.source = decl.source
  decl.root().append(keyframes)
}

2.5. 公開されている PostCSS API のみを使用する

PostCSS プラグインは、文書化されていないプロパティやメソッドに依存してはいけません。これらはマイナーリリースで変更される可能性があります。公開 API については、API ドキュメントで説明されています。

3. 依存関係

3.1. メッセージを使用して依存関係を指定する

プラグインが別のファイルに依存している場合は、dependency メッセージを result に添付して指定する必要があります。

result.messages.push({
  type: 'dependency',
  plugin: 'postcss-import',
  file: '/imported/file.css',
  parent: result.opts.from
})

ディレクトリの依存関係は、`dir-dependency` メッセージタイプを使用して指定する必要があります。デフォルトでは、ディレクトリ内のすべてのファイル(再帰的)が依存関係と見なされます。オプションの `glob` プロパティを使用して、特定の glob パターンに一致するファイルのみを考慮するように指定できます。

result.messages.push({
  type: 'dir-dependency',
  plugin: 'postcss-import',
  dir: '/imported',
  glob: '**/*.css', // optional
  parent: result.opts.from
})

4. エラー

4.1. CSS 関連のエラーには node.error を使用する

入力 CSS が原因でエラーが発生した場合(ミックスインプラグインの不明な名前など)、node.error を使用して、ソースの位置を含むエラーを作成する必要があります。

if (typeof mixins[name] === 'undefined') {
  throw node.error('Unknown mixin ' + name)
}

4.2. 警告には result.warn を使用する

console.logconsole.warn で警告を出力しないでください。一部の PostCSS ランナーはコンソール出力を許可しない場合があります。

Declaration (decl, { result }) {
  if (outdated(decl.prop)) {
    result.warn(decl.prop + ' is outdated', { node: decl })
  }
}

CSS 入力が警告の原因である場合、プラグインは node オプションを設定する必要があります。

5. ドキュメント

5.1. プラグインのドキュメントは英語で記述する

PostCSS プラグインは、README.md を英語で記述する必要があります。英語力に不安があっても、オープンソースコミュニティがエラーを修正してくれるので心配しないでください。

もちろん、他の言語でドキュメントを記述することも歓迎します。適切な名前を付けてください(例:README.ja.md)。

5.2. 入力と出力の例を含める

プラグインの README.md には、CSS の入力例と出力例を含める必要があります。明確な例は、プラグインの動作を説明する最良の方法です。

README.md の最初のセクションは、例を配置するのに適した場所です。postcss-opacity を例として参照してください。

もちろん、プラグインが CSS を変換しない場合は、このガイドラインは適用されません。

5.3. 更新履歴を管理する

PostCSS プラグインは、すべてのリリースの変更を CHANGELOG.mdHistory.md、または GitHub Releases などの個別のファイルに記述する必要があります。これらの書き方について詳しくは、Keep A Changelog をご覧ください。

もちろん、SemVer を使用する必要があります。

5.4. package.jsonpostcss-plugin キーワードを含める

npm 用に記述された PostCSS プラグインは、package.jsonpostcss-plugin キーワードを含める必要があります。この特別なキーワードは、PostCSS エコシステムに関するフィードバックに役立ちます。

npm に公開されていないパッケージの場合、これは必須ではありませんが、パッケージ形式にキーワードを含めることができる場合は推奨されます。