Skip to content
intermediate Phase 9 · Routing with Vue Router

Route-Level Code Splitting

Load view chunks on demand with dynamic import in route definitions.

35m
0 problems
Topic Progress 0%

Route-Level Code Splitting: Core Concepts

Load a view when its route is visited

A static import includes a component in the importing module's dependency graph. For a route that is rarely visited, loading that component in the initial bundle can make the first screen download and parse code the user may never need. Vue Router supports a dynamic import function as a route component. The build tool can turn that boundary into a separate chunk, and the router loads it when navigation reaches that route.

const routes = [
  { path: '/', component: HomeView },
  {
    path: '/reports',
    component: () => import('./views/ReportsView.vue'),
  },
]

This is route-level code splitting: the route record retains a function that resolves to a component. Do not wrap the route import in defineAsyncComponent by default; Vue Router already knows how to resolve lazy route components and coordinates navigation with the import. defineAsyncComponent is appropriate for an async component rendered inside a view when that component is not the route boundary.

Choose useful split boundaries

Splitting every tiny component creates many requests and chunks with little useful savings. Start with substantial routes or feature areas that are not needed on initial navigation, such as an admin console, report builder, or rarely used settings flow. Keep the application shell, common navigation, and first-screen components eager when their code is needed immediately. A shared dependency may still be extracted into a common chunk by the bundler, so measure the production output rather than assuming each route maps one-to-one to one file.

Dynamic import is a promise boundary. Navigation waits for the route component to resolve before completing. If the chunk fails to download because of a network issue or a deployment where an old HTML shell references a removed chunk, navigation can fail. Provide a route error strategy and make deployments resilient to cached entry documents where possible. A full refresh may be a reasonable recovery for a stale deployment asset, but it should not hide a persistent missing file.

Loading and navigation feedback

While a route chunk is loading, the current route may remain visible and navigation remains pending. Provide feedback for slow transitions when the delay is noticeable, but avoid flashing a spinner for every fast cached import. A global progress indicator can be tied to router navigation hooks, while route-specific data loading can have its own state after the component loads. Chunk loading and API loading are separate phases and should not be represented as one ambiguous failure.

Prefetching can warm a chunk before the user navigates, for example when a likely next destination is hovered or becomes visible. It trades bandwidth and cache usage for lower future wait time. Prefetching every route undermines the initial network savings, especially on metered connections. Use intent signals or measured navigation patterns, and ensure hover is not the only way to reach or prepare the route for keyboard and touch users.

Distinguish splitting from server rendering

Lazy route imports affect client bundle delivery; they do not decide whether a route is server-rendered, static-generated, or protected. They also do not replace authorization checks or data fetching. A code-split admin view can still be downloaded by an unauthorized client; the API must enforce access. Treat chunking as a performance optimization and inspect its behavior under the application's rendering and deployment model.

The useful rule is to defer code that is not needed now, preserve a fast critical path, and measure the result. A smaller initial bundle is valuable only if users can still reach the feature reliably and the added navigation latency is acceptable.

Route-Level Code Splitting: Practice

Split a substantial feature route

Choose a route that is not part of the first screen and whose component graph is large enough to justify a separate chunk. Replace its static component import with a dynamic import function in the route record. Leave the root layout and commonly used home route eager. Build the production application and inspect the emitted assets; development mode often serves modules individually and does not show the production chunk shape.

const routes = [
  { path: '/', name: 'home', component: HomeView },
  {
    path: '/analytics',
    name: 'analytics',
    component: () => import('./views/AnalyticsView.vue'),
  },
]

Navigate to the analytics route and observe the network request. Navigate away and back to see whether the browser cache avoids another transfer. Then test a throttled connection to understand the delay and whether the current page remains usable while the chunk loads. A route-level chunk can include dependencies used only by analytics, but a library shared with the home page may be placed in a shared chunk.

Measure the trade-off

Compare the initial JavaScript size and route chunk size before and after the change. Also compare time to the first useful screen and time to the first analytics render on a cold cache. The split can improve initial loading while making first navigation to analytics slower. Evaluate the routes users actually visit and the cost of repeat navigation; a rarely used, heavy report builder is a better candidate than a tiny common settings tab.

Use production-like hosting for the test. Confirm that the server and CDN serve the emitted chunk paths with the expected content type, that cache headers allow safe reuse, and that an old cached HTML document does not reference chunks removed by a deployment. Content-hashed assets help cache correctness, but deployment cleanup policies still matter. Keep recently used assets available long enough for clients with open tabs when the operational environment allows it.

Handle failed imports

A dynamic import can reject. The router exposes navigation failure and error hooks that can be used to log a failed chunk load and show recovery guidance. Avoid catching every import error and silently rendering an unrelated page; that makes the URL and visible content disagree. A retry can help with a transient network failure, while a deployment mismatch may require a controlled refresh. Prevent refresh loops by recording whether an automatic recovery has already been attempted.

Chunk loading feedback should not conflate code delivery with API data. The component cannot show its own data state until its code has loaded, but a global navigation indicator can represent the transition. After the view resolves, its data request may still be pending. Keep messages specific enough that a person knows whether to wait, retry, or revisit the page.

As an exercise, split a route and verify the initial bundle, direct deep link, browser Back and Forward, and failure behavior with the chunk request blocked. Add a keyboard-accessible navigation path and consider a lightweight prefetch when the analytics link enters the viewport. Compare bandwidth against latency on a constrained network. Keep prefetch opt-in and selective so users who never visit the route do not download the code anyway.

Route-Level Code Splitting: Trade-offs and Interviews

Split by user journey, not file count

The right split boundary usually follows a feature journey. A large report editor, administrative workspace, or rarely used onboarding flow can be deferred as a unit. Splitting every component creates request overhead, more cache entries, and a harder-to-understand dependency graph. Bundlers may also share common dependencies, so a route component does not guarantee an isolated chunk. Inspect the build output and use a bundle analyzer when the dependency graph is unclear.

Keep the critical route fast. If the initial page immediately needs a component, making it lazy merely moves its wait into the first navigation. Conversely, an uncommon route can be a strong candidate even if its code is moderate when it pulls in an expensive visualization or editor library. Measure initial load, route transition, and repeat navigation rather than optimizing one file-size number.

Reliability is part of the optimization

Lazy imports add a network failure point at navigation time. A stale document may point to an asset removed by a new deployment; a transient connection can interrupt the chunk request. Use content-hashed assets and deployment retention appropriate to open clients, monitor chunk failures, and provide a recovery path. Do not catch and suppress errors in a way that leaves the URL changed while the old view remains unexplained.

Prefetch can hide latency, but it spends bytes before they are required. Use intent signals that work for mouse, keyboard, and touch, or use measured navigation probability. Avoid broad prefetch rules that recreate the original eager bundle. Consider browser data-saver preferences and ensure the feature remains usable without prefetch success.

Code splitting does not secure a route. A user can inspect downloaded JavaScript or request an API directly. Continue to enforce authentication and authorization at the server and treat route guards as navigation experience only. Likewise, lazy loading a component does not automatically defer its data request; that lifecycle should be designed separately.

Verify the result

Build production assets and compare the initial transfer and route chunks. Test a cold navigation, a warm navigation, a slow network, and a failed chunk. Directly load the lazy route and refresh it to verify hosting fallback. Check browser console and network responses for MIME or cache errors. Run a representative browser test after deployment because development servers can conceal output-path and cache behavior.

In an interview, explain dynamic import at a route boundary, why the bundler emits deferred code, and which user journey justifies it. Discuss the first-navigation trade-off, prefetch bandwidth, shared chunks, and error recovery. Finish by distinguishing performance from authorization. That decision-oriented answer shows code splitting is a measured delivery strategy rather than a mechanical syntax change. After release, monitor chunk-load failures by route and build version, and compare real navigation latency with the baseline. Retain hashed assets long enough for open tabs that still reference an earlier document. If a retry or refresh is offered, prevent repeated loops and preserve the destination so the user can recover without losing context. Verify this retention policy during a staged deployment as well.

Quiz

1. Which statement about Route-Level Code Splitting is accurate?

Question 1 options

2. When reviewing Route-Level Code Splitting, which point must hold?

Question 2 options

3. How should a Vue Router route component be lazy-loaded?

Question 3 options

4. What is a key cost of route-level code splitting?

Question 4 options

Flashcards

Question

What is Route-Level Code Splitting?

Answer

Load view chunks on demand with dynamic import in route definitions.

Question

Route-Level Code Splitting: why it matters

Answer

Passing an import function to the component field defers loading until the route is visited.

Question

Route-Level Code Splitting: key detail

Answer

Each lazily loaded route becomes a separate chunk in the production bundle output.

Question

Route-Level Code Splitting: practical note

Answer

The main entry chunk shrinks because view code no longer ships up front.

Question

What is the cold-navigation cost of a lazy route?

Answer

The browser must download the deferred route chunk on first visit.

Revision Notes

Key Takeaways

  • 1. Passing an import function to the component field defers loading until the route is visited.
  • 2. Each lazily loaded route becomes a separate chunk in the production bundle output.
  • 3. The main entry chunk shrinks because view code no longer ships up front.

Interview Tips

  • • Explain Route-Level Code Splitting with one concrete example from real vue work, not a textbook restatement.
  • • Discuss the trade-off: when Route-Level Code Splitting helps and when a lighter approach wins.
  • • Place Route-Level Code Splitting inside the Routing with Vue Router phase — interviewers check that you see the progression, not isolated facts.

Cheat Sheet

Route-Level Code Splitting Cheat Sheet

Phase: Routing with Vue Router | Level: intermediate

Key points:

  • Passing an import function to the component field defers loading until the route is visited.
  • Each lazily loaded route becomes a separate chunk in the production bundle output.
  • The main entry chunk shrinks because view code no longer ships up front.
  • Prefetching on hover hides the network latency of a first-time chunk request.

Tags: vue, router, performance

Continue Learning

Before You Start

  • No prerequisites listed.

Next Topics

Related Reading