Deploying React AppsEntry 3 of 11
Lazy Loading Route Loaders with import()
When a lazy page also exports a loader, the route's loader must load that module with import() too, then call the loader from it.
Notes
- Importing
loaderstatically from the page file would pull the whole page into the main bundle, undoing the lazy loading. - Instead, the route's
loaderis a function that dynamically imports the module and calls itsloader. - Pass the loader arguments through (
{ params, request }) so dynamic routes still get their params. - The browser caches the module, so the loader and the lazy component share one download.
What / Why / When
- What
Deferred loader code.
- Why
Keeps the page and its data logic out of the main bundle.
- When
Any lazy-loaded page that has a loader or action.
Code compare
// App.tsximport { lazy } from "react";import type { LoaderFunctionArgs } from "react-router";const BlogPage = lazy(() => import("./pages/Blog"));const PostPage = lazy(() => import("./pages/Post"));const router = createBrowserRouter([ { path: "/", element: <RootLayout />, children: [ { index: true, element: <HomePage /> }, { path: "posts", children: [ { index: true, element: <BlogPage />, // wrapped in Suspense in Entry 4 loader: () => import("./pages/Blog").then((module) => module.loader()), }, { path: ":id", element: <PostPage />, loader: (args: LoaderFunctionArgs) => import("./pages/Post").then((module) => module.loader(args)), }, ], }, ], },]);Resolvers live in the route config, so put them in a lazy routes file. They're then downloaded with the feature.
// app.routes.ts{ path: 'posts', loadChildren: () => import('./posts/posts.routes').then((m) => m.POSTS_ROUTES) }// posts/posts.routes.ts (separate chunk, including resolvers)export const POSTS_ROUTES: Routes = [ { path: "", component: BlogComponent, resolve: { posts: postsResolver } }, { path: ":id", component: PostComponent, resolve: { post: postResolver } },];Quick reference
| React | Angular |
|---|---|
loader: () => import('./Page').then(m => m.loader()) | Resolver inside a loadChildren routes file |
loader: (args) => import(...).then(m => m.loader(args)) | ResolveFn receives route automatically |