动态 import()

我们可以使用动态 import() 来懒加载组件:

- import SomeComponent from 'some-component'
+ const { SomeComponent } = await import('some-component')

Vite 在 import() 处自动进行代码拆分,some-component 的代码不会包含在初始的 JavaScript bundle 中: 只有在执行 import('some-component') 时才会加载代码

常见用例:

  • 性能: 我们可以使用 import() 来懒加载组件(例如交互式地图),这样用户就可以在浏览器开始加载该重组件之前与页面进行交互
  • 客户端组件: 我们可以使用 import() 来避免在服务端加载/渲染组件。(有些组件库不能再服务端渲染,参考 指南 > Client-only 组件

UI 框架支持 import() 懒加载组件:

React Example

// ages/location/pick.page.jsx

import React from 'react'

export function Page() {
  // 浏览器加载 <SomeHeavyMapComponent> 代码之前,
  // 用户可以看到 "Please pick a location" 按钮并与之交互
  return (
    <>
      <button>Please pick a location</button>
      <Map />
    </>
  )
}

// <Map> 是:
//  - 懒加载的
//  - 仅在浏览器中加载渲染
function Map() {
  const [Component, setComponent] = React.useState(() => Loading)

  // useEffect() 回调仅在浏览器中运行
  // 因此 map 组件也仅在浏览器中加载和渲染
  React.useEffect(() => {
    setComponent(() => React.lazy(() => import('some-heavy-map-component')))
  }, [])

  return (
    <React.Suspense fallback={<Loading />}>
      <Component />
    </React.Suspense>
  )
}

function Loading() {
  return <div>Loading map...</div>
}

我们可以将逻辑提取到通用的 <ClientOnly> 组件中:

import React from 'react'

function Map() {
  return (
    <ClientOnly
      load={() => import('some-heavy-map-component')}
      fallback={<Loading />}
    />
  )
}

function ClientOnly({ load, fallback }) {
  const [Component, setComponent] = React.useState(() => fallback)

  React.useEffect(() => {
    setComponent(() => React.lazy(load))
  }, [])

  return (
    <React.Suspense fallback={fallback}>
      <Component />
    </React.Suspense>
  )
}

另请参考: