What You Can Do with Netlify Build Plugins

Netlify Build is coming! It is in private beta now, and will go into public beta soon (and you can try it out as part of the RedwoodJS tutorial).

There are a number of new capabilities Netlify Build will enable, but probably the one you'll hear about most is the new plugin system. Chris Coyier, of course, already got the scoop on this when it was announced at JAMstack Conf, Sarah Drasner has written about creating your first Netlify Build Plugin (note: APIs have changed) and I've recently written about how to write quality plugins with Unit and Integration testing.

I've spent the past couple months dabbling with Build Plugins, and I thought I should share what I've worked on, thought about, and seen done by others.

⚠️ Note: That Beta label is Beta for a reason - Netlify reserves the right to change these APIs as it observes real usage. So we will focus on general principles over specific APIs.

Capabilities

What you can do as part of plugins is circumscribed by A) what the build system does and B) exposes to you, the plugin author/user. So we should understand both.

What A Build Does

I'll adapt from the excellent docs:

  1. Netlify clones your repo
  2. If not cached, dependencies are installed in the project. If the cache is still valid (based on a manifest like package.json), it simply restores the cache
  3. Netlify runs your build command
  4. Files & dependencies are cached
  5. Netlify runs proprietary post processing, including detecting Forms, Functions, and Redirects
  6. Functions are deployed, if detected
  7. Your site is deployed

I'm omitting a lot. For Netlify to be as low-config as it is, and still support every ecosystem from PHP to Dotnet Core, there is a ton to get right. For the Docker-literate, you can see the exact, nonsimplified steps of Netlify's Build Image (aka Buildbot) in its Dockerfile. I'd recommend Brian Holt's Intro to Docker for those who aren't.

Previously, the only user-configurable section was Step 3, the build command. If you wanted to, for example, do stuff between steps 1 and 2, or steps 3 and 5, you'd have to write scripts in a variety of places, like npm scripts, or a Webpack plugin, or a site generator specific lifecycle. And what if you needed to pass information between steps? Fuhgeddaboudit!

What Netlify Build Exposes

With Netlify Build, the potential to programmatically control steps 1 - 7 and more is there (but has not yet been promised so don't hold them to it). For now, Netlify Build exposes a subset of that functionality (note, I expect this list to change over time):

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

So you don't have access to everything, but you have more than you had with a simple build command.

Plugin Categories

If I were to map a build system like this to tools I'm already familiar with, it'd be a combination of CI/CD tool (like, say, Jenkins or GitHub Actions) and static site generator/bundler lifecycles (which somehow superceded old school task runners). So you'd expect the possible plugins to be a superset of that.

Note: these are by no means formal categories endorsed by Netlify, this is just me randomly coming up with classifications. Don't let this limit your thinking.

Notifiers

The lightest weight plugins (that would, for example, have the least amount of config and the lowest impact on workflow and build times) are ones that simply dispatch information about the build after a build is done.

Most notifications can be enhanced with some progressive sense of history - so if you make it easy to access the cache, you can, for example, warn or block on regressions in performance, as I did in this unpublished Lighthouse plugin.

Cache/Asset Optimization

Faster builds, and faster sites.

Deploy Blockers

You could, abstractly, block a deploy if some precondition were not met. This could be viewed as similar to CI, except that this could happen after integration, and can block deploys instead of just builds, on a wider set of conditions. It is common to throw new Error to block a build, but this bears no distinction from real errors which you should pay attention to - therefore, Netlify offers some utils like failBuild, failPlugin, and cancelBuild to indicate whether something is wrong or working as intended.

Generate Source Files

Sometimes part of your content lives elsewhere other than git. Netlify Build can pull it down for you before you run your build.

Generate Build Artefacts

Before deploying, you can statically analyze your build, and then build atop your build! This is most often used to create static build artefacts, but because Netlify has an integrated serverless solution, you can generate that too. (My hope is that all first party products are up for programmatic provisioning in future)

Weird Combos

What you can do is really limited by your imagination. (Cue cliché: "We can't wait to see what you come up with!") Here's a weird one of mine that actually came up due to real life needs - netlify-plugin-encrypted-files. It helps you partially obscure files (names and contents) in git repos, so that you can partially open source your site, while still being able to work as normal on your local machine and in your Netlify builds.

BYOP

You don't have to use plugins others write, either. Since Netlify Build allows local plugins, creating local forks and adjustments is mostly a copy-and-paste job (as is the reverse workflow of develop-locally-then-publish-separately - this is how I do local testing for netlify-plugin-rss).

Conclusion

It's still early days yet but I hope to have spelled out a little of how I personally place a plugin system in context of something like Netlify.

Every platform eventually aspires to have plugins - a very challenging tradeoff because it makes users' lives easier and helps third parties integrate/become more discoverable, and yet the security and maintenance concerns are high. You can't just ban or artificially constrain Remote Code Execution, especially if your whole job is to run other people's code. (If you run other people's code on other people's browsers, you should read Figma's writeup How to build a plugin system on the web and also sleep well at night).

But also, every pluginized platform eventually figures out that it, itself, can be composed of a bunch of plugins too. This was webpack's realization, and it is comparable to the Lean Core idea from React Native. It turns out that forcing yourself to be a first class consumer of your own plugins makes both the plugins and your system more maintainable and reliable, just like how it is a good idea to only consume internal services through public APIs.

There's a ton more things to think about, which is what makes this an exciting engineering challenge. Should plugins have plugins? Will you allow point-and-click configuration through UI? How does that translate to a local dev setup? How can you expose more core capability without overwhelm?

It will be exciting to watch Netlify's plugin ecosystem come to life. You can learn more on the Netlify Build Repo.


Webmentions

Failed to load...