App & Module
A Module is a scoped set of providers with a lifecycle. An App is the root module - the only one you construct yourself. The semantics are on Modules; this page is the API surface.
Signature
class Module {
readonly id: string
readonly parent: Module | null
readonly resolver: Resolver
readonly traversal: ModuleTraversal
get children(): ReadonlySet<Module>
get status(): ModuleStatus
init(): void
mount(): void
unmount(): void
destroy(): Promise<void>
}
class App extends Module {
constructor(params?: ModuleParams)
}The four phase methods are called by AppProvider and ModuleProvider, not by you.
new App(params?)
App is the only module with a public constructor you use. Scoped modules are built for you by ModuleProvider and createModuleComponent, under the module already in context.
ModuleParams is the whole argument, and every key is optional:
| Key | Type | What it is |
|---|---|---|
id | string | The module's name in traversal lookups and error messages. Defaults to a generated id:<n>. |
providers | readonly ProviderInput[] | Providers and features this module owns. |
onModuleInit | (resolver: Resolver) => unknown | Runs when the module is armed. |
onModuleMount | (resolver: Resolver) => unknown | Runs when the module mounts. |
onModuleUnmount | (resolver: Resolver) => unknown | Runs when the module unmounts. |
onModuleDestroy | (resolver: Resolver) => unknown | Runs when the module is destroyed. |
import { App, AppProvider } from "@remodulo/react"
export const app = new App({
providers: [OrdersApi],
onModuleInit: (resolver) => resolver.resolve(OrdersApi).warmUp(),
})
export function Root() {
return (
<AppProvider app={app}>
<OrdersPage />
</AppProvider>
)
}app is constructed before React renders, so OrdersApi is registered by the time AppProvider arms it. Each hook receives the module's own resolver - there is no other argument.
Public surface
Everything below is readable on any module, App included:
| Member | Type | What it is |
|---|---|---|
id | string | The id you passed, or the generated one. |
resolver | Resolver | This module's resolver. The same object useResolver returns. |
traversal | ModuleTraversal | The tree around this module. |
parent | Module | null | The module this one forked from. null on an App. |
children | ReadonlySet<Module> | Direct children that have mounted, in attach order. |
status | ModuleStatus | See below. |
What is not on a module: container, lifecycle, addChild and removeChild are internal and stripped from the published types. Reads go through resolver; the tree goes through traversal.
status
The eight ModuleStatus values - created, initializing, initialized, mounted, unmounted, destroying, destroyed, failed - exist and you can read them, but reading them is diagnostics, not a lifecycle API: drive work from the module hooks, not from a status check.
An App is a Module; a Module is not an App
App carries a private type-only brand, so the subtyping runs one way in TypeScript too. A Module is not assignable to App, and AppProvider's app prop accepts only something built with new App(...). The brand is declared and emits no runtime field.