プラグインの作成

プラグイン作成時の注意点

プラグインAPI

#

いくつかの異なるタイプのプラグインがあります。それらはすべて非常に似ていますが、それぞれが実行できることを厳密に規定するために別々に保たれています。

すべてのタイプのプラグインで従うべきルールがいくつかあります。

プラグインAPIはすべて共通の形状に従います。

import { NameOfPluginType } from "@parcel/plugin";

export default new NameOfPluginType({
async methodName(opts: JSONObject): Promise<JSONObject> {
return result;
},
});

プラグインの各メソッドは、非同期関数であり、

必要なものが`opts`を通して渡されていない場合は、Parcelチームに相談してください。ファイルシステムなど、他のソースから自分で情報を取得しようとしないでください。

モジュール形式

#

Parcelは、CommonJSまたはESモジュールとして記述されたプラグインをサポートしています。プラグインのモジュール形式は、リゾルバーモジュールのファイル拡張子、またはその`package.json`から決定されます。ESモジュールプラグインには`.mjs`拡張子を使用し、CommonJSには`.cjs`または`.js`を使用します。プラグインの`package.json`に`"type": "module"`が宣言されている場合、`.js`拡張子はCommonJSではなくESMとして扱われます。この動作は、Node.jsがモジュールをロードする方法と一致します。

ESモジュールプラグインは現在実験段階です。発生した問題についてはGithubで報告してください。

設定の読み込み

#

多くのプラグインは、ユーザーのプロジェクトから何らかの設定を読み込む必要があります。場合によっては、プラグインがラップしているコンパイラまたはツールに、設定読み込みメカニズムが組み込まれている場合があります。他のケースでは、プラグイン用の設定ファイル形式を作成する必要があります。

**注記**: ファイルシステムから直接読み取るのではなく、Parcelの設定読み込みメカニズムを使用することが重要です。すべてのプラグインの結果はParcelによってキャッシュされ、Parcelの設定読み込みシステムを使用しない場合、自分で読み込んだファイルが認識されず、キャッシュを適切に無効にすることができません。

設定の読み込みは、ほとんどのプラグインタイプでサポートされている`loadConfig`メソッドで行われます。このメソッドは、設定ファイルの読み込みのためのユーティリティメソッドと、設定ファイルが依存するファイルと依存関係をParcelに通知するためのメソッドを含むConfigオブジェクトを受け取ります。これらは結果を無効にする必要があります。`loadConfig`関数から返された結果は、他のプラグイン関数に渡されます。

import {Transformer} from '@parcel/plugin';

export default new Transformer({
async loadConfig({config}) {
let {contents, filePath} = await config.getConfig([
'tool.config.json'
]);

return contents;
},
async transform({asset, config}) {
// ...
return [asset];
}
});

上記の例では、`Config`オブジェクトの`getConfig`メソッドを使用して設定ファイルを読み込んでいます。これは、指定されたファイル名に一致する設定ファイルを、アセットのファイルパスからディレクトリツリーを上に検索します。JSON5(デフォルト)、JavaScript、またはTOMLを使用してファイルを読み込むことができ、ファイルパスは自動的に設定の無効化に追加されます。

無効化の追加

#

ラップしているコンパイラまたはツールに組み込まれている設定読み込みメカニズムを使用している場合は、`invalidateOnFileChange`を呼び出すことで、そのプロセスで読み込まれたすべてのファイルをParcelに通知する必要があります。このようにして、Parcelは、この設定を使用してコンパイルされたファイルが変更されたときに、ファイルを無効にすることができます。読み込まれたファイルのリストは、多くの場合、さまざまなツールによって読み込まれた設定と一緒に返されます。

設定が読み込まれない場合、またはアセットに近い新しい設定ファイルが結果を変更する場合、`invalidateOnFileCreate`メソッドを使用して、設定ファイルの作成を監視する必要があります。このようにして、Parcelが新しい設定ファイルを検出すると、プラグインが再実行され、新しい設定が読み込まれます。

import {Transformer} from '@parcel/plugin';

export default new Transformer({
async loadConfig({config}) {
let {result, files} = await loadToolConfigSomehow(config.searchPath);

if (result) {
// Invalidate whenever one of the loaded files changes.
for (let file of files) {
config.invalidateOnFileChange(file);
}
} else {
// Invalidate when a new config is created.
config.invalidateOnFileCreate({
fileName: 'tool.config.json',
aboveFilePath: config.searchPath
});
}

return result;
}
});

開発依存関係

#

Parcelは、Parcelプラグイン自体のソースファイルと、そのすべての依存関係の変化を自動的に追跡します。プラグインのコードが変更された場合、キャッシュを無効にし、プラグインによって生成されたアセットを再構築する必要があります。

一部のプラグインは、他の依存関係を動的に読み込む場合があります。たとえば、トランスフォーマーには、ユーザーのプロジェクトで設定されている独自のプラグイン(例:Babel)がある場合があります。これらは自動的に追跡できず、`Config`オブジェクトに開発依存関係として追加する必要があります。これは`addDevDependency`メソッドを使用して行います。

import {Transformer} from '@parcel/plugin';

export default new Transformer({
async loadConfig({config}) {
let {result, filePath} = await loadToolConfigSomehow(config.searchPath);

for (let plugin of result.plugins) {
config.addDevDependency({
specifier: plugin,
resolveFrom: filePath
});
}

return result;
}
});

JavaScript設定

#

一部のツールは、JSON、YAML、またはTOMLなどの静的な設定言語ではなく、JavaScriptで記述された設定ファイルを使用します。残念ながら、これらのプログラムの設定ファイルは、非決定論的な結果を返す可能性があるため、Parcelでのキャッシングに問題を引き起こす可能性があります。

Parcelでこれに対処するための規則は、Parcelプロセスが再起動されたときに常に設定を無効にすることです。このようにして、JavaScriptの設定はすべてのビルドで無効になることはありません(これは遅すぎるでしょう)が、設定が非決定論的な場合、Parcelを再起動することで最新の状態が保証されます。

これは、`Config`オブジェクトの`invalidateOnStartup`メソッドを使用して行うことができます。

import {Transformer} from '@parcel/plugin';

export default new Transformer({
async loadConfig({config}) {
let {contents, filePath} = await config.getConfig([
'tool.config.json',
'tool.config.js'
]);

if (filePath.endsWith('.js')) {
config.invalidateOnStartup();
}

return contents;
}
});

利用可能なすべてのメソッドとプロパティの詳細については、ConfigオブジェクトのAPIドキュメントを参照してください。

ネーミング

#

すべてのプラグインは、ネーミングシステムに従う必要があります。

公式パッケージ コミュニティパッケージ 非公開企業/スコープ付きチームパッケージ
設定 @parcel/config-{name} parcel-config-{name} @scope/parcel-config[-{name}]
リゾルバー @parcel/resolver-{name} parcel-resolver-{name} @scope/parcel-resolver[-{name}]
トランスフォーマー @parcel/transformer-{name} parcel-transformer-{name} @scope/parcel-transformer[-{name}]
バンドラー @parcel/bundler-{name} parcel-bundler-{name} @scope/parcel-bundler[-{name}]
ネイマー @parcel/namer-{name} parcel-namer-{name} @scope/parcel-namer[-{name}]
ランタイム @parcel/runtime-{name} parcel-runtime-{name} @scope/parcel-runtime[-{name}]
パッケージャー @parcel/packager-{name} parcel-packager-{name} @scope/parcel-packager[-{name}]
オプティマイザー @parcel/optimizer-{name} parcel-optimizer-{name} @scope/parcel-optimizer[-{name}]
レポーター @parcel/reporter-{name} parcel-reporter-{name} @scope/parcel-reporter[-{name}]
バリデーター @parcel/validator-{name} parcel-validator-{name} @scope/parcel-validator[-{name}]

`{name}`は、パッケージの目的と直接関連する記述的なものでなければなりません。`.parcelrc`または`package.json#devDependencies`で名前を読むだけで、パッケージの機能を理解できる必要があります。

parcel-transformer-posthtml
parcel-packager-wasm
parcel-reporter-graph-visualizer

プラグインが特定のツールへのサポートを追加する場合は、ツールの名前を使用してください。

parcel-transformer-es6 (bad)
parcel-transformer-babel (good)

プラグインが既存のものの再実装である場合は、それがなぜ別個のものであるかを説明する名前を付けるようにしてください。

parcel-transformer-better-typescript (bad)
parcel-transformer-typescript-server (good)

コミュニティメンバーが協力し、フォークが発生した場合に解決することを求めます。誰かがあなたのプラグインのより良いバージョンを作成した場合、より良いパッケージ名を与えることを検討してください。メジャーバージョンを上げ、新しいツールに人をリダイレクトしてもらってください。

公開せずにプロジェクトでプラグインを使用するための推奨事項については、ローカルプラグインを参照してください。

バージョン管理

#

セマンティックバージョニングに従う必要があります(できる限り)。いいえ、完璧なシステムではありませんが、私たちが持っている中で最高のシステムであり、人々はそれに依存しています。

プラグイン作成者が意図的にセマンティックバージョニングに従わない場合、Parcelはユーザーにプラグインのバージョン番号を固定する必要があることを警告し始める場合があります。

エンジン

#

プラグインがサポートするParcelのバージョン範囲を使用して、`package.json#engines.parcel`フィールドを指定する必要があります。

{
"name": "parcel-transformer-imagemin",
"engines": {
"parcel": "2.x"
}
}

このフィールドを指定しないと、Parcelは警告を出力します。

Warning: The plugin "parcel-transformer-typescript" needs to specify a
`package.json#engines.parcel` field with the supported Parcel version range.

Parcelエンジンフィールドを指定し、ユーザーが互換性のないバージョンのParcelを使用している場合、エラーが表示されます。

Error: The plugin "parcel-transformer-typescript" is not compatible with the
current version of Parcel. Requires "2.x" but the current version is "3.1.4"

Parcelは、バージョン範囲を一致させるために`node-semver`を使用します。