Skip to content

Progressive Loading

Progressive loading means shipping the minimum code needed for initial render, then loading additional services on demand. asimo’s bundle() makes this idiomatic.

The Pattern

Initial load (~3 KB + core)
User interacts
Feature bundle loaded on first access
Deferred services activate

Basic Code Splitting

Structure your application so that each feature lives in its own chunk:

// app.ts — entry point, only core services
import { createContainer, factory, bundle } from "@asimojs/asimo";
const app = createContainer({
name: "app",
services: [
// Eager: always needed
factory({ provide: CONFIG, load: () => loadConfig() }),
factory({ provide: LOGGER, load: () => createLogger() }),
// Lazy: loaded on first access
bundle({ provide: [ANALYTICS], load: () => import("./analytics-bundle") }),
bundle({ provide: [AUTH], load: () => import("./auth-bundle") }),
bundle({ provide: [DASHBOARD], load: () => import("./dashboard-bundle") }),
],
});

Each import() call creates a separate code-split chunk. Vite, webpack, and other bundlers handle this automatically.

Feature Bundle Structure

A bundle module exports an Container with services registered:

analytics-bundle.ts
import { createContainer, factory } from "@asimojs/asimo";
import { ANALYTICS, TRACKER } from "./types";
export default createContainer({
name: "analytics",
services: [
factory({
provide: ANALYTICS,
load: async () => {
const lib = await import("expensive-analytics-lib");
return new Analytics(lib.init());
},
}),
factory({
provide: TRACKER,
dependencies: [ANALYTICS],
load: (c) => new Tracker(c.get(ANALYTICS)),
}),
],
});

Skeleton + Progressive Hydration

Render a functional UI immediately, then progressively enhance as services load:

function App() {
return (
<Suspense fallback={<Skeleton />}>
<HydratedDashboard />
</Suspense>
);
}
function HydratedDashboard() {
// Triggers bundle load — shows skeleton until ready
const analytics = useService(ANALYTICS); // custom hook wrapping fetch()
return <Dashboard analytics={analytics} />;
}

The user sees the skeleton immediately. The analytics bundle loads in the background. When ready, the skeleton is replaced.

Route-Based Splitting

Load feature bundles based on routes:

router.ts
async function loadRoute(route: string) {
switch (route) {
case "/dashboard":
return app.fetch(DASHBOARD_SERVICE); // triggers dashboard bundle
case "/settings":
return app.fetch(SETTINGS_SERVICE); // triggers settings bundle
default:
return app.fetch(HOME_SERVICE);
}
}

Conditional Bundle Loading

Load heavy services only when needed:

async function trackEvent(event: Event) {
// Analytics bundle loads on first tracked event — not at startup
const analytics = await app.fetch(ANALYTICS);
analytics.track(event);
}
async function exportReport() {
// Report bundle loads only when user clicks "Export"
const reporter = await app.fetch(REPORT_EXPORTER);
return reporter.exportPDF();
}

Measuring Impact

Use config.onLoad to track when services activate:

const metrics: Array<{ ns: string; time: number }> = [];
const app = createContainer({
name: "app",
config: {
onLoad(iid) {
metrics.push({ ns: iid.ns, time: Date.now() });
},
},
services: [...],
});
// Later: analyze which services loaded, when, and their impact on TTI
console.table(metrics);

Bundle Dependencies

Bundles can depend on eagerly-loaded services to avoid circular import chains:

// Core: loaded at startup
factory({ provide: DB, load: () => createPool() })
factory({ provide: AUTH, load: () => createAuth() })
// Feature: loaded on demand, gets DB and AUTH from the parent
bundle({
provide: [DASHBOARD],
dependencies: [DB, AUTH],
load: async (c) => {
const db = c.get(DB);
const auth = c.get(AUTH);
return import("./dashboard").then(m => m.createContainer(db, auth));
},
});

Trade-offs

ApproachProsCons
Eager loadingAll services immediately availableLarger initial bundle, slower startup
Per-feature bundlesMinimal startup, code split by featureSmall delay on first feature access
Fine-grained bundlesSmallest chunks, most granular loadingMore HTTP requests, more bundle coordination