Skip to content

Client Loader

Language: JavaScript

The loader.js at src/app-core/loader.js is the bootstrap and dependency-injection root of the client. It builds the Lib container, wires helper modules, and provides the single point where cross-cutting dependencies enter the React tree. The pattern mirrors the server loader: every framework module is a factory, Lib is built fresh on each call, and nothing outside the loader reads environment configuration.

On This Page


What the Loader Builds

The loader is a pure build function. It performs three tasks in order:

  1. Validate the adapter set - the gate checks that every host-supplied slot is present and is a function, before anything is built
  2. Build Lib - attach helper modules, theme engine, font manifest, SDK, React itself, and host adapters
  3. Return Lib and Config to the React tree via a context provider

After the loader returns, the rest of the client treats Lib as a read-only registry. No other file instantiates helper modules or reads configuration directly.

The loader is not memoized. The React context provider holds the only cache, memoizing on the adapter set reference. This lets a test build a second independent container by calling the loader with a different adapter set. A memoized composition root would prevent that.


The Lib Container

The Lib container holds every dependency the React tree needs. Each entry is either a helper module loaded via its factory or a plain data object.

Lib keyWhat it holdsHow it enters
Lib.ReactThe React moduleimport React from 'react' in the loader only
Lib.UtilsCore utility helperimport utils from '@superloomdev/js-helper-utils'; utils(Lib)
Lib.DebugDebug logging helperimport debug from '@superloomdev/js-helper-debug'; debug(Lib)
Lib.ThemerTheme engine (buildTheme, resolve, emit, cacheStats, clearCache, getContract, validateContract)import themer from '@superloomdev/js-client-helper-themer'; themer(Lib)
Lib.ThemerReactReact extension for themer (ThemeProvider, hooks)import themerReact from '@superloomdev/js-client-helper-themer-ext-react'; themerReact({ React, Themer, Utils, Debug })
Lib.ThemesReference theme profiles and brand layersimport { profile, brands } from '../themes/brand-layers.js'
Lib.ComponentsComponent system factoryimport { createSystem } from '@superloomdev/rnw-components'
Lib.FontFont core (family registry, role resolution)import font from '@superloomdev/js-client-helper-font'; font(Lib)
Lib.FontsFont manifest and useFontsReady hookimport fonts from '../fonts/fonts.js'; fonts(Lib)
Lib.FontAdapterPlatform font loader adapterSupplied by a host adapter
Lib.FontManifestHost-owned font asset sourcesSupplied by a host adapter
Lib.NavigationNavigation surface (Link, Redirect)Supplied by a host adapter
Lib.IconsIcon glyph componentSupplied by a host adapter
Lib.ThemeContextReact theming hub (ThemeProvider + hooks)import themeContext from './contexts/theme-context.js'; themeContext(Lib)
Lib.ClientClient utilities (os, device info)import client from './client.js'; client(Lib, Config)
Lib.SuperAppSuper-app launcher utilitiesimport superApp from './superApp.js'; superApp(Lib, Config)
Lib.SdkClient SDK (entity APIs)import sdk from '../../sdk.js'; sdk(Lib) or stub
Lib.ConfigApplication configuration objectDirect assignment in the loader

Every framework module follows the loader pattern: export default function (shared_libs, config) { ... }. The loader calls each factory with Lib, and the factory returns its public interface. This is identical to how server-side helper modules work.

Reference theme profiles are plain frozen data objects, not loaders. They are imported directly in the loader and attached to Lib.Themes. A profile is a named, versioned set of reference templates with identity (see Themes, templates, layers, profiles); it has no behavior and no dependencies. The loader also holds the brand layers and the system builder under src/themes/.


Adapters

Three slots are supplied by host adapters, not by published packages:

SlotPort definesAdapter returns
NavigationLink, Redirect{ Link, Redirect }
IconsGlyph{ Glyph }
Fontsadapter, manifest{ adapter, manifest }

Each build target has its own adapter directory. The Expo host supplies adapters under hosts/expo/adapters/; the web host supplies adapters under hosts/web/adapters/. The loader calls each adapter factory with Lib and assigns the return value to the container slot.

The adapter set is validated at boot before the container is built. A missing slot throws a TypeError naming every missing adapter. See Composition and Adapters for the full adapter doctrine, including the standard signature, the gate, and the test-tier pattern.


React Boundary Rule

Dependency injection applies at the package boundary, not inside the app's own React files. The rule:

  • Helper modules and framework packages receive dependencies through Lib. They never import React directly. The loader injects Lib.React into the themer adapter, for example
  • The app's own React files (screens, layouts, context providers) keep idiomatic import statements. JSX and hooks are import-time bindings; injecting React into every component adds ceremony without benefit

The boundary is the package edge. Inside the app, React is a peer dependency resolved normally. Outside the app (in published helper modules and the component library), React enters through Lib.

This keeps helper modules testable in isolation (inject a mock Lib.React) while keeping app code ergonomic.


Folder Conventions

Two folders organize React context and theme data inside src/app-core/:

FolderHoldsConvention
contexts/React context objects and hook definitionsLibContext (provides Lib), ThemeContext (provides theme + controller)
providers/Provider components, if they grow complex enough to separate from the context fileReserved. Simple providers stay in contexts/

Both folders use plural names, matching React community convention. A generic context/ folder is avoided because it could be confused with non-React context code.

Reference theme profiles and brand layers live in src/themes/ as frozen JS objects. The loader is the single source of truth for which profiles and brands are wired:

js
import { profile, brands } from '../themes/brand-layers.js';

Lib.Themes = {
  profile: profile,
  brands: brands
};

Font manifest lives in src/fonts/ as a loader module receiving Lib. The separation of theme data (names font roles) from font manifest (loads font files) is deliberate: bundler asset imports for .ttf files are bundler-bound, and a server-sent theme JSON cannot carry binaries. See Fonts.


Boot Chain

The entry chain from the host's entry file to first render:

text
hosts/expo/app/_layout.js            ← host entry file, imports host adapters
  |
  v  declares adapter set at module scope, mounts LibProvider
src/app-core/contexts/lib-context.js ← provides Lib via React context (memoized on adapters)
  |
  v  calls loader(adapters) - pure build function, no cache
src/app-core/loader.js               ← validates adapters, builds Lib + Config
  |
  v  mounts ThemeProvider
src/app-core/contexts/theme-context.js ← calls Lib.Themer, provides theme + controller
  |
  v  calls buildSystem()
src/themes/build-system.js           ← builds themed component system
  |
  v
src/components/index.js              ← re-exports screen from src/screens/

_layout.js is the boot file. The loader is the DI root. Everything else is wired through Lib. The chain is linear: each step depends only on what precedes it.

Every path in the diagram resolves on disk. The host entry file lives under hosts/[target]/app/; the shared source lives under src/app-core/.


Further Reading

  • Client Architecture - Stack decision, project layout, bundler-agnostic rule
  • Composition and Adapters - The four tiers, host adapters, the adapter gate, the test-tier pattern
  • Theming - The themer and runtime re-theming
  • Fonts - Font delivery mechanisms and the theme-names/host-loads contract
  • Server Loader - The server-side counterpart (same pattern, different dependencies)

Released under the MIT License.