Как использовать динамический импорт в Next.js

Published on
Authors

Во время ночного тестирования производительности я все время спрашивал себя: «Как уменьшить время загрузки страницы в Next.js?» Тестируя в Network Panel, я сделал то, что делают большинство инженеров во время отчаяния, и пошел искать в Google. Именно тогда я открыл для себя удивительный мир динамического импорта.

Примечание. Динамический импорт был введен в ES2020 и может потребовать дополнительной настройки. На момент написания этого динамический импорт в Next.js поддерживался только для компонентов.

Что такое динамический импорт?

В отличие от импорта обычных модулей, динамический импорт позволяет гибко определять, когда и как они загружаются. Вместо принудительной загрузки файла модуля во время чтения, динамический импорт может быть запрошен во время использования.

Как настроить динамический импорт в Next.js

Прежде чем продолжить, следует помнить о некоторых вещах, связанных с динамическим импортом. Хотя динамический импорт может снизить загрузку страницы, очень важно знать, как ведет себя процесс получение пакета, чтобы избежать негативных побочных эффектов, которые могут увеличить загрузку страницы.

  1. Динамический импорт запрашивает при первом рендеринге компонента.
  2. Уже обработанный импорт не запускает дополнительную повторный запрос.
  3. Каждый динамический импорт будет создавать новый увеличенный файл пакета. Это включает вложенный динамический импорт.
  4. Каждый динамический импорт создает новый запрос на сервер.

Next.js поддерживает динамический импорт ES2020() для JavaScript. С его помощью вы можете динамически импортировать модули JavaScript и работать с ними. Они также работают с SSR.

В следующем примере мы реализуем нечеткий поиск с помощью fuse.js и динамически загружаем модуль в браузер только после того, как пользователь вводит поисковый запрос:

Создание примера

import { useState } from 'react'

const names = ['Tim', 'Joe', 'Bel', 'Max', 'Lee']

export default function Page() {
  const [results, setResults] = useState()

  return (
    <div>
      <input
        type="text"
        placeholder="Search"
        onChange={async (e) => {
          const { value } = e.currentTarget
          // Dynamically load fuse.js
          const Fuse = (await import('fuse.js')).default
          const fuse = new Fuse(names)

          setResults(fuse.search(value))
        }}
      />
      <pre>Results: {JSON.stringify(results, null, 2)}</pre>
    </div>
  )
}

Вы можете рассматривать динамический импорт как еще один способ разбить код на управляемые части.

Компоненты React также можно импортировать с помощью динамического импорта, но в этом случае мы используем его вместе с next/dynamic, чтобы убедиться, что он работает как любой другой компонент React. 

Основное использование

В следующем примере модуль ../components/hello будет динамически загружен страницей:

import dynamic from 'next/dynamic'

const DynamicComponent = dynamic(() => import('../components/hello'))

function Home() {
  return (
    <div>
      <Header />
      <DynamicComponent />
      <p>HOME PAGE is here!</p>
    </div>
  )
}

export default Home

DynamicComponent будет компонентом по умолчанию, возвращаемым ../components/hello. Он работает как обычный компонент React, и вы можете передавать ему пропсы, как обычн

Примечание. В import ('path/to/component') путь должен быть явно записан. Это не может быть ни строка шаблона, ни переменная.
Кроме того, import() должен находиться внутри вызова dynamic() для Next.js, чтобы иметь возможность сопоставлять идентификаторы пакетов/модулей веб-пакетов с конкретным вызовом dynamic() и предварительно загружать их перед рендерингом.
dynamic() не может использоваться внутри React-рендеринга, так как он должен быть отмечен на верхнем уровне модуля для предварительной загрузки для работы, аналогично React.lazy.
-

ПРОВЕРКА ВАШЕЙ РАБОТЫ

Вы можете убедиться в волшебстве динамического импорта, проверив сетевую панель в коде и просмотрев несколько JS-файлов, таких как 0.js. В Next.js 0.js является основным файлом пакета. Между тем, динамический импорт начинается с 1.js и увеличивает новый пакет за новый динамический импорт.

После рендеринга модуля динамического импорта загружается новый пакет Next.js. Имя увеличивается, например: 1.js, и будет отображаться на панели сети. Это происходит при рендеринге динамического импорта.

С именованным экспортом

Если динамический компонент не является компонентом экспортированным по умолчанию, вы также можете использовать именованный экспорт. Рассмотрим модуль ../components/hello.js с именем export Hello:

export function Hello() {
  return <p>Hello!</p>
}

Чтобы динамически импортировать компонент Hello, вы можете вернуть его из Promise, возвращаемого функцией import(), например:

import dynamic from 'next/dynamic'

const DynamicComponent = dynamic(() =>
  import('../components/hello').then((mod) => mod.Hello)
)

function Home() {
  return (
    <div>
      <Header />
      <DynamicComponent />
      <p>HOME PAGE is here!</p>
    </div>
  )
}

export default Home

Настраиваемая загрузка компоненты

Опциональный компонент "загрузка" может быть добавлен для визуализации состояния загрузки во время загрузки динамического компонента. Например

import dynamic from 'next/dynamic'

const DynamicComponentWithCustomLoading = dynamic(
  () => import('../components/hello'),
  { loading: () => <p>...</p> }
)

function Home() {
  return (
    <div>
      <Header />
      <DynamicComponentWithCustomLoading />
      <p>HOME PAGE is here!</p>
    </div>
  )
}

export default Home

Без SSR

Возможно, вы не всегда хотите включать модуль на стороне сервера. Например, когда модуль включает библиотеку, которая работает только в браузере.

Взгляните на следующий пример:

import dynamic from 'next/dynamic'

const DynamicComponentWithNoSSR = dynamic(
  () => import('../components/hello3'),
  { ssr: false }
)

function Home() {
  return (
    <div>
      <Header />
      <DynamicComponentWithNoSSR />
      <p>HOME PAGE is here!</p>
    </div>
  )
}

export default Home

Когда использовать динамический импорт

Чтобы определить лучшие места для динамического импорта, может потребоваться метод проб и ошибок, но это не всегда хороший метод. Вот список мест, которые я посчитал полезными когда проводил мои эксперименты.

ЧТО НУЖНО ИСКАТЬ:

  1. Сценарии, в которых ресурсоемкие компоненты не отображаются при загрузке страницы, отлично подходят для динамического импорта.
  2. Модули, использующие внешние ресурсы, могут использовать асинхронный импорт.
  3. Необходимость отображать загружаемый компонент во время рендеринга компонента. Это может быть легче обнаружить при ограниченном сетевом подключении.

ЧТО СЛЕДУЕТ ИЗБЕГАТЬ:

  1. Если динамически импортированный компонент отображается немедленно, размер полезной нагрузки остается таким же, и добавляется дополнительный запрос сервера для дополнительного пакета кода.
  2. Избегайте чрезмерного использования динамического импорта. Каждый вариант использования добавляет новый запрос сервера и пакет кода. Это может быть дорогостоящим, если этой функцией злоупотреблять.
  3. По возможности избегайте вложенных динамических импортов. Это может легко добавить дополнительные запросы к серверу и дополнительные бандлы кода.
  4. Динамический импорт в Next.js не работает с функциями. Это может быть возможно в будущем, но пока не поддерживается.

СЦЕНАРИИ РЕАЛЬНОЙ ЖИЗНИ:

Вот несколько типичных компонентов, которые отлично подходят для динамического импорта:

  1. UI компоненты, такие как модальные окна, всплывающие панели навигации и переключатели, которые не отображают контент, пока не произойдет взаимодействие.
  2. Компоненты поиска, использующие ввод текста или нажатие кнопки
  3. Компоненты «Загрузить еще», которые отображают дополнительный контент при взаимодействии с пользователем.
  4. Модульные запросы из внешнего API
  5. Компоненты, которые загружаются медленно и могут получить выгоду от компонента загрузки, пока выполняется импорт

Выводы

Если у вас есть тяжелые компоненты ресурсов, которые не нужно обрабатывать при загрузке страницы, обязательно используйте динамический импорт. Это может оказать огромное влияние на время загрузки страницы и показать высокие оценки в PageSpeed Lighthouse. Эта функция действительно проста в использовании, и вам нечего терять, попробовав ее.