If you want to support other JS dialects or CSS preprocessors, you can contribute an additional pipeline to the project. We recommend that you read the source for the faucet-pipeline-static project. It is the simplest of the existing pipelines, because it just copies file from one place to another.

Registering your pipeline

The faucet-pipeline project has a list of known pipelines that it automatically requires and initializes. When you write a new plugin it won’t be on that list. In this case, you need to configure faucet to load your plugin. In your faucet.config.js you put:

module.exports = {
  name: [{
    a: 1,
    b: 2

  plugins: {
    name: {
      plugin: path.resolve("./path/to/your/plugin"),
      bucket: "chosen-bucket"

With this configuration, your plugin with the name name will be loaded from the provided path when running faucet. You also need to choose one of our four “buckets”. It is a categorization of the pipelines that determines the order in which they will be run. You have the choice between the following buckets – the choice depends on the kind of files that your pipeline generates:

expect your main module to export a function with the following signature:

module.exports = function(pluginConfig, assetManager, options) {

The pluginConfig is whatever you write in the config file (in the example above this would be [{ a: 1, b: 2 }]). The convention is to expect an array of tasks. Each of them is an object with a source and a target plus any other things you need to configure. The assetManager will be described below in its own section. options is an object with the following keys:

This function should return a function that runs your pipeline. This function takes an optional argument:


The assetManager helps you to write files to disk. It will make sure that your file is fingerprinted (if the user asked for that) and that it will be added to the manifest (if the user asked for that). All you need to do is to provide the path where it should be written (without the fingerprint) and the content as a buffer:

assetManager.writeFile(targetPath, content);

As a third argument, it takes an optional object with the following keys:

The assetManager can also resolve paths for you. If your user provides a path in the configuration (for example the source and target), you can pass it to this function to receive the absolute path to that file. If the user provides a relative path, it will be relative to the configuration file. If they provide an absolute path, it will be sourced from the installed packages. If you want to disallow the second option, pass { enforceRelative: true } as the second argument to the function.

let source = assetManager.resolvePath(copyConfig.source);
let target = assetManager.resolvePath(copyConfig.target, {
    enforceRelative: true

You can also receive entries from the manifest like this:



browsers is the detected browserslist. It is an object with keys for each browserslist. Your plugin can ignore this when it doesn’t produce code that needs to be modified due to supported browsers.

If no browserslist was detected, the object will be empty. If one was detected, it contains at least the browserslist "default" which you should default to. You can allow users to ignore the browserslist for one of the bundles or choose another browserslist. The convention for the name of that options is browserslist. An example for an implementation could look like this:

let selectedBrowsers;
let { browserslist } = bundleConfig;
if(browserslist === false) {
    selectedBrowsers = null;
} else if(browserslist) {
    selectedBrowsers = browsers[browserslist];
} else {
    selectedBrowsers = browsers.defaults;