Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Framework Adapters

Architect provides adapters for React, Vue, Solid, and Svelte. Each adapter integrates the Application container with the framework’s component tree so any component can resolve services without prop-drilling.

React

npm install @artisansdk/architect react

With JSX (main.tsx):

import "reflect-metadata"
import React from "react"
import ReactDOM from "react-dom/client"
import { Application } from "@artisansdk/architect"
import { ContextProvider } from "@artisansdk/architect/react"
import App from "./App"

const app = Application.configure()
  .withProviders([new AppProvider()])

ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
  <React.StrictMode>
    <ContextProvider application={app}>
      <App />
    </ContextProvider>
  </React.StrictMode>
)

Without JSX (main.ts):

import "reflect-metadata"
import { createElement } from "react"
import { createRoot } from "react-dom/client"
import { Application } from "@artisansdk/architect"
import { ContextProvider } from "@artisansdk/architect/react"
import App from "./App"

const app = Application.configure()
  .withProviders([new AppProvider()])

const root = createRoot(document.getElementById("root")!)
root.render(
  createElement(ContextProvider, { application: app }, createElement(App))
)

Resolving services in components

import { useService } from "@artisansdk/architect/react"
import { UserService } from "./services/user"

function Profile() {
  const userService = useService(UserService)
  // ...
}

Reactive services

Bindings registered with container.reactive(...) (see Container) are automatically subscribed to — useService detects the "reactive" tag and wraps the result in Valtio’s useProxy, so the component re-renders on mutation with no extra code:

// provider
container.reactive(Menu, Menu)

// component — mutating menu re-renders this component, same call as any other service
const menu = useService(Menu)

Services registered with bind/singleton are returned as-is; use component state, signals, or another framework mechanism for those.

Error boundaries

ApplicationProvider/ContextProvider wrap your tree in an ErrorBoundary — pass errorFallback to render something in place of a crashed subtree. See Errors for how caught errors get dispatched onto the Events bus.

Using an existing container

If you already have a container (e.g. in tests or SSR), pass it directly:

<ContextProvider container={myContainer}>
  <App />
</ContextProvider>

Hooks

HookDescription
useService(Token)Resolve a binding from the Service Container
useContainer()Access the raw ContainerContract
useSignal(signal)Read a Signal’s current value and subscribe to changes

Vue

npm install @artisansdk/architect vue

ContextProvider renders its default slot, so it needs an explicit render function to receive children — mounting it directly as createApp(ContextProvider, props) leaves the slot empty and renders nothing:

import "reflect-metadata"
import { createApp, h } from "vue"
import { Application } from "@artisansdk/architect"
import { ContextProvider } from "@artisansdk/architect/vue"
import App from "./App.vue"

const application = Application.configure()
  .withProviders([new AppProvider()])

createApp({
  render: () => h(ContextProvider, { application }, () => h(App)),
}).mount("#root")

Resolving services in components

import { useService } from "@artisansdk/architect/vue"
import { UserService } from "./services/user"

const userService = useService(UserService)

Or inject the container directly:

import { inject } from "vue"
import { containerKey } from "@artisansdk/architect/vue"
import { UserService } from "./services/user"

const container = inject(containerKey)!
const userService = container.make(UserService)

Solid

npm install @artisansdk/architect solid-js
import "reflect-metadata"
import { render } from "solid-js/web"
import { Application } from "@artisansdk/architect"
import { ContextProvider } from "@artisansdk/architect/solid"

const application = Application.configure()
  .withProviders([new AppProvider()])

render(
  () => <ContextProvider application={application}><App /></ContextProvider>,
  document.getElementById("root")!
)

Svelte

npm install @artisansdk/architect svelte

Svelte has no ContextProvider component. Call application.run() yourself, pass the resulting container into your root component as a prop, and call provideContainer(...) inside it before any useService(...) calls:

// main.ts
import "reflect-metadata"
import { Application } from "@artisansdk/architect"
import App from "./App.svelte"

const application = Application.configure()
  .withProviders([new AppProvider()])

const running = application.run()

new App({
  target: document.getElementById("root")!,
  props: { container: running.container },
})

window.addEventListener("beforeunload", running.stop, { once: true })
<!-- App.svelte -->
<script lang="ts">
  import { provideContainer, useService } from "@artisansdk/architect/svelte"
  import { UserService } from "./services/user"

  export let container: unknown

  provideContainer(container as never)
  const userService = useService(UserService)
</script>