Date: 2019
Netlify Build Plugins are a layer on top of Netlify's CI pipeline that adds a pluggable programmatic interface for users to extend to fit any use case.
Users of Netlify's build system, including myself, have the following questions:
At Netlify, we are striving to answer these questions & provide a superior developer experience around the solutions we bring to the market. Netlify build plugins are no exception and a core component of the overall product experience we provide to our users.
Let's explore these key questions in our customer's minds & see how build plugins can be used to address these critical areas.
Making builds faster is top of mind.
Using a smart build plugin, you could avoid expensive time-consuming build processes such as optimizing the same images every build, avoiding long-running builds if relevant files haven't changed, or running incremental builds.
Some plugin examples:
As we begin to package & charge for build minutes, the cost is at the forefront of the developer's consideration when choosing a platform.
Any tools we can provide to allow users to glean insights on usage & optimize costs are going to be a big win for transparency and the overall developer experience.
Cost optimization examples are very similar to the How can I make things faster?
section.
Some plugin examples:
Setting up new projects & build tools is no easy feat. The amount of complexity that comes with setting up a production build environment is non-trivial & typically replicated over and over again for projects.
How can we streamline this flow & make it easy for companies to standardize their projects & CI flows without recreating the wheel each time?
How can we scale processes across a growing organization?
Build plugins are one way.
By design, build plugins are meant to be shared. This means a couple of things.
First, we can begin abstracting common build tasks up the stack out of specific static site generator tools. This allows for plugins to be used in any type of project regardless of the frontend framework or static site generator used.
Second, because these are dependencies that can be shared across projects from a centralized location, this allows organizations to begin standardizing their deployment flows.
Benefits that fall out of standardizing these flows include:
Some plugin examples:
Whether a bug in the code, an issue with an older browser, a missing dependency in a serverless function, or performance degradation, shipping regressions is never a good time.
How can we improve & help users ensure the quality of their projects to guard against these regressions?
Some plugin examples:
Compliance is often overlooked at the offset of smaller projects but becomes increasingly important as a company matures until it becomes non-negotiable in larger enterprises.
How can we provide our larger enterprise customers the security features they need to fall within compliance standards?
Some plugin examples:
Additional plugin use cases and examples can be found here
Below is the original spec of build plugins.
Plugins are a way for users to extend the functionality of the Netlify Platform.
Plugins have the ability to:
Plugins can listen to core lifecycle events that happen during different Netlify activities, for example during the build, while Netlify dev is running, or during a Netlify deployment.
The lifecycle is extendable; plugins can define their own lifecycle events that other plugins and listen to and react to. For example, the mongoDb
plugin can expose an afterDatabaseCreated
hook that other plugins can run functionality from.
All plugin logs should flow through a structured logging system.
Every console.log/warn/etc. should be grouped for the UI + plugins to consume.
Logging should be as secure as possible without sacrificing performance. This means automatically redacting known env
variables from plugins trying to console.log them out. Plugins installed should be vetted by users to ensure they are not installing malware.
Plugins can return outputs that other plugins may leverage.
This means a mongoDB provisioning plugin might pass a connection string back as an output that a "mongo crud function" plugin can reference
This means the order is essential in how plugins are defined in the configuration, and a dependency graph of outputs is required to ensure things run in the correct order.
The manifest is the aggregated list of all outputs returned from the build.
This includes things like liveSiteUrl
, deployId, plugin outputs, function names, function URLs, etc.
This manifest file is written to .netlify/manifest.json
Plugins can expose additional commands to the Netlify CLI.
For example the mongoDb
plugin could expose a netlify mongo:delete
command that tears down the given resource.
Below is the original plugin API design.
pluginApi
input.netlify.yml
Example build plugin:
module.exports = function myBuildPlugin(pluginConfig) {
return {
onInit: (pluginApi) => { /* do stuff on onInit */ },
onPreBuild: (pluginApi) => { /* do stuff on onPreBuild */ },
onPostBuild: (pluginApi) => { /* do stuff on onPostBuild*/ },
onPostDeploy: (pluginApi) => { /* do stuff on onPostDeploy */ },
onSuccess: (pluginApi) => { /* do stuff on onSuccess */ },
onError: (pluginApi) => { /* do stuff on onError*/ },
}
}
The pluginApi
definition is listed below
module.exports = function myBuildPlugin(pluginConfig) {
return {
/**
* Plugin API
* @param {object} netlifyConfig - Resolved value of Netlify configuration file
* @param {object} pluginConfig - Initial plugin configuration
* @param {object} utils - set of utility functions for working with Netlify
* @param {object} utils.cache - Helper functions for dealing with build cache
* @param {object} utils.git - Helper functions for dealing with git
* @param {object} utils.run - Helper functions for dealing with executables
* @param {object} utils.functions - Helper functions for dealing with Netlify functions
* @param {object} utils.redirects - Helper functions for dealing with Netlify redirects
* @param {object} utils.headers - Helper functions for dealing with Netlify headers
* @param {object} constants - constant values referencing various env paths
* @param {string} constants.CONFIG_PATH - path to netlify config file
* @param {string} constants.BUILD_DIR - path to site build directory
* @param {string} constants.CACHE_DIR - path to cache directory
* @param {string} constants.FUNCTIONS_SRC - path to functions source code directory
* @param {string} constants.FUNCTIONS_DIST - path to functions build directory
* @param {object} api - scoped API instance of Netlify sdk
* @return {object} outputs - output values from call
*/
onPreBuild: ({ netlifyConfig, pluginConfig, utils, constants, api }) => {
// do the thing
},
}
}
Attaching a plugin to your build would be done in netlify.yml
# Build settings
build:
functions: functions
publish: build
# Inline lifecycle hooks
lifecycle:
onInit:
- echo "starting the build"
onPostBuild:
- echo "build complete the build"
# Build plugins
plugins:
pluginOne:
# Local plugin definition
package: ./plugins/one
# plugin inputs
inputs:
foo: bar
sitemapPlugin:
# Remote plugin from NPM
package: netlify-sitemap-plugin
The events that build plugins can hook into are as follows
Event | Description |
---|---|
onInit | Runs before anything else |
onPreBuild | Before build commands are executed |
onBuild | Build commands are executed |
onPostBuild | After Build commands are executed |
onSuccess | Runs on build success |
onError | Runs on build error |
onEnd | Runs on build error or success |
Read the full input/output spec here
Plugin outputs are a way for values to be passed between plugins.
These outputs will allow for more advances use cases of plugins that depend on values from each other.
For example, a mongodb-atlas-plugin
might pass a connection string back as an output that a custom-rest-api-function-plugin might use to automatically scaffold a serverless function with said connection string.
To achieve a feature like this, Netlify Build requires additional configuration from the plugin author so outputs and build order can be correctly executed.