Reducing Initial Load with Framework7 Lazy-Loaded Routing
Learn how to implement lazy-loaded routing in Framework7 to reduce initial bundle size and improve time-to-interactive for mobile web applications.
04 Sept 2026, 17:43 UTC

The Initial Bundle Bloat Problem
As a mobile web application grows, the JavaScript bundle often expands linearly with every new page added. For users on low-end devices or unstable 3G connections, this results in a long "white screen" period where the browser downloads and parses code for pages the user may never actually visit. The goal is to move from a monolithic bundle to a system where code is fetched on-demand.
The solution is lazy loading: a technique that splits your application into smaller chunks, loading the specific JavaScript required for a route only when the user navigates to it. In Framework7, this is achieved by combining the framework's router with the dynamic import() syntax supported by modern bundlers like Webpack or Rollup.
Implementing Dynamic Route Imports
To implement lazy loading, you must replace static page imports with functions that return a promise. Instead of importing a component at the top of your file, you define the component property of your route as a function.
When the router hits a lazy-loaded route, it triggers the dynamic import. The bundler recognizes this syntax and automatically creates a separate .js chunk for that specific page during the build process.
Worked Example: Lazy Route Configuration
Assuming a project using a modern bundler (Webpack/Vite/Rollup) and Framework7 v6+, here is how to configure a lazy-loaded route:
// routes.js
export const routes = [
{
path: '/',
component: () => import('./pages/home.f7'), // Lazy loaded
},
{
path: '/settings/',
component: () => import('./pages/settings.f7'), // Lazy loaded
},
{
path: '/profile/',
component: () => import('./pages/profile.f7'), // Lazy loaded
}
];
Execution Context: This configuration is defined in your routes file and passed to the Framework7 instance initialization. No special permissions are required beyond standard file system access for the bundler to create the chunks.
Handling the "Loading Gap"
On high-latency networks, there is a measurable gap between the user clicking a link and the JavaScript chunk arriving. Without a strategy, this looks like a frozen UI or a blank screen, which breaks the "native app" feel Framework7 aims to provide.
To solve this, use a placeholder or a global preloader. Framework7 allows you to define a loading state that persists until the component promise resolves. By integrating a skeleton UI or a spinner, you signal to the user that the app is responding, even if the network is slow.
Trade-offs and Limitations
Lazy loading is not a silver bullet. It introduces a trade-off between Initial Load Time and Navigation Latency.
- Initial Load: Decreases significantly because the entry bundle is smaller.
- Navigation: Increases slightly for the first visit to a page, as the browser must make an HTTP request for the chunk.
A critical limitation is bundler configuration. If your bundler is not configured for code splitting (e.g., using a simple bundle script without a module system), the import() call may be transpiled into a standard require, pulling everything back into a single file and negating the performance gain.
Verifying the Implementation
To ensure lazy loading is actually working and not just simulating it, perform these three checks:
- Build Inspection: Run your production build command. Check the
/distfolder; you should see multiple small.jsfiles (chunks) rather than one massiveapp.js. - Network Monitoring: Open the Browser DevTools Network tab. Refresh the home page. Navigate to the "Settings" page. You should see a new
.jsfile being requested only after the navigation event occurs. - Throttling Test: Set the Network tab to "Fast 3G" or "Slow 3G". Navigate between pages to verify that your loading indicators appear and that the app doesn't crash during the fetch.
Rollback Procedure
If lazy loading causes critical navigation errors (such as ChunkLoadError due to aggressive caching or CDN issues), revert to static imports:
// Change this:
component: () => import('./pages/home.f7')
// To this:
import Home from './pages/home.f7';
// ... inside routes array:
component: Home0 replies
A thoughtful contribution can make all the difference. Be the first to share one.