Lazy-Loaded Routes in Framework7: Faster Startup Without Rewriting Your App
Framework7's router supports lazy-loaded routes via dynamic imports, cutting initial bundle size and startup time. Here's the pattern, a Vue example, and the first-navigation trade-off to plan for.
10 Mar 2026, 12:26 UTC

If your Framework7 app feels heavy on first launch — a long white screen, then everything snapping in at once — the usual culprit is that every page component is bundled into one file and parsed before the first view can render. On a mid-range Android phone, that parse-and-execute cost is often the difference between an app that feels native and one that feels like a website from 2012.
The fix is not a rewrite. Framework7's router has supported lazy-loaded routes since v5.7, and switching to them is mostly a matter of changing how you reference your page components. This post walks through the pattern, shows a concrete Vue-based example, and covers the one real trade-off you need to plan around.
How lazy routes work
Normally you import a page component at the top of your routes file and hand the router a direct reference. That import is static: the bundler includes the component in your main bundle whether or not the user ever visits that page.
A lazy route instead hands the router a function that returns a dynamic import(). The bundler (Webpack, Rollup, or Vite) splits that component into a separate chunk, and Framework7 only requests it when the user actually navigates to the route. The router integrates with the History API, so the URL still updates normally and back-button behavior is preserved — no full page reloads anywhere.
A concrete example with Framework7-Vue
Assume a standard Framework7-Vue project scaffolded with the CLI and built with Webpack 5 or Vite. Instead of this eager route:
import AboutPage from './pages/about.vue';
var routes = [
{ path: '/', component: HomePage },
{ path: '/about/', component: AboutPage },
];use a dynamic import:
var routes = [
{ path: '/', component: HomePage },
{
path: '/about/',
component: () => import('./pages/about.vue'),
},
];That is the entire change for the route itself. Navigation stays exactly the same:
<f7-link href="/about/">About</f7-link>When the user taps that link, Framework7 calls the function, waits for the chunk to load, then runs its normal page transition. Nothing else in your templates or navigation code needs to change, which is what makes this such a cheap win.
Deciding what to lazy-load
A reasonable rule of thumb: keep the home view and anything on the critical first-interaction path eager, and lazy-load everything else — settings, about, detail pages, admin panels, rarely used forms. A settings page with a rich text editor or a charting library is an ideal candidate; your login screen is not.
If you use route events like beforeEnter or tabbed routes with async components, the same dynamic-import pattern applies. Framework7 resolves the component before firing the page lifecycle events (page:beforein, page:mounted), so your existing event handlers keep working unchanged.
Verifying it actually worked
Do not trust the config — check the network. Run your dev server (npm run dev), open Chrome DevTools, go to the Network tab, and enable "Disable cache". Load the app and confirm the about page code is absent from the initial requests. Then click the About link: you should see a new chunk request (something like src_pages_about_vue.chunk.js under Webpack) fire at that moment, followed by the page rendering and the URL updating without a document reload.
For a rough performance check, run a Lighthouse audit or compare First Contentful Paint before and after the change on a throttled CPU profile (DevTools lets you apply 4x or 6x CPU slowdown, which approximates a low-end phone). The improvement shows up at startup, not at navigation time — that distinction matters for the next section.
The trade-off: first-navigation delay
Lazy loading moves cost rather than eliminating it. The first visit to a lazy route now includes a network round trip plus chunk evaluation, so the transition can pause briefly — noticeable on slow connections. Three mitigations:
- Prefetch during idle time. After the home page mounts, fire the same
import('./pages/about.vue')call without navigating. The bundler caches the chunk, so the real navigation is instant. - Keep hot routes eager. If analytics say 40% of sessions open the cart page, that page belongs in the main bundle.
- Show a preloader. Framework7's
page:beforeintiming means you can show its built-in preloader while the chunk resolves, so the delay reads as intentional loading rather than a freeze.
Limitations to know
Dynamic import() requires a bundler that supports code splitting — Webpack 4+, Rollup, or Vite all qualify. If you are loading Framework7 from a CDN with plain script tags and no build step, this pattern is not available to you. Also, the lazy-route API described here is stable from Framework7 v5.7 onward; on earlier versions you would need manual async route resolution, and behavior differs enough that upgrading is the better path. Check your installed version with npm list framework7 before copying the snippet above.
Where to start
Pick your three heaviest non-critical pages, convert their routes to dynamic imports, and measure startup with CPU throttling before and after. It is typically an afternoon of work, the navigation code stays untouched, and the History API integration means deep links and the back button behave exactly as users expect. That is about the best effort-to-payoff ratio you will find in mobile web performance work.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.