Authoring Plugins
What to take in mind when authoring a plugin
ΒΆ Plugin APIs
There are several different types of plugins. They all look very similar, but are kept separate so we can have strict contracts one what each one is allowed to do.
There are some rules that should be followed across every type of plugin:
- Stateless β Avoid any kind of state, it will likely be the source of bugs for your users. For example, the same transform may exist in multiple separate workers which are not allowed to communicate with one another, state will not work as expected.
- Pure β Given the same input, a plugin must produce the same output, and you must not have any observable side effects, or implicit dependencies. Otherwise Parcel's caching will break and your users will be sad. You should never have to tell users to delete their caches.
The plugin APIs all follow a common shape:
import { NameOfPluginType } from "@parcel/plugin";
export default new NameOfPluginType({
async methodName(opts: JSONObject): Promise<JSONObject> {
return result;
},
});
They are made up of modules with well-known named exports of async functions that:
- Accept a strictly validated JSON-serializable
opts
object. - Return a strictly validated JSON-serializable
vals
object.
If something you need is not being passed through opts
, please come talk to
the Parcel team about it. Avoid trying to get information yourself from other
sources, especially from the file system.
ΒΆ Naming
All plugins must follow a naming system:
Official package | Community packages | Private company/scoped team packages | |
---|---|---|---|
Configs | @parcel/config-{name} |
parcel-config-{name} |
@scope/parcel-config[-{name}] |
Resolvers | @parcel/resolver-{name} |
parcel-resolver-{name} |
@scope/parcel-resolver[-{name}] |
Transformers | @parcel/transformer-{name} |
parcel-transformer-{name} |
@scope/parcel-transformer[-{name}] |
Bundlers | @parcel/bundler-{name} |
parcel-bundler-{name} |
@scope/parcel-bundler[-{name}] |
Namers | @parcel/namer-{name} |
parcel-namer-{name} |
@scope/parcel-namer[-{name}] |
Runtimes | @parcel/runtime-{name} |
parcel-runtime-{name} |
@scope/parcel-runtime[-{name}] |
Packagers | @parcel/packager-{name} |
parcel-packager-{name} |
@scope/parcel-packager[-{name}] |
Optimizers | @parcel/optimizer-{name} |
parcel-optimizer-{name} |
@scope/parcel-optimizer[-{name}] |
Reporters | @parcel/reporter-{name} |
parcel-reporter-{name} |
@scope/parcel-reporter[-{name}] |
Validators | @parcel/validator-{name} |
parcel-validator-{name} |
@scope/parcel-validator[-{name}] |
The {name}
must be descriptive and directly related to the purpose of the
package. Someone should be able to have an idea of what the package does simply
by reading the name in a .parcelrc
or package.json#devDependencies
.
parcel-transformer-posthtml
parcel-packager-wasm
parcel-reporter-graph-visualizer
If your plugin adds support for a specific tool, please use the name of the tool.
parcel-transformer-es6 (bad)
parcel-transformer-babel (good)
If your plugin is a reimplementation of something that exists, try naming it something that explains why it is a separate:
parcel-transformer-better-typescript (bad)
parcel-transformer-typescript-server (good)
We ask that community members work together and when forks happen to try and resolve them. If someone made a better version of your plugin, please consider giving the better package name over, have them make a major version bump, and redirect people to the new tool.
ΒΆ Versioning
You must follow semantic versioning (to the best of your ability). No, it's not the perfect system, but it's the best one we have and people do depend on it.
If plugin authors intentionally don't follow semantic versioning, Parcel may start warning users that they should be locking down the version number for your plugin.
ΒΆ Engines
You must specify a package.json#engines.parcel
field with the version range
of Parcel that your plugin supports:
{
"name": "parcel-transform-imagemin",
"engines": {
"parcel": "2.x"
}
}
If you do not specify this field, Parcel will output a warning:
Warning: The plugin "parcel-transform-typescript" needs to specify a
`package.json#engines.parcel` field with the supported Parcel version range.
If you do specify the parcel engine field and the user is using an incompatible version of Parcel, they will see an error:
Error: The plugin "parcel-transform-typescript" is not compatible with the
current version of Parcel. Requires "2.x" but the current version is "3.1.4"
Parcel uses node-semver
to match version ranges.