Base Additives
Some features are really a foundation that several variants build on: a shared layout, a set of common routes, a battery of models. WebFluid models that with base Additives — Additives that aren't meant to run on their own, but to be extended.
What makes an Additive a base
A base Additive is declared with "type": "base" and, because it is a
foundation rather than a finished feature, it may not declare a frontend. It is never
enabled directly in your app config either; instead, a regular (default) Additive picks it
up and extends it.
{
"id": "core",
"version": "1.0.0",
"type": "base",
"frontend": { "type": "none" },
"name": "Core"
}
A base looks like any other Additive otherwise — it has routers, templates and hooks. Here it contributes a shared route that every extending Additive will inherit:
from webfluid import Additive
additive = Additive(__name__)
@additive.before_enable
def before_enable(_):
from .app import about
additive.app.get("/about")(about)
Extending a base
A default Additive becomes a child of a base by passing it into the constructor. You don't
import the base package directly — you resolve it through
import_base, which finds the installed base by its id:
from webfluid import Additive
from webfluid.additives.core import import_base
additive = Additive(
__name__,
import_base("core")
)
@additive.before_enable
def before_enable(_):
from .app import index
additive.app.get("/")(index)
What extension actually does
When the child is enabled, the framework folds the base into it:
-
The base's
api,appandwsrouters are included into the child, so the/aboutroute above now answers under the child's prefix (e.g./portal/about). - The base's templates join the child's namespace, so the child can extend layouts and partials the base ships — under the child's id.
- The base's required extensions are merged into the child's requirements.
- The base inherits the child's url prefix and id, so reverse-url lookups line up.
Only the child is switched on in your app config. The base rides along with it. You never put a base id into the [additives] section — bases are loaded on demand when something extends them.
A given base can be extended by exactly one default Additive at a time. If two of your enabled Additives try to extend the same base, enabling will fail. Bases are foundations for a single feature, not a shared singleton service — reach for an extension if you need the latter.
Why bother
Base Additives shine for distribution. You can publish a polished foundation — an admin shell, an auth flow, a billing skeleton — and let each project extend it with its own routes and frontend without forking. That packaging story is exactly what the next chapter is about.
Continue reading
From here you can continue straight with Interaction between.