Dynamic import()

We can use import() to lazily load components.

- import { SomeComponent } from 'some-component'
// Somewhere in our code
function someFunction() {
  // We load `<SomeComponent>` at a later point, after the initial JavaScript
  // is already loaded & running.
  const { SomeComponent } = await import('some-component')
  // We can even conditionally load a component:
  if (someCondition) {
    const { SomeOtherComponent } = await import('some-other-component')
  }
}

Vite automatically code-splits at import(): the code of some-component is not included in the initial JavaScript browser-side bundle; instead, it is only loaded when/if import('some-component') is executed.

There are two use cases for dynamically importing components:

  • For performance. The idea here is to defer loading heavy components (e.g. an interactive map), so that the user can already interact with our page before the browser has loaded that heavy component.
  • For client-side only components. Some components don't work in Node.js; we use import() to load & render them only on the client-side.
    const isBrowser = typeof window !== 'undefined'
    if (isBrowser) {
      // We load the component only in the browser; we never load `some-component` in Node.js.
      const { SomeComponent } = await import('some-component')
    }

UI frameworks usually have built-in support for dynamically loading components:

React Example:

// pages/pick-location.page.jsx

import React from 'react'
import { Loading } from './Loading'

export function Page() {
  // Users will see the text `Please pick a location` before the browser loads the `<Map>`
  // component's code. (This is the case anyways when using SSR, but `import()` allows the
  // user to not only see but also interact with our page before `<Map>` is loaded.)
  return <>
    Please pick a location.
    <Map />
  </>
}

function Map() {
  const isBrowser = typeof window !== 'undefined'
  const isNodejs = !isBrowser

  // We skip rendering the interactive map on the server-side (SSR'ing a map is mostly useless).
  if (isNodejs) {
    return <Loading />
  }

  // We lazily load `<SomeHeavyMapComponent>`
  const SomeHeavyMapComponent = React.lazy(() => import('some-heavy-map-component'))
  return (
    <React.Suspense fallback={<Loading />}>
      <SomeHeavyMapComponent />
    </React.Suspense>
  )
}