Merge pull request 'docs(authoring/modules): add examples for dependency injection' (#3249) from hsjobeki/clan-core:docs-authoring into main

Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3249
This commit is contained in:
hsjobeki
2025-04-08 21:10:52 +00:00

View File

@@ -184,3 +184,81 @@ The following example shows how to create a local instance of machine specific s
If calling extendSettings is done that doesn't change the original `settings` this means if a different machine tries to access i.e `roles.client.settings` it would *NOT* contain your changes.
Exposing the changed settings to other machines would come with a huge performance penalty, thats why we don't want to offer it.
## Passing `self` or `pkgs` to the module
Passing any dependencies in general must be done manually.
In general we found the following two best practices:
1. Using `lib.importApply`
2. Using a wrapper module
Both have pros and cons. After all using `importApply` is the easier one, but might be more limiting sometimes.
### Using `importApply`
Using [importApply](https://github.com/NixOS/nixpkgs/pull/230588) is essentially the same as `import file` followed by a function-application; but preserves the error location.
Imagine your module looks like this
```nix title="messaging.nix"
{ self }:
{ ... }: # This line is optional
{
_class = "clan.service";
manifest.name = "messaging"
# ...
}
```
To import the module use `importApply`
```nix title=flake.nix
# ...
outputs = inputs: flake-parts.lib.mkFlake { inherit inputs; } ({self, lib, ...}: {
imports = [ inputs.clan-core.flakeModules.default ];
# ...
clan = {
# Register the module
inventory.modules."@hsjobeki/messaging" = lib.importApply ./service-modules/messaging.nix { inherit self; };
# Expose the module for downstream users, 'self' would always point to this flake.
modules."@hsjobeki/messaging" = lib.importApply ./service-modules/messaging.nix { inherit self; };
};
})
```
### Using a wrapper module
```nix title="messaging.nix"
{ config, ... }:
{
_class = "clan.service";
manifest.name = "messaging"
# ...
# config.myClan
}
```
Then wrap the module and forward the variable `self` from the outer context into the module
```nix title=flake.nix
# ...
outputs = inputs: flake-parts.lib.mkFlake { inherit inputs; } ({self, lib, ...}: {
imports = [ inputs.clan-core.flakeModules.default ];
# ...
clan = {
# Register the module
inventory.modules."@hsjobeki/messaging" = {
# Create an option 'myClan' and assign it to 'self'
options.myClan = lib.mkOption {
default = self;
};
imports = [./service-modules/messaging.nix ];
}
};
})
```
The benefit of this approach is that downstream users can override the value of `myClan` by using `mkForce` or other priority modifiers.