Bindings
The examples in this section build on what you learned in the "Config - Part 2" tutorial.
First, a soapbox about about side-effects
When the functional components of a system are allowed to reach outside their intended domain, and are allowed to implicitly affect other components, it can easily result in unintended and difficult to debug side-effects. To mitigate this problem, Targets isolates all configuration to namespaced domains of functionality and forces you to explicitly declare any interactions or interdependencies between these domains.
To be clear, the framework's limitations in this regard are not intended to disallow side-effects, but rather to ensure that proper functional boundaries are maintained within the workflows you author. It's all about surfacing the complexity of inter-related components—all cross-functional relationships become explicit and obvious.
As you'll learn below, Targets provides an elegant solution to support this philosopy.
Sometimes you want the result from one target to be fed to the input for another target. Targets supports this via a mechanism called bindings.
Consider the following:
If you're coding along with the tutorial, you'll need to add axios to your project for the above example code to work (
npm i axios
).
Let's run some example commands and use a binding on the targets we've implemented above...
...and another example...
Here you'll see that the result from one target was "bound" to the config of another target.
The right-side of the binding can use the special array notations you learned about in the previous section:
[+]
,[-]
,[<int>,<int>]
.
Aside from binding results, targets also allows you to bind config from one namespace to another. For example...
In this example the foo location config value will be copied over to weather.location.
This is particularly useful when you are creating composition targets. You'll learn about composition targets more later, but for now consider the following.
Given we have a config file which looks like this:
...let's say you have a docker namespace and a k8s namespace target which both want to use this top-level name property. Don't worry about how these targets are implemented—we'll keep this example conceptual.
For this scenario, you could write a composition target like so:
When you run your composition target (i.e. mycli deploy
), both the docker.build
and the k8s.deploy
targets will receive the top-level name
config property.
It's important to understand that bindings are actually just operations. Target has other built-in operations which you'll learn about later, as well as supporting custom operations which you can define yourself.
In the examples above, we used a binding shorthand. Bindings have a special short-hand syntax because they are one of the most common operations you'll use as you build your CLI tool.
Let's see review these examples again, but this time we'll use the long-form syntax.
The long-form bind syntax would look like this:
Now that you understand bindings, it's time to learn how to sequence and parallelize target execution, and you'll learn more about target composition.
Last updated