Modules & Bundling
Dynamic Imports — import()
Master dynamic module imports in JavaScript. Learn how dynamic import() loads modules asynchronously on demand, improving startup performance.
1. Introduction
Standard import statements are static: they must be declared at the top level of files and load modules immediately during compilation. Dynamic Imports use the functional import(modulePath) syntax to load modules asynchronously at runtime, enabling code splitting and on-demand loading.
2. Why It Matters
Loading all scripts at once increases initial page load times. Dynamic imports allow you to load modules on demand (for example, loading an analytics script only after the user logs in, or loading a heavy chart library only when the user clicks a tab), reducing initial bundle sizes.
3. Real-World Analogy
Think of a Restaurant Menu Ordering System:
- Static Imports (Pre-cooking all items): A kitchen that prepares every single dish on the menu before the restaurant opens (highest memory usage and preparation time). If a customer only orders salad, the prepared steaks are wasted.
- Dynamic Imports (Cook to Order): The kitchen sits ready. When a customer orders a steak (clicks a button), the chef prepares and serves the steak asynchronously (on-demand loading), saving resources.
4. The import() Function
The import() syntax behaves like a function call that returns a Promise resolving to the module's namespace object:
5. Dynamic Imports with Async/Await
You can combine dynamic imports with async/await syntax to write clean asynchronous code:
6. Practical Example
This script demonstrates loading a translation module dynamically based on the user's browser language setting:
7. Common Mistakes
- Trying to use static syntax inside execution blocks: Standard
importdeclarations are parsed statically and must be placed at the top level of files. Declaring them inside functions or loops throws a SyntaxError. Use the functionalimport()syntax instead for dynamic loading.
8. Quick Quiz
Q1: What does the functional import() syntax return?
A) The exported default class directly
B) A Promise that resolves to the module's namespace object
Answer: B — The functional import() call returns a Promise resolving to the module's namespace object, which contains all exports.
9. Scenario-Based Challenge
The Conditional Analytics Tracker:
An application tracks user interactions. To respect privacy options, load the analytics library: ./analytics.js only if the user has consented to tracking (window.localStorage.getItem("consent") === "granted"). Write this conditional loader using dynamic imports.
10. Debugging Exercise
Explain why this dynamic import handler fails to access the default export class:
// button.js
export default class Button {
render() { return 'rendered'; }
}
// app.js
async function renderWidget() {
const widget = await import('./button.js');
// Bug: trying to instantiate the module namespace object directly!
const btn = new widget(); // throws TypeError: widget is not a constructor! Why?
}
View Solution
Diagnosis: The import() Promise resolves to a module namespace object, not the default export itself. The default export is accessible via the default property on the resolved object.
Fix: Access the default export using the default property, or destructure the property during import:
async function renderWidget() {
const { default: Button } = await import('./button.js'); // Destructure default
const btn = new Button(); // Works!
}
11. Interview Questions
🟢 Q1: Compare static imports and dynamic imports and explain their differences in loading behavior.
Answer:
• Static Imports: Declared at the top level of files using the import keyword. They are parsed and loaded statically before the script runs, which blocks execution until all modules are loaded.
• Dynamic Imports: Called dynamically using the import() function syntax. They load modules asynchronously at runtime, returning a Promise. This design allows you to load modules on demand, improving startup performance.
12. Production Considerations
- • Code Splitting: Most modern bundlers (like Webpack or Rollup) automatically create separate chunk files (code splitting) for any dynamic imports they encounter, saving bandwidth during initial page loads.