Введение

Последние несколько месяцев ни для кого не были легкими. Я надеюсь, что все и их семьи останутся здоровыми.

Чтобы поддержать новую инициативу компании и снизить затраты на привлечение пользователей, нашу команду инженеров попросили придумать решение для улучшения SEO (обычных результатов поиска).

В идеале мы хотим найти решение, которое поддерживает рендеринг на стороне сервера и обеспечивает достойную производительность в Интернете. Наши существующие приложения создаются как одностраничное приложение, которое обрабатывает всю визуализацию страниц на стороне клиента, а First Contentful Paint выполняется слишком долго из-за большого количества JavaScript, отправляемого в браузеры. Мы решили попробовать Next.js, учитывая, что он обеспечивает рендеринг на стороне сервера из коробки, а SSR должен повысить скорость загрузки страницы за счет снижения нагрузки на браузер. Однако путь не так прост. Я хочу поделиться несколькими проблемами и препятствиями, с которыми я столкнулся при создании нашего приложения Next.js.

Нет окна

Как разработчики, ежедневно работающие с Javascript и браузерами, мы обычно принимаем некоторые вещи как должное. Именно в нашем подсознании window объект всегда рядом, когда он нам нужен. Это не относится к Next.js. window является частью веб-API браузеров, а не частью ядра JavaScript. Для SSR Next.js выполняет первоначальный рендеринг на стороне сервера в Node.js, где объект window недоступен.

Для нашего исходного кода, который использует window или что-то, что исходит от веб-API, мы проверим, существует ли объект, прежде чем вызывать его.

if (typeof window !== 'undefined') {
  window.addEventListener('NAV_LOADED', () => handleInitNavData());
  window.addEventListener('resize', refreshNavHeight);
}

Для компонентов, которые мы хотим визуализировать только на стороне клиента, мы можем использовать Динамический импорт. ssr: false убедитесь, что компонент не обрабатывается на стороне сервера.

import dynamic from 'next/dynamic';
...

const Footer = dynamic(import('../../components/ui/Footer/Footer'), {
  ssr: false,
});

Вынос

Пакеты из node_module не могут быть обработаны таким образом. К сожалению, нам придется либо изменить способ использования библиотеки, либо заменить ее новой. Одним из примеров первой ситуации является react-media, нам пришлось зависеть от пользовательского агента из запроса, чтобы предоставить полунадежное значение по умолчанию, чтобы он знал размер экрана по умолчанию.

Где находится переменная среды

Разве это не просто process.env.MY_THING? Да, но это еще не все. Next.js предоставляет 3 различных типа переменных окружения.

const globalConfig = {
  env: {
    ASSET_PATH: isDevelopment ? '' : 'https://cdn.cloudfront.net/',
  },
  publicRuntimeConfig: {
    SEGMENT_ID,
  },
  serverRuntimeConfig: {
    CACHE,
  },
};

env: заменяет значение на времени сборки. process.env.ASSET_PATH будет заменено на https://cdn.cloudfront.net/, когда мы попытаемся сделать производственную сборку.

publicRuntimeConfig & serverRuntimeConfig: есть переменные времени выполнения, хороший пример — Next.js.

import getConfig from 'next/config'

// Only holds serverRuntimeConfig and publicRuntimeConfig
const { serverRuntimeConfig, publicRuntimeConfig } = getConfig()
// Will only be available on the server-side
console.log(serverRuntimeConfig.mySecret)
// Will be available on both server-side and client-side
console.log(publicRuntimeConfig.staticFolder)

function MyImage() {
  return (
    <div>
      <img src={`${publicRuntimeConfig.staticFolder}/logo.png`} alt="logo" />
    </div>
  )
}

export default MyImage

Вынос

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

Нет бесплатных файлов cookie

У меня возникла проблема, когда я начал работать с выборкой данных в приложении Next.js. У меня есть этот код, который делает GET запрос на получение информации о пользователе. Однако запрос не смог аутентифицировать пользователя в getServerSideProps.

// Fetch user context
async function fetchUser(req: IncomingMessage): Promise<UserContext | null> {
  let userContext: UserContext | null = null;
  try {
    // our custom API helper uses fetch internally
    userContext = await ApiService.get(
      `${process.env.WEB_HOST}/web-api/user/get`,
      {}, // params
    );
  } catch (error) {
    console.error('Unable to load user context', error);
  }
  return userContext;
}

export const getServerSideProps: GetServerSideProps = async ({ req }) {
  const userCtx = await fetchUser(req);
  return {
    props: {
      userCtx,
    },
  };
}

Вынос

Мы должны вручную передавать файлы cookie в запрос, который отправляется на наши конечные точки.

Для сервера Next.js:

await ApiService.get(
  `${process.env.WEB_HOST}/web-api/user/get`,
  {}, // params
  {
    // adding cookie to the new request
    cookie: req.headers.cookie,
  }
);

Другие вещи

  • Глобальную таблицу стилей можно добавить только в _app.js. Next.js автоматически использует ограниченный CSS (модуль CSS) для компонентов. Next.js — встроенная поддержка CSS
  • assetPrefix применяется только к сгенерированным ресурсам (JS, CSS, JSON...), он не оказывает никакого влияния на ресурсы (изображения, шрифты...) в папке public. Next.js - поддержка CDN
  • Чтобы лучше организовать наш код, мы можем переместить весь наш исходный код под src/.... Next.js - каталог Src

Последние мысли

Нам очень нравится Next.js. Он делает большинство вещей прямо из коробки. Мы уже начали перенос страниц с фокусом на SEO в это новое приложение Next.js, и это было здорово. С другой стороны, мы до сих пор не нашли решения для интеграции в нашу инфраструктуру некоторых функций Next.js, таких как Incremental Static Regeneration. Если вы недавно начали изучать Next.js, как и я, я надеюсь, что этот пост сэкономит вам время и сэкономит время на гугление.

Первоначально опубликовано на https://www.andrew-zheng.com 26 августа 2020 г.