Последние несколько месяцев я работал с Nuxt над пересборкой веб-приложения, написанного с помощью Express и Vue. Идея заключалась в том, чтобы рендеринг на стороне сервера и на стороне клиента обрабатывался в одном месте одной и той же структурой. А поскольку интерфейс уже был написан на Vue, естественно, Nuxt был фреймворком, который я выбрал (для приложений, написанных на React, я предлагаю взглянуть на Next).

Nuxt - относительно новая библиотека, поэтому иногда отсутствие документации и ресурсов может сильно расстраивать. Вот почему я постараюсь рассказать как можно больше о том, чему я научился на этом пути.

Примечание. В этой статье рассматривается Nuxt 2.x. Для этого требуются некоторые базовые знания Vue и Vuex.

О Nuxt и рендеринге на стороне сервера

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

Чтобы сделать взаимодействие пользователя с Интернетом как можно более плавным, появились приложения Singe Page (SPA). При использовании одностраничных приложений сервер визуализирует начальную страницу (часто пустую), а затем все остальное обрабатывается клиентскими скриптами. SPA позволяли создавать сложные веб-приложения, в которых все взаимодействия с пользователем, включая навигацию по страницам, обрабатывались на стороне клиента, а все взаимодействия на стороне сервера происходили через вызовы API.

В то время как SPA обеспечивал плавное взаимодействие с пользователем, рендеринг начальной страницы стал серьезной проблемой для производительности из-за необходимости загрузки и выполнения клиентских скриптов. Чтобы решить эту проблему, мы можем визуализировать html на стороне сервера и обслуживать его при загрузке первой страницы, чтобы пользователь сразу увидел страницу. Для этого и серверный html, и клиентский html должны выглядеть одинаково, так что когда один будет заменен другим, пользователь явно не увидит никакой разницы. Это означало, что сервер и клиент должны использовать одну и ту же логику для рендеринга страницы, что может быть эффективно достигнуто только при использовании одной и той же базы кода. Так появились серверные фреймворки рендеринга для SPA.

Nuxt является одним из них - это фреймворк на основе библиотеки Vue, который создает универсальное приложение, в котором и бэкэнд, и интерфейс используют одну и ту же кодовую базу. Вместо SPA, написанного на Vue, вы получаете полную настройку сервера, которая создает SPA, который использует рендеринг на стороне сервера (SSR).

SSR дает вам лучшее из обоих миров - плавную навигацию по страницам с помощью SPA и быструю загрузку начальной страницы. Это также делает ваше веб-приложение более удобным для поисковых роботов. Если вы хотите узнать больше по теме, я рекомендую вам прочитать Введение из Руководства по Vue SSR.

Быстрый старт и Webpack из коробки

Nuxt - это фреймворк, который означает, что в нем с самого начала для вас разобрано много вещей. Он поставляется с предустановленными Webpack, Vuex, Vue Router и vue-meta. Дело не только в том, что вам вообще не нужно иметь дело с настройкой Webpack (например, vue-cli также имеет настройку Webpack), но с Nuxt у вас есть как бэкэнд, так и интерфейс сразу из коробки, бесперебойно работающие вместе. Более того, такие вещи, как среда разработчика (включая горячую перезагрузку) и отображение изображений, работают без каких-либо дополнительных усилий.

Процесс установки очень простой и быстрый, все, что вам нужно сделать, это следовать официальной документации и выбрать один из двух подходов: либо использовать create-nuxt-app - инструмент для быстрого старта, либо начать с нуля и самостоятельно создать настройку проекта. . В конце концов, все, что вам нужно сделать, это запустить свой проект с npm run dev.

Nuxt генерирует для вас макет страницы (включая все передовые методы), поэтому вам не нужно беспокоиться / знать, где лучше всего разместить скрипты и CSS, чтобы обеспечить максимальную производительность сайта. Например, просмотрев вывод html, вы увидите, что скрипты добавляются в заголовок с rel="preload”:

Кроме того, они добавляются в конце тела с опцией defer:

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

Задача 1: добавление мета-тегов и значков

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

В Nuxt метатеги обрабатываются так же, как и во Vue, с помощью vue-meta - библиотеки, которая позволяет вам управлять метаинформацией вашего приложения в виде объекта. Это означает, что у вас нет прямого доступа к тегу <head>, вместо этого вам следует отредактировать head property в nuxt.config.js:

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

Атрибут hid здесь имеет решающее значение и играет ту же роль, что и атрибут vmid в библиотеке vue-meta. На основе свойства hid Nuxt понимает, что значение родительского метатега должно быть заменено значением дочернего метатега, а не просто конкатенировано.

Чтобы добавить значок, я попытался использовать тот же подход, следуя примеру для link рендеринга:

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

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

В конце концов, у вас должно получиться что-то подобное в вашем nuxt.config.js:

К сожалению, вместе с мета-тегами и ссылками в nuxt.config.js попадает и многое другое: переменные среды, внешние скрипты и даже конфигурация веб-пакетов. Идея, лежащая в основе конфигурации один для всего, вероятно, заключалась в том, чтобы сделать конфигурацию Nuxt как можно более простой и фиктивной, но на самом деле nuxt.config.js имеет внутри все мыслимые настройки, и он довольно длинный и трудный для чтения.

Задача 2: заставить магазин работать

Как и любой фреймворк, Nuxt очень самоуверен. К счастью, некоторые из этих мнений приносят пользу. Мне нравится, как Nuxt определяет структуру папок, решая за вас, где что разместить. Он следует так называемому подходу к конфигурации, а не к соглашению: если вы поместите модули в определенные папки, приложение будет работать с помощью некоторой магии Nuxt в фоновом режиме.

Например, Nuxt поставляется с уже интегрированным Vuex, но имейте в виду, что для того, чтобы магазин работал, вы должны следовать нескольким соглашениям, которые могут быть не очень очевидными с самого начала. Во-первых, вам нужно создать папку astore и выбрать один из двух режимов хранения - Классический режим и Режим модулей в зависимости от того, хотите ли вы, чтобы ваши модули были с пространством имен или нет.

Режим модулей сильно основан на соглашениях, что означает, что вам нужно только создать файлы с модулями внутри папки store, и Nuxt импортирует их за вас. В этом режиме в store/index.js вы должны экспортировать корневое состояние как функцию, а корневые мутации и действия как объект:

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

Если вы хотите больше контроля над магазином, вы можете выбрать классический режим. В этом случае вам придется самостоятельно импортировать модули хранилища и зарегистрировать их с помощью свойства modules (как вы обычно делаете это с Vuex). Для классического режима store/index.js также следует соблюдать соглашение и экспортировать метод, который возвращает экземпляр Vuex:

В обоих режимах структура файлов модулей одинакова и должны экспортировать state, actions и mutations:

Важно 1: обратите внимание, что состояние здесь является функцией. Я начал с объявления состояния как объекта и в конечном итоге столкнулся с поведением, что состояние не очищалось между перезагрузками страницы. Как сказано здесь:

Если мы используем простой объект для объявления состояния модуля, то этот объект состояния будет совместно использоваться по ссылке и вызовет перекрестное загрязнение состояния хранилища / модуля при его мутации.

Важно 2: если вы перемещаете приложение с Vue на Nuxt, не забудьте удалить импорт из хранилища внутри компонентов. Некоторые из моих страниц напрямую импортировали store и передавали его как свойство дальше (как вы обычно делаете это в приложении Vue). В итоге у меня было несколько экземпляров магазина. Проблема заключалась в следующем: Nuxt импортирует магазин за вас, поэтому вам не нужно делать это явно (Внимание: следующий код неверен):

Задача 3. Исправление полной перезагрузки страницы

Режим по умолчанию в приложении Nuxt - universal, что означает, что на стороне сервера будет отображаться SPA для внешнего интерфейса. Поэтому я был удивлен, увидев перезагрузку всей страницы при навигации по приложению. Причина оказалась простой (хотя я потратил некоторое время, пытаясь ее понять) - поскольку я переносил уже существующее приложение, у меня было много обычных <a href="link"> ссылок по всему проекту.

Очевидно, в Nuxt, если вы не хотите, чтобы при переходе между страницами выполнялась полная перезагрузка страницы, вам следует использовать только компонент <nuxt-link>. Таким образом, вы получите все преимущества SPA, предоставляемые вашим сервером.

Задача 4: добавление поддержки нескольких языков

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

Плагины запускаются перед инициализацией приложения Vue, поэтому они являются идеальным местом для выполнения кода раньше всего. Имейте в виду, что плагины будут выполняться дважды: один раз на стороне сервера и один раз на стороне клиента. Если вы знаете, что библиотека, которую вы включаете в плагины, будет использоваться только на стороне клиента, есть возможность явно отключить выполнение на стороне сервера с помощью параметра ssr:false.

В этом примере сначала мы инициализируем vue-i18n библиотеку внутри plugins/i18n.js файла:

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

Таким образом, вначале locale и fallbackLocale будут иметь одинаковое значение по умолчанию.

После плагинов - выполняется код из папки middleware. На стороне сервера промежуточное ПО вызывается один раз после плагинов и перед рендерингом страницы. А на стороне клиента промежуточное ПО вызывается каждый раз при изменении URL-адреса страницы. Это означает, что промежуточное ПО подходит для любой логики, основанной на изменении маршрута.

В нашем примере языковой стандарт является частью URL-адреса, поэтому всякий раз, когда он будет изменен на стороне клиента, будет выполняться код внутри промежуточного программного обеспечения, который зафиксирует мутацию, чтобы изменить значение языкового стандарта в магазине и изменить значение app.i18n.locale:

Заключение

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

TL;DR

  • Nuxt поставляется с полным набором настроек Webpack, средой разработчика и передовыми методами повышения производительности.
  • nuxt.config.js содержит все настройки проекта, включая свойство head, расширения Webpack и переменные среды.
  • Nuxt использует подход к конфигурации, а не соглашение, и интегрирует Vuex из коробки.
  • <nuxt-link> - единственный способ навигации без полной перезагрузки страницы
  • В Nuxt плагины запускаются перед промежуточным программным обеспечением как на стороне клиента, так и на стороне сервера, если вы не настроите их так, чтобы они не запускались на сервере с параметром конфигурации ssr: false

Спасибо, что прочитали эту статью. Пожалуйста, оставьте аплодисменты 👏 и поделитесь в твиттере, если сочтете это полезным! И я буду рад услышать любые отзывы.

📝 Прочтите этот рассказ позже в Журнале.

🗞 Просыпайтесь каждое воскресное утро и слышите самые интересные истории, мнения и новости недели, ожидающие в вашем почтовом ящике: Получите примечательный информационный бюллетень›