Lazy Loading

As your application grows and you add more pages, the amount of JavaScript your application needs to download grows as well. Downloading the entire application at once—even the pages a user might never visit—can make your initial load time very slow.

Lazy Loading solves this by splitting your code into smaller separate files, and only downloading those files when the user actually navigates to that specific page.

Basic Lazy Loading

In Retend, you can easily lazy-load a route's component using the lazy() function. You just wrap a dynamic import() statement around the path to your component file.

import { defineRoutes, lazy } from 'retend/router';

// This component is included in the main initial download
const Home = () => <div>Home</div>;

// This component is separated into its own file and downloaded only when needed
const SettingsLazy = lazy(() => import('./views/Settings'));

const routes = defineRoutes([
  { path: '/', component: Home },
  { path: '/settings', component: SettingsLazy },
]);

Exporting your Component

The lazy() function specifically expects the component to be the default export of that file.

// views/Settings.tsx

// You can still use local helper components
function SettingsForm() {
  return <form>...</form>;
}

// But the component you want to lazy-load MUST be the `default` export
export default function SettingsView() {
  return (
    <div class="settings">
      <h1>Account Settings</h1>
      <SettingsForm />
    </div>
  );
}

Lazy Loading Nested Routes

Lazy loading works exactly the same way with nested routes. You can lazily load the parent layout, the child pages, or both!

import { defineRoutes, lazy, Outlet } from 'retend/router';

const DashboardLayout = () => (
  <div>
    <h1>Dashboard</h1>
    <Outlet />
  </div>
);

// The child page is lazy-loaded
const UserProfileLazy = lazy(() => import('./views/dashboard/UserProfile'));

const routes = defineRoutes([
  {
    path: '/dashboard',
    component: DashboardLayout,
    children: [{ path: 'profile', component: UserProfileLazy }],
  },
]);

Lazy Subtrees (Advanced)

If you are building a massive application with hundreds of routes, even the file containing all your routes can become too large to download at once.

Lazy Subtrees let you split up your routing configuration itself, so entire sections of your app's routes are only downloaded when the user enters that section.

Step 1: Create the Subtree File

Create a separate file that exports a single route configuration as its default export:

// finance.routes.ts
import { defineRoute, lazy } from 'retend/router';
import FinanceDashboard from './views/FinanceDashboard';

// The path MUST match where it will be mounted in the parent router
export default defineRoute({
  path: '/finance/:accountId',
  component: FinanceDashboard,
  children: [
    {
      path: 'reports',
      component: lazy(() => import('./views/Reports')),
    },
    {
      path: 'invoices',
      component: lazy(() => import('./views/Invoices')),
    },
  ],
});

Step 2: Connect it to the Main Router

In your main route file, use the subtree property instead of component or children, and wrap the import in lazy() just like before:

// index.routes.ts
import { defineRoutes, lazy } from 'retend/router';

const routes = defineRoutes([
  { path: '/', component: Home },
  {
    path: '/finance/:accountId',
    // The entire finance section (routes and components) loads on demand
    subtree: lazy(() => import('./finance.routes.ts')),
  },
]);

Lazy loading is the best way to ensure your application stays blazing fast, no matter how large it gets.