Я использую Nuxt.js для проекта, над которым работаю уже некоторое время. Работая с Vue.js ранее, было не так уж сложно разобраться в происходящем, но между Vue.js и Nuxt.js есть некоторые существенные различия, которые важно понимать. В этой статье я рассмотрю три основных отличия от Vue, которые я испытал, и раскрою особенности, на которых нужно сосредоточиться при входе в мир Nuxt и рендеринга на стороне сервера.

Рендеринг на стороне сервера

Для тех, кто совершенно не знаком с Nuxt, он основан на Vue.js, но добавляет возможность отображать компоненты и данные на сервере, а не на клиенте. Основное преимущество, которое это дает, заключается в том, что контент вашего веб-приложения будет доступен при загрузке страницы, что позволяет поисковым системам, таким как Google, правильно индексировать контент вашего веб-сайта.

По крайней мере, это было то преимущество, которое я искал при выборе фреймворка для проекта, над которым я работал; для этого требовалось веб-приложение, которое содержало бы информацию, которую должны были обнаружить поисковые системы. Для этого проекта мне понадобился рендеринг на стороне сервера.

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

Маршрутизация и структура проекта

Создать новое приложение Nuxt стало очень просто с помощью инструмента командной строки create-nuxt-app. После создания нового приложения Nuxt я был готов приступить к разработке, но первое, что я заметил, это то, что папка проекта казалась отличной от обычного проекта Vue. Оказывается, эта структура проекта также связана с тем, как Nuxt обрабатывает маршрутизацию для приложения, и что очень важно понимать это при разработке приложений Nuxt.

Nuxt поставляется с каталогом pages/, который содержит все страницы приложения. Nuxt автоматически определяет маршрутизацию на основе именования этих страниц: например, если у вас есть файл в pages/user/posts.vue, это создаст маршрут к «/ user / posts» на вашем веб-сайте. Вы также можете создавать динамические маршруты, добавляя подчеркивание к имени файла Vue: pages/user/_post.vue

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

Получение данных

После создания нескольких страниц и компонентов пришло время заполнить приложение некоторыми данными из базы данных. В типичном приложении я бы получил эти данные с помощью запросов AJAX со стороны клиента. Очевидно, что этого решения будет недостаточно, поскольку эти данные будут извлекаться после отображения страницы, что исключает возможность для поисковых систем индексировать данные.

Эта проблема решена в Nuxt с помощью метода asyncData для предварительной выборки данных на сервере. Таким образом, данные уже вставлены в HTML, когда они поступают к клиенту, что делает их видимыми для поисковых систем.

Nuxt также рекомендует использовать Axios Nuxt для сетевых запросов вместе с asyncData. Работает хорошо и очень удобно:

asyncData({ $axios }) {
    const endpoints = [
      {url: '/api/posts', title: 'posts'},
      {url: '/api/comments', title: 'comments'},
    ]    
    const promises = endpoints.map((endpoint) => {
      return $axios.$get(endpoint.url)
    })
    return Promise.all(promises).then((res) => {
        const data = {}
        endpoints.forEach((endpoint, index) => {
          return data[endpoint.title] = res[index]
        })
        // Returns to the data() on the component, how convenient!
        return data
      }).catch((error) => {
        console.log(error)
      })
  }

Приведенный выше код передает asyncData метод Axios и создает массив обещаний, каждое из которых делает запрос к одной конечной точке URL. Затем все эти обещания обрабатываются, полученные данные помещаются в объект data и, наконец, возвращаются. Когда метод asyncData возвращает результат, он автоматически помещает полученные данные в хранилище компонентов data(), готовые к использованию. Очень удобно!

Компоненты рендеринга на стороне клиента

Наконец, проблема рендеринга компонентов на клиенте, а не на сервере. Это может показаться простым делом - и это так. Вы можете легко рендерить компоненты динамически, как и во Vue, но есть некоторые подводные камни, и их может быть сложно поймать.

Я обнаружил, что почесываю голову, когда обнаружил следующие загадочные сообщения об ошибках:

Не только это, но и то, как мои компоненты отображались (или не отображались) на странице. В конце концов я понял, почему это происходит.

Когда пользователь входит в систему, я сохраняю токен и объект «пользователь» на вкладках браузера localStorage. Если зарегистрированный пользователь посещает страницу, приложение захватывает этот токен и объект «пользователь» и показывает пользователю некоторые компоненты, которые доступны только аутентифицированным пользователям. Однако, поскольку все это происходит после того, как страница уже отрисована, он создает разные версии дерева DOM на клиенте и то, что было представлено сервером.

Для визуализации компонентов после загрузки страницы мы можем использовать теги элементов <client-only></client-only>. Это означает, что разметка между этими тегами будет отображаться только на стороне клиента, а не на сервере. После внедрения этого исправления ошибка исчезла, и компонент отрисовывается должным образом.

Заключение

Переход от Vue к Nuxt - это не большой переход, но понимание того, как работает SSR, может быть корректировкой. Надеюсь, вышеупомянутые ловушки помогут другим не повторять тех же ошибок, что и я!