Volume 2

Q143: Lazy Loading, Code Splitting and Side Effect Boundaries

Difficulty: SeniorFrequency: HighAnswer time: 8-12 minutes

What Interviewers Want To Evaluate

This question checks whether you can reason about JavaScript loading strategy. Interviewers want dynamic import, route-level splitting, component-level splitting, side effects, preloading, waterfall risk, error states, and measuring bundle impact.

Senior answers should connect splitting decisions to user experience, not just smaller files.

Short Interview Answer

Code splitting divides JavaScript into chunks so users do not download everything upfront. Lazy loading uses dynamic import() or framework primitives to load code when needed. It helps when a feature is expensive and not required for initial interaction. The trade-offs are loading delay, waterfalls, error states, and complexity. Modules with side effects can make splitting less effective or risky because importing them does work immediately.

Detailed Interview Answer

Modern apps can grow large quickly.

Code splitting asks:

what must load for the first useful screen?
what can wait until user intent?
what can preload before likely use?
what should never be in the initial bundle?

The goal is faster useful interactivity, not splitting for its own sake.

Dynamic Import

Dynamic import returns a promise.

async function openEditor() {
  const { Editor } = await import("./editor.js");
  render(Editor);
}

This can place editor code in a separate chunk.

Good Candidates

Good lazy-loading candidates include:

rich text editors
charts
maps
admin-only tools
payment SDKs
large validation libraries
rarely used modals
export or import workflows

These are expensive or low-frequency features.

Bad Candidates

Bad candidates include code required for the initial render or first critical interaction.

Lazy loading a tiny but critical button handler may add delay without meaningful savings.

Every split has overhead.

Waterfall Risk

Lazy loading can create waterfalls.

load page
user clicks
load feature chunk
feature chunk loads data
feature renders

If likely user intent is clear, preload the chunk earlier.

Preloading Strategy

Potential preload triggers:

route hover
button visible in viewport
user opens parent menu
idle time after main screen settles
analytics shows high likelihood

Preloading should be measured. Too much preloading becomes eager loading under another name.

Side Effects

Module-scope side effects run when a chunk is imported.

initializeTracking();
registerGlobalPlugin();
patchPrototype();

This can make lazy-loaded code affect the whole app unexpectedly.

Prefer explicit initialization:

export function initEditorPlugins() {}

Error and Loading States

Lazy chunks can fail to load due to network issues, deploy mismatches, ad blockers, or cache problems.

The UI needs:

loading state
retry option
fallback copy
error reporting
possibly full page refresh for stale chunks

Chunk failures are production realities.

Bundle Measurement

Use bundle analysis and route-level metrics.

Check:

initial JavaScript size
route chunk size
shared chunks
duplicated dependencies
parse and execute cost
lazy chunk load timing
user interaction delay

Smaller transfer size is not the only metric. Parse and execution cost matter.

Common Mistakes

A common mistake is lazy loading everything and creating a slow, jumpy UI.

Another mistake is forgetting chunk error handling.

Another mistake is importing a large library through a shared utility, pulling it into the main bundle anyway.

Senior Trade-Offs

Code splitting trades initial load cost for later loading cost.

Use it where delayed code aligns with delayed user intent.

Measure before and after so the split improves the real workflow.

Code or Design Example

let editorModulePromise;

function preloadEditor() {
  editorModulePromise ??= import("./editor.js");
  return editorModulePromise;
}

async function openEditor() {
  const { createEditor } = await preloadEditor();
  return createEditor();
}

This avoids loading the same chunk repeatedly and supports preloading on intent.

Debugging Workflow

When lazy loading hurts UX:

inspect bundle analyzer
check network waterfall
check chunk load failures
check whether shared imports pulled code eagerly
check side effects at module scope
add preload on strong intent
measure interaction delay
remove unnecessary splits

Interview Framing

Explain dynamic import and code splitting, then discuss candidates, waterfalls, preloading, side effects, and measurement.

Revision Notes

Lazy loading is a user-intent strategy. It works when delayed code matches delayed need.

Key Takeaways

Good splitting makes the first experience lighter without making later interactions feel broken or sluggish.

Follow-Up Questions

  1. What is code splitting?
  2. What does dynamic import return?
  3. What features should be lazy loaded?
  4. When should you avoid lazy loading?
  5. What is a loading waterfall?
  6. When should chunks be preloaded?
  7. Why are module side effects risky?
  8. How do chunk load failures happen?
  9. What should bundle analysis inspect?
  10. How do you decide if a split helped?

How I Would Answer This In A Real Interview

I would say code splitting delays non-critical JavaScript until user intent. Then I would discuss dynamic import, good candidates like editors and charts, waterfall risk, preload strategy, side-effect boundaries, error states, and measurement.