Skip to content

Documentation · ARDOR

Application ​

An ARDOR application pairs a BaseArdorApplication inversion-of-control container with an <ArdorApplication /> React root component that mounts react-admin. To start the application, extend BaseArdorApplication, call await application.start(), and pass the container to <ArdorApplication />.

Create src/application.ts:

ts
import 'reflect-metadata';

import AutoArtifacts from '@venizia/ignis-boot/auto';

import { BaseArdorApplication, type IApplicationInfo, type IArtifactIndex } from '@venizia/ardor';

// The decorated classes live in their own files and this module imports none of them: the build lists
// every one under src/ in `AutoArtifacts`, and importing it here keeps the list out of any shared kit.
export class Application extends BaseArdorApplication {
  getAppInfo(): IApplicationInfo {
    return { name: 'quickstart', version: '0.0.0', description: 'ARDOR 5-minute quickstart' };
  }

  override artifacts(): Array<IArtifactIndex> {
    return [AutoArtifacts];
  }

  bindContext(): void {}
}

Create src/main.tsx:

tsx
import 'reflect-metadata';

import { configureStore } from '@reduxjs/toolkit';
import { ArdorApplication } from '@venizia/ardor';
import { createRoot } from 'react-dom/client';
import { ListBase } from 'ra-core';

import { Application } from '@/application';
import { LoginPage } from '@/pages/login';
import { ProductList } from '@/pages/product-list';

const application = new Application();
const store = configureStore({
  reducer: { quickstart: (state: { ready: boolean } = { ready: true }) => state },
});

// `resource.list` is what react-admin renders for `/products`; `ListBase` runs the data provider.
const ProductsPage = () => (
  <ListBase resource="products" perPage={10}>
    <ProductList />
  </ListBase>
);

await application.start();

createRoot(document.getElementById('root')!).render(
  <ArdorApplication
    container={application}
    reduxStore={store}
    suspense={<p>Loading</p>}
    loginPage={LoginPage}
    resources={[{ name: 'products', list: ProductsPage }]}
  />,
);

NOTE

For the complete API contract and method signatures, see the Application Reference.

BaseArdorApplication ​

BaseArdorApplication (in packages/kernel/src/base/applications/abstract.ts) extends AbstractArdorApplication, which extends the IGNIS Container. The application instance is the container; call this.bind(...) and this.get(...) directly on it.

Subclasses implement two abstract methods:

  • getAppInfo(): Returns an IApplicationInfo object containing name, version, and description. preConfigure() binds this metadata under CoreBindings.APPLICATION_INFO. Return the object, or a promise of it: preConfigure() waits for a promise before it binds the rest.
  • bindContext(): Hook for registering container bindings by hand (such as this.service(), this.repository(), this.dataSource(), this.component(), or this.bind()). Bindings placed here override any binding declared by a configuration class or stereotype decorator.

The start() Lifecycle ​

The start() method in packages/kernel/src/base/applications/abstract.ts awaits three steps in order:

  1. resolveArtifactIndexes(): Evaluates this.artifacts(). Plain artifact indexes or pre-inlined groups (from IgnisArtifactsPlugin) are kept as-is. Dynamic groups with a resolve() function (such as AutoArtifacts from @venizia/ignis-boot/auto) have resolve() awaited to import modules and trigger decorators. Stored in this.resolvedIndexes for verification.
  2. preConfigure(): Directly binds CoreBindings.APPLICATION_INSTANCE, CoreBindings.APPLICATION_INFO, and CoreBindings.FEATURES. It runs stereotypes and @provide methods, features, bindingList(), and bindContext(). For details, see The bind order.
  3. postConfigure(): Runs after preConfigure() and bindContext() complete. Defaults to an empty function in BaseArdorApplication; override it for post-startup logic like cache warmups or runtime checks.

ArdorApplication on Render ​

ArdorApplication (in packages/admin/src/components/application.tsx) connects the IGNIS container to React. When rendered, it executes the following steps:

  1. Reads features: When the features prop is absent, calls Features.read({ container }) to retrieve features bound under CoreBindings.FEATURES. The prop replaces that read.
  2. Mounts resources and routes: Calls Features.mount({ features, resources, routes }) in packages/admin/src/features/feature.ts. Application resources and routes mount first, then each feature's in order. Duplicate resource names throw [features] Resource '<name>' is mounted by both ... | A resource name is unique within an application.
  3. Resolves default providers: Resolves framework providers from the container via container.get():
    • CoreBindings.DEFAULT_REST_DATA_PROVIDER: Required IDataProvider.
    • CoreBindings.DEFAULT_AUTH_PROVIDER: Optional IAuthProvider (isOptional: true). If unbound, ArdorApplication omits authProvider, running react-admin without sign-in so every page is public.
    • CoreBindings.DEFAULT_I18N_PROVIDER: Required I18nProvider.
  4. Verifies internationalization readiness: Calls useFeatureMessagesReady. If a feature supplies lazy translation loaders for the active locale, triggers i18nProvider.changeLocale() and renders the suspense fallback until ready.
  5. Wraps the component hierarchy:
    • ApplicationContext.Provider with { container, logger } (the logger prop, else a console logger named after the application).
    • ReduxProvider with reduxStore, only when the prop is passed.
    • React.Suspense with suspense.
  6. Renders CoreAdmin: Passes providers and forwarded props, mounting resources as <Resource key={resource.name} {...resource} /> and routes inside <CustomRoutes> as <Route key={route.id ?? route.path} {...route} />.

Application Props ​

ArdorApplication accepts IApplication props (in packages/admin/src/common/types.ts), extending CoreAdminProps (omitting children). Each prop, with its type and whether it is required, is in the Application reference.

Next Steps ​