Dynamic Import
Dynamic import loads a JavaScript module asynchronously when execution reaches the import expression. In frontend builds, bundlers commonly place the dynamically imported module in a separate chunk that can be fetched on demand.
A dynamic import uses the `import()` expression instead of a static `import` declaration. It returns a Promise that fulfills with the imported module's namespace object, so the module can be used after the asynchronous load completes.
Because the import happens at runtime, bundlers can often split the dependency graph at that point. The resulting code may be emitted as a separate chunk and downloaded only when that code path is reached, reducing the initial JavaScript payload.
Dynamic import is useful for features that are not needed immediately, such as a settings screen, a large editor, or a route that the user may never visit. It can improve initial loading by moving optional code out of the initial bundle, although the deferred chunk still has to be downloaded before the feature can run.
The expression is asynchronous even when the requested module is already cached. Code should therefore handle the Promise, commonly with `await` or `.then()`, and should consider failures such as a missing chunk or network error.
Key points
- `import()` loads a module asynchronously and returns a Promise.
- Bundlers commonly use dynamic imports as code-splitting boundaries.
- The deferred chunk is fetched when the dynamic import is evaluated.
- Dynamic import can reduce initial JavaScript, but adds a later loading step.
- Use error handling when loading a dynamically imported module can fail.
Interview questions
What is dynamic import in JavaScript?
Dynamic import uses the `import()` expression to load a module asynchronously at runtime. It returns a Promise that resolves to the module namespace. This allows code to be loaded only when a particular execution path needs it. In frontend applications, this is commonly used for lazy loading and code splitting.
How does dynamic import help frontend bundle optimization?
A bundler can treat a dynamic import as a boundary between code that can be loaded separately. Instead of putting every dependency in the initial JavaScript payload, optional dependencies can be emitted into additional chunks. The browser downloads those chunks when the corresponding `import()` executes. This can reduce initial download and parsing work when users do not need the deferred feature.
What happens when a dynamic import fails?
The Promise returned by `import()` rejects if the module cannot be loaded or evaluated successfully. Applications can handle this with `try`/`catch` around `await import()` or with a Promise rejection handler. In a browser application, a failure can occur because a generated chunk is unavailable or the network request fails. User-facing applications should decide how to recover, such as retrying or showing an error state.
Does every dynamic import guarantee a separate network request?
No. `import()` provides an asynchronous module-loading boundary, but the exact network and chunk behavior depends on the runtime, module loader, bundler, and build configuration. A bundler may create a separate chunk, but caching or other optimizations can prevent a new network transfer. Therefore, dynamic import should be understood as a mechanism for deferred module loading rather than a guarantee of one specific network request.