Как Next.js выполняет предварительный рендеринг

внешний интерфейс внешний фреймворк
Как Next.js выполняет предварительный рендеринг

автор:Ихэн

предисловие

Открытьnext.jsНа официальном сайте первое, что бросается в глаза, это Слоган и введение:

The React Framework for Production

Next.js gives you the best developer experience with all the features you need for production: hybrid static & server rendering, TypeScript support, smart bundling, route pre-fetching, and more. No config needed.

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

Три режима предварительного рендеринга

Обычные одностраничные приложения имеют только один HTML-код. HTML-код, возвращаемый первоначальным запросом, не содержит содержимого страницы. Ему необходимо запросить пакет JS через сеть и отобразить его. Весь процесс рендеринга завершается на стороне клиента, поэтому это называется рендерингом на стороне клиента (CSR). Хотя этот метод рендеринга очень быстр при последующем переключении страниц, очевидно, есть две проблемы:

  1. Чрезмерное время белого экрана: страница пуста, пока пакет JS не вернется. Если размер пакета слишком велик или сетевые условия плохие, опыт будет еще хуже.
  2. SEO-недружественность: когда поисковая система получает доступ к странице, она просматривает только содержимое в формате HTML. По умолчанию JS не выполняется, поэтому она не может сканировать конкретное содержимое страницы.

image.png

Все три режима предварительного рендеринга, предоставляемые Next.js, предварительно рендерят содержимое страницы на стороне сервера до запуска CSR, избегая проблем, связанных с долгим временем белого экрана и недружественным SEO.

SSR

Для решения двух вышеупомянутых проблем родился SSR (Server Side Rendering). Я полагаю, что все знакомы с SSR, поскольку он напрямую и изоморфно отображает страницу, к которой обращается текущий пользователь, на стороне сервера, а возвращаемый HTML-код содержит конкретное содержимое страницы для улучшения взаимодействия с пользователем. React обеспечивает поддержку непосредственно на уровне фреймворка, просто позвонитеrenderToString(Component)функция для получения содержимого HTML.

image.png

Next.js предоставляетgetServerSidePropsАсинхронная функция для извлечения дополнительных данных в сценарии SSR и возврата их компоненту для рендеринга.getServerSidePropsВы можете получить контекст каждого запроса (Context),Например:

export default function FirstPost(props) {
  // 在 props 中拿到数据
  const { title } = props;
  return (
    <Layout>
      <h1>{title}</h1>
    </Layout>
  )
}

export async function getServerSideProps(context) {
  console.log('context', context.req);
  // 模拟获取数据
  const title = await getTitle(context.req);
  // 把数据放在 props 对象中返回出去
  return {
    props: {
      title
    }
  }
}
 

Хотя решение SSR решает две проблемы, связанные с CSR, оно также создает еще одну проблему: требуется сервер для размещения запроса, рендеринга и ответа страницы в реальном времени, что, несомненно,Увеличение стоимости разработки и эксплуатации и обслуживания серверов. Кроме того, для некоторых относительно статичных сценариев, таких как блоги, официальные сайты и т. д., их содержание относительно детерминировано и меняется нечасто.Отображаемый контент тот же, несомненно, тратя много ненужных ресурсов сервера. В настоящее время есть ли решение сделать эти страницы статическими? В этот момент родилась генерация статического сайта (SSG, также известная как предварительная визуализация во время сборки).

SSG

SSG (Генерация статического сайта) относится к предварительному рендерингу страницы, когда приложение компилируется и создается, и генерирует статический HTML. После развертывания сгенерированных статических ресурсов HTML на сервере браузер может не только запрашивать HTML с содержимым страницы в первый раз, но и не требует от сервера рендеринга и ответа в режиме реального времени, что значительно экономит затраты на эксплуатацию и обслуживание сервера. и ресурсы.

image.png

Next.js по умолчанию включает SSG для каждой страницы. Для сценариев, в которых содержимое страницы должно полагаться на статические данные, это разрешено на каждой странице.exportОдинgetStaticPropsАсинхронная функция, в которой данные, необходимые компоненту страницы, могут быть собраны и возвращены. когдаgetStaticPropsПосле выполнения функции компонент страницы может бытьpropsПолучите эти данные и выполните статическую визуализацию. взятьстатическая маршрутизацияПример использования SSG в:

// pages/posts/first-post.js
function Post(props) {
	const { postData } = props;
  
  return <div>{postData.title}</div>
}

export async function getStaticProps() {
  // 模拟获取静态数据
	const postData = await getPostData();
  return {
  	props: { postData }
  }
}

длядинамическая маршрутизациясценарий, как Next.js выполняет SSG? Next.js предоставляетgetStaticPathsАсинхронная функция в этом методе вернетpathsМассив, содержащий данные страницы, которые этот динамический маршрут должен предварительно отобразить при построении. Например:

// pages/posts/[id].js
function Post(props) {
	const { postData } = props;
  
  return <div>{postData.title}</div>
}

export async function getStaticPaths() {
  // 返回该动态路由可能会渲染的页面数据,比如 params.id
  const paths = [
    {
      params: { id: 'ssg-ssr' }
    },
    {
      params: { id: 'pre-rendering' }
    }
  ]
  return {
    paths,
    // 命中尚未生成静态页面的路由直接返回 404 页面
    fallback: false
  }
}

export async function getStaticProps({ params }) {
  // 使用 params.id 获取对应的静态数据
  const postData = await getPostData(params.id)
  return {
    props: {
      postData
    }
  }
}

когда мы выполняемnextjs buildПосле этого вы можете увидеть, что результат упаковки содержитpre-rendering.htmlа такжеssg-ssr.htmlДве страницы HTML, то есть при выполнении SSG, будутgetStaticPathsФункция возвратаpathsМассив зациклен, предварительно отрисовывая компоненты страницы один за другим и генерируя HTML.

├── server
|  ├── chunks
|  ├── pages
|  |  ├── api
|  |  ├── index.html
|  |  ├── index.js
|  |  ├── index.json
|  |  └── posts
|  |     ├── [id].js
|  |     ├── first-post.html
|  |     ├── first-post.js
|  |     ├── pre-rendering.html       # 预渲染生成 pre-rendering 页面
|  |     ├── pre-rendering.json
|  |     ├── ssg-ssr.html             # 预渲染生成 ssg-ssr 页面
|  |     └── ssg-ssr.json

Хотя SSG решает проблемы долгого времени белого экрана и недружественного SEO, он подходит только для сценариев с относительно статичным содержимым страниц, таких как официальные веб-сайты и блоги. лицоДанные страницы часто обновляютсяилиМного страницВ случае с , он кажется немного беспомощным, ведь он не может получить последние данные и не может перечислить массивные страницы во время статической сборки. В настоящее время требуется схема инкрементной статической регенерации (Incremental Static Regeneration).

ISR

image.png

Решение ISR (Incremental Static Regeneration), запущенное Next.js, позволяетВосстанавливайте HTML-код каждой страницы во время работы приложения вместо перестройки всего приложения.. Таким образом, даже при большом количестве страниц можно использовать возможности SSG. В общем, использование ISR требуетgetStaticPathsа такжеgetStaticPropsИспользуйте вместе в то же время. Например:

// pages/posts/[id].js
function Post(props) {
	const { postData } = props;
  
  return <div>{postData.title}</div>
}

export async function getStaticPaths() {
  const paths = await fetch('https://.../posts');
  return {
    paths,
    // 页面请求的降级策略,这里是指不降级,等待页面生成后再返回,类似于 SSR
    fallback: 'blocking'
  }
}

export async function getStaticProps({ params }) {
  // 使用 params.id 获取对应的静态数据
  const postData = await getPostData(params.id)
  return {
    props: {
      postData
    },
    // 开启 ISR,最多每10s重新生成一次页面
    revalidate: 10,
  }
}

На этапе компиляции и построения приложения будет создана определенная статическая страница, которая соответствует описанному выше процессу выполнения SSG.

существуетgetStaticPropsОбъект, возвращаемый функцией, добавляетсяrevalidateАтрибут, указывающий, что ISR включен. В приведенном выше примере укажитеrevalidate = 10, что означает, что статический HTML-код обновляется не чаще одного раза в 10 секунд. Когда браузер запрашивает страницу, которая была обработана во время создания, сначала возвращается кешированный HTML-код. Через 10 секунд начинается повторная визуализация страницы. После успешного создания страницы кэш обновляется. Когда браузер снова запрашивает страницу , он может получить последний обработанный HTML-контент страницы.

Статический HTML генерируется сразу же, когда браузер запрашивает страницу, которая не была создана во время сборки. Во время этого процессаgetStaticPathsвернутьfallbackПоле имеет следующие параметры:

  • fallback: 'blocking': Не понижайте версию и требуйте от пользователей ожидания до окончания статической генерации новой страницы, а статическая страница будет кэширована после окончания генерации.
  • fallback: true: Понизить версию, сначала вернуться на страницу с пониженной версией, когда статическая страница создается, она вернет JSON для использования CSR страницы понижения, после второго рендеринга выходит полная страница.

В приведенном выше примере используется схема без понижения версии (fallback: 'blocking'), которая на самом деле похожа на схему SSR, обе блокируют рендеринг, но с большим объемом кэша.

If fallback is 'blocking', new paths not returned by getStaticPaths will wait for the HTML to be generated, identical to SSR (hence why blocking), and then be cached for future requests so it only happens once per path.

Не все сценарии подходят для использования ISR. Для сценариев с высокими требованиями к работе в реальном времени, таких как новостные и информационные веб-сайты, SSR может быть лучшим выбором.

Гибридный режим рендеринга

Next.js поддерживает не только SSR, SSG, CSR, ISR, но и сочетание режимов рендеринга. Три гибридных режима рендеринга описаны ниже.

SSR + CSR

Как упоминалось выше, SSR, кажется, решила проблемы, вызванные CSR, так что от CSR вообще нет никакой пользы? Вообще-то нет. При использовании CSR переключение страниц не требует обновления, и нет необходимости повторно запрашивать содержимое всего HTML. В этом случае каждый может воспользоваться своими сильными сторонами и компенсировать свои недостатки, поэтому есть решение SSR + CSR:

  • Загрузка первой страницы — SSR: при этом обеспечивается скорость загрузки первого экрана и соответствие требованиям SEO.
  • Страница переключается на CSR: Next.js инициирует сетевой запрос, выполняетgetServerSidePropsфункция, после получения возвращаемых ею данных страница отображается

Органичное сочетание этих двух факторов может значительно снизить нагрузку и стоимость внутреннего сервера и в то же время повысить скорость переключения страниц и еще больше улучшить взаимодействие с пользователем. Помимо Next.js, есть и другие фреймворки, которые также используют схему SSR + CSR, напримерice.jsЖдать.

SSG + CSR

Как упоминалось выше, SSR требует больших затрат на эксплуатацию и обслуживание сервера. Для некоторых статических веб-сайтов или веб-сайтов с более низкими требованиями к реальному времени нет необходимости использовать SSR. Если вместо SSR используется SSG, лучше использовать схему SSG + CSR:

  • Статический контент проходит через SSG: для относительно статического контента на странице, такого как панель навигации, макет и т. д., статический HTML может быть предварительно обработан при компиляции и сборке.
  • Динамический контент переходит в CSR: обычно вuseEffectзапрашивать интерфейс для получения динамических данных, а затем повторно отображать страницу

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

SSG + SSR

Как упоминалось в представленной выше схеме ISR, суть ISR заключается в SSG + SSR:

  • Статический контент проходит через SSG: относительно статические страницы предварительно визуализируются для генерации HTML при компиляции и сборке, а статический HTML возвращается напрямую, когда браузер запрашивает
  • Динамический контент проходит через SSR: браузер запрашивает страницу, которая не была предварительно обработана, генерирует страницу с помощью SSR-рендеринга во время выполнения, затем возвращается в браузер, кэширует статический HTML и возвращается непосредственно при следующем попадании в кеш.

По сравнению с SSG + CSR, ISR может напрямую отображать динамический контент, что еще больше улучшает опыт доступа к странице в первый раз; по сравнению с SSR + CSR, он уменьшает ненужный статический рендеринг страницы и экономит некоторые затраты на внутренние серверы.

Суммировать

В этой статье сначала представлены три режима предварительного рендеринга, предоставляемые Next.js: SSR, SSG, ISR, а также объясняются их преимущества и недостатки, а также сценарии, для которых они могут подойти. Три гибридных режима рендеринга, которые в настоящее время поддерживаются Next.js, представлены позже и сравниваются с другими режимами рендеринга.

В общем, идеального решения для рендеринга не существует, и компромиссы и компромиссы необходимо делать в соответствии с реальной сценой.

Ссылка на ссылку: