PostCSSプラグインの作成
リンク
ドキュメント
サポート
- 質問する
- 最新のアップデートはPostCSSのTwitterで確認できます。
ステップ1:アイデアを創出する
新しいPostCSSプラグインを作成することで、作業に役立つ分野はたくさんあります。
- 互換性の修正:ブラウザの互換性のためのハックを追加し忘れることが多い場合は、PostCSSプラグインを作成して、このハックを自動的に挿入することができます。
postcss-flexbugs-fixes
とpostcss-100vh-fix
は良い例です。 - ルーチン操作の自動化:コンピュータにルーチン操作をさせ、創造的なタスクのための時間を freeing yourself for creative tasks. 例えば、RTLCSS を使用したPostCSSは、デザインを右から左への言語(アラビア語やヘブライ語など)に自動的に変換したり、postcss-dark-theme-class` を使用して、ダーク/ライトテーマスイッチャー用のメディアクエリを挿入したりすることができます。
- よくあるミスの防止:「エラーが2回発生した場合、再び発生します。」 PostCSSプラグインは、ソースコードでよくあるミスをチェックし、不要なデバッグの時間を節約できます。最良の方法は、新しいStylelintプラグインを作成することです(Stylelintは内部でPostCSSを使用しています)。
- コードの保守性の向上: CSS Modules や
postcss-autoreset
は、PostCSSが分離によってコードの保守性を向上させることができる素晴らしい例です。 - ポリフィル:
postcss-preset-env
には、CSSドラフト用のポリフィルがすでにたくさんあります。新しいドラフトを見つけた場合は、新しいプラグインを追加して、このプリセットに送信することができます。 - 新しいCSS構文: CSSに新しい構文を追加することは避けることをお勧めします。新しい機能を追加する場合は、CSSドラフトプロポーザルを作成し、CSSWG に送信してから、ポリフィルを実装することをお勧めします。
postcss-easing-gradients
と このプロポーザル は良い例です。ただし、プロポーザルを送信できない場合がたくさんあります。たとえば、ブラウザのパーサーのパフォーマンスがCSSWGの入れ子になった構文を大きく制限しているため、`postcss-nested の非公式のSassのような構文が必要になる場合があります。
ステップ2:プロジェクトを作成する
プラグインを作成するには2つの方法があります。
- プライベートプラグインを作成する。この方法は、プラグインがプロジェクトの特定のものに関連している場合にのみ使用してください。たとえば、独自のUIライブラリの特定のタスクを自動化する場合などです。
- パブリックプラグインを公開する。これは常に推奨される方法です。Googleでさえ、プライベートのフロントエンドシステムはしばしばメンテナンスされなくなることを覚えておいてください。一方、多くの一般的なプラグインは、クローズドソースプロジェクトでの作業中に作成されました。
プライベートプラグインの場合
postcss/
フォルダに、プラグインの名前を付けた新しいファイルを作成します。- ボイラープレートからプラグインテンプレートをコピーします。
パブリックプラグインの場合
- PostCSSプラグインボイラープレートのガイドに従って、プラグインディレクトリを作成します。
- GitHubまたはGitLabにリポジトリを作成します。
- そこにコードを公開します。
module.exports = (opts = {}) => {
// Plugin creator to check options or prepare caches
return {
postcssPlugin: 'PLUGIN NAME'
// Plugin listeners
}
}
module.exports.postcss = true
ステップ3:ノードを見つける
ほとんどのPostCSSプラグインは2つのことを行います。
- CSSで何かを見つける(たとえば、
will-change
プロパティ)。 - 見つかった要素を変更する(たとえば、古いブラウザのポリフィルとして
will-change
の前にtransform: translateZ(0)
を挿入する)。
PostCSSはCSSをノードのツリー(ASTと呼びます)に解析します。このツリーには以下が含まれる場合があります。
Root
:ツリーの最上位のノード。CSSファイルを表します。AtRule
:@
で始まるステートメント。たとえば、@charset "UTF-8"
や@media (screen) {}
などです。Rule
:内部に宣言を含むセレクタ。たとえば、input, button {}
です。Declaration
:キーと値のペア。たとえば、color: black
です。Comment
:スタンドアロンのコメント。セレクタ、at-ruleパラメータ、および値内のコメントは、ノードのraws
プロパティに格納されます。
AST Explorer を使用して、PostCSSが異なるCSSをASTにどのように変換するかを学ぶことができます。
プラグインオブジェクトにメソッドを追加することで、特定のタイプのすべてのノードを見つけることができます。
module.exports = (opts = {}) => {
return {
postcssPlugin: 'PLUGIN NAME',
Once (root) {
// Calls once per file, since every file has single Root
},
Declaration (decl) {
// All declaration nodes
}
}
}
module.exports.postcss = true
プラグインのイベントの完全なリストはこちらです。
特定の名前の宣言またはat-ruleが必要な場合は、クイック検索を使用できます。
Declaration: {
color: decl => {
// All `color` declarations
}
'*': decl => {
// All declarations
}
},
AtRule: {
media: atRule => {
// All @media at-rules
}
}
その他の場合、正規表現または特定のパーサーを使用できます。
- セレクタパーサー
- 値パーサー
number
、length
、percentage
用のディメンションパーサー。- メディアクエリパーサー
- フォントパーサー
margin
、padding
、border
プロパティ用のサイドパーサー。
ASTを分析するためのその他のツール
正規表現とパーサーは負荷の高いタスクであることを忘れないでください。負荷の高いツールでノードをチェックする前に、String#includes()
クイックテストを使用できます。
if (decl.value.includes('gradient(')) {
let value = valueParser(decl.value)
…
}
リスナーには、enterとexitの2種類があります。 Once
、Root
、AtRule
、Rule
は、子を処理する前に呼び出されます。 OnceExit
、RootExit
、AtRuleExit
、RuleExit
は、ノード内のすべての子を処理した後に呼び出されます。
リスナー間でいくつかのデータを再利用したい場合があります。実行時に定義されたリスナーを使用してこれを行うことができます。
module.exports = (opts = {}) => {
return {
postcssPlugin: 'vars-collector',
prepare (result) {
const variables = {}
return {
Declaration (node) {
if (node.variable) {
variables[node.prop] = node.value
}
},
OnceExit () {
console.log(variables)
}
}
}
}
}
prepare()
を使用して、リスナーを動的に生成できます。たとえば、Browserslist を使用して宣言プロパティを取得する場合などです。
ステップ4:ノードを変更する
適切なノードを見つけたら、それらを変更するか、周囲に他のノードを挿入/削除する必要があります。
PostCSSノードには、ASTを変換するためのDOMのようなAPIがあります。 APIドキュメントをご覧ください。ノードには、周囲を移動するメソッド(Node#next
や Node#parent
など)、子を見るメソッド(Container#some
など)、ノードを削除するメソッド、内部に新しいノードを追加するメソッドがあります。
プラグインのメソッドは、2番目の引数でノードクリエーターを受け取ります。
Declaration (node, { Rule }) {
let newRule = new Rule({ selector: 'a', source: node.source })
node.root().append(newRule)
newRule.append(node)
}
新しいノードを追加した場合、正しいソースマップを生成するためにNode#source
をコピーすることが重要です。
プラグインは、変更または追加したすべてのノードを再訪します。子を変更すると、プラグインは親も再訪します。 Once
と OnceExit
のみが再度呼び出されません。
const plugin = () => {
return {
postcssPlugin: 'to-red',
Rule (rule) {
console.log(rule.toString())
},
Declaration (decl) {
console.log(decl.toString())
decl.value = 'red'
}
}
}
plugin.postcss = true
await postcss([plugin]).process('a { color: black }', { from })
// => a { color: black }
// => color: black
// => a { color: red }
// => color: red
ビジターは変更があった場合にノードを再訪するため、子を追加するだけでは無限ループが発生します。これを防ぐには、このノードがすでに処理されていることを確認する必要があります。
Declaration: {
'will-change': decl => {
if (decl.parent.some(decl => decl.prop === 'transform')) {
decl.cloneBefore({ prop: 'transform', value: 'translate3d(0, 0, 0)' })
}
}
}
Symbol
を使用して、処理されたノードをマークすることもできます。
const processed = Symbol('processed')
const plugin = () => {
return {
postcssPlugin: 'example',
Rule (rule) {
if (!rule[processed]) {
process(rule)
rule[processed] = true
}
}
}
}
plugin.postcss = true
2番目の引数には、警告を追加するためのresult
オブジェクトもあります。
Declaration: {
bad: (decl, { result }) {
decl.warn(result, 'Deprecated property bad')
}
}
プラグインが別のファイルに依存している場合、メッセージをresult
に添付して、ランナー(webpack、Gulpなど)にこのファイルが変更されたときにCSSを再構築する必要があることを知らせることができます。
AtRule: {
import: (atRule, { result }) {
const importedFile = parseImport(atRule)
result.messages.push({
type: 'dependency',
plugin: 'postcss-import',
file: importedFile,
parent: result.opts.from
})
}
}
依存関係がディレクトリの場合は、代わりに `dir-dependency` メッセージタイプを使用する必要があります.
result.messages.push({
type: 'dir-dependency',
plugin: 'postcss-import',
dir: importedDir,
parent: result.opts.from
})
構文エラー(たとえば、未定義のカスタムプロパティ)が見つかった場合は、特別なエラーをスローできます。
if (!variables[name]) {
throw decl.error(`Unknown variable ${name}`, { word: name })
}
ステップ5:フラストレーションと戦う
プログラミングが嫌い
プログラミングが嫌い
プログラミングが嫌い
動いた!
プログラミングが好き
バグが発生し、単純なプラグインでもデバッグに少なくとも10分かかります。単純な元のアイデアが現実の世界では機能せず、すべてを変更する必要があることに気付くかもしれません。
心配しないでください。すべてのバグは見つけられるものであり、別のソリューションを見つけることで、プラグインがさらに良くなる可能性があります。
テストの作成から始めます。プラグインボイラープレートには、`index.test.js` にテストテンプレートがあります。 `npx jest` を呼び出してプラグインをテストします.
テキストエディタのNode.jsデバッガを使用するか、単に `console.log` を使用してコードをデバッグします.
PostCSSコミュニティは、私たち全員が同じ問題を抱えているため、あなたを助けることができます。 特別なチャンネルで質問することを恐れないでください。
ステップ6:公開する
プラグインの準備ができたら、リポジトリで `npx clean-publish` を呼び出します。 `clean-publish` は、npmパッケージから開発設定を削除するためのツールです。このツールはプラグインボイラープレートに追加されています。
新しいプラグイン(小さなものであっても)について、`@postcss` メンションを付けてツイートしてください。または、[私たちのチャット]でプラグインについて教えてください。マーケティングのお手伝いをします。
新しいプラグインをPostCSSプラグインカタログに追加します。