Dynamic Imports & Code Splitting
Dynamic imports load modules on demand — only when needed. This enables code splitting: load the initial page fast, then load additional features when the user needs them. Essential for performance.
Dynamic Imports
- Static import — import { fn } from './module'; loads at startup. Always available
- Dynamic import — import('./module') returns a Promise. Loads on demand
- Code splitting — Only load code when needed: routes, heavy libraries, conditional features
- Lazy loading — Load a module only when user clicks a button or navigates to a page
- Bundle splitting — Build tools (Webpack, Vite) automatically create separate files for dynamic imports
- Use cases — Admin panels, charts, PDF generators, language packs, feature flags
Dynamic Import Code
// Static import (always loaded)
// import { heavyFunction } from './heavyModule.js';
// Dynamic import (loaded on demand)
async function loadChart() {
console.log("Loading chart module...");
const chartModule = await import("./chartModule.js");
// chartModule.renderChart(data);
console.log("Chart module loaded!");
}
// Load only when user clicks
// document.querySelector("#showChart").addEventListener("click", loadChart);
// Conditional feature loading
async function loadFeature(featureName) {
try {
const module = await import(`./features/${featureName}.js`);
module.default.init();
console.log(`Feature '${featureName}' loaded ✅`);
} catch (error) {
console.error(`Feature '${featureName}' not found ❌`);
}
}
// Load language pack
async function loadLanguage(lang) {
const translations = await import(`./locales/${lang}.json`);
console.log(`Loaded ${Object.keys(translations).length} translations for '${lang}'`);
return translations;
}
// Pattern: lazy loading with fallback
async function loadHeavyModule() {
console.log("Loading heavy module...");
try {
const { default: HeavyLib } = await import("./heavy-lib.js");
return HeavyLib;
} catch {
console.log("Failed to load, using lightweight fallback");
return { process: data => data }; // fallback
}
}
console.log("Dynamic imports enable on-demand code loading! ⚡");Tip
Tip
Use dynamic import() for route-based code splitting in SPAs. Each page loads its own JavaScript bundle only when navigated to, reducing initial page load time by 50-80% in large applications.
ESM is the standard — use import/export for new projects
Common Mistake
Warning
Over-splitting modules with dynamic imports. Each dynamic import adds a network request. Only split at route boundaries and for genuinely large features. Splitting tiny utilities adds overhead without meaningful benefit.
Practice Task
Note
Dynamic imports: (1) Lazy-load a heavy library only when a feature is used. (2) Implement route-based code splitting. (3) Add a loading indicator while the module is being fetched.
Quick Quiz
Key Takeaways
- Dynamic imports load modules on demand — only when needed.
- Static import — import { fn } from './module'; loads at startup. Always available
- Dynamic import — import('./module') returns a Promise. Loads on demand
- Code splitting — Only load code when needed: routes, heavy libraries, conditional features