- architecture: introduction, Go modules and workspaces, application lifecycle, request lifecycle - plugins: registration, scheduling, extending, testing - verified Examples for backpack services, towel request context, pact schedules and festival events - TestDocsRequiredPages lists the eight new pages
backpack
Per-instance application container that holds the configuration, a typed service registry, the event bus and the set of activated plugins.
import "git.golem15.com/golem15/summercms/modules/backpack"
Overview
backpack plays the role of the Laravel service container that WinterCMS plugins reach through App::make and singleton bindings, without any process-global state: every backpack.App is independent, so tests and multiple instances in one process do not interfere. The generated main of an application loads configuration with compass, creates the container with backpack.New, and hands it to party, which passes it to every plugin's Register and Boot. backpack deliberately does not import party, which keeps the dependency graph acyclic.
Features
backpack.Newwires a container around a loaded*compass.Config:backpack.App.Config, a fresh service registry inbackpack.App.Servicesand a new festival bus inbackpack.App.Events.- Typed services keyed by the type argument:
backpack.App.Publishstores a value under its type T andbackpack.App.Lookupreturns it. Publishing the same T twice or publishing nil is an error, so two plugins cannot silently replace each other's service. Framework modules share their infrastructure this way (for example the database handles published by lagoon, or the translator from phrasebook). - Plugin presence checks:
backpack.App.SetPluginsrecords the complete activated set before any plugin boots, andbackpack.App.HasPluginanswers whether an optional integration partner is part of this build (the equivalent of WinterCMS'sPluginManager::exists). backpack.Registrycan be used on its own throughbackpack.NewRegistry; it is safe for concurrent use.- Nil-safe methods: calls on a nil container or registry return an error or a zero value instead of panicking.
Usage
package blog
import (
"git.golem15.com/golem15/summercms/modules/backpack"
"git.golem15.com/golem15/summercms/modules/compass"
)
// Feed is a service the blog plugin offers to other plugins.
type Feed interface {
Latest(n int) []string
}
type staticFeed struct{}
func (staticFeed) Latest(n int) []string { return []string{"hello-world"} }
func setup() error {
cfg, err := compass.Load("config")
if err != nil {
return err
}
app := backpack.New(cfg)
app.SetPlugins([]string{"acme.blog", "acme.search"})
// Provider side, usually in the plugin's Register step.
var feed Feed = staticFeed{}
if err := app.Publish(feed); err != nil { // published under Feed, not staticFeed
return err
}
// Consumer side, usually in another plugin's Boot step.
if app.HasPlugin("acme.blog") {
if found, ok := app.Lookup[Feed](); ok {
_ = found.Latest(5)
}
}
return nil
}
Publish under an interface type when consumers should not depend on the concrete implementation; the lookup must use exactly the same type argument.
API reference
| Identifier | Description |
|---|---|
backpack.App |
The application container: configuration, service registry, event bus and the activated plugin set. |
backpack.New |
Creates a backpack.App around a loaded configuration, with an empty registry and a new event bus. |
backpack.App.Publish / backpack.App.Lookup |
Store and retrieve an app-scoped service by type. |
backpack.App.SetPlugins / backpack.App.HasPlugin |
Record the activated plugin IDs and check whether one is present. |
backpack.Registry |
Concurrency-safe typed service catalog behind backpack.App.Services. |
backpack.NewRegistry |
Returns an empty registry. |
backpack.Registry.Publish / backpack.Registry.Lookup |
Registry-level publish and lookup behind the backpack.App methods. |
Dependencies
Testing
go test ./modules/backpack/...
The tests build containers in memory and need no external services.