Статьи

Nuxt.js: минималистичный каркас для создания универсальных приложений Vue.js

Хотите узнать Vue.js с нуля? Получите полную коллекцию книг Vue, охватывающих основы, проекты, советы и инструменты и многое другое с SitePoint Premium. Присоединяйтесь сейчас всего за $ 14,99 / месяц .

Универсальный (или изоморфный) JavaScript — это термин, который стал очень распространенным в сообществе JavaScript. Он используется для описания кода JavaScript, который может выполняться как на клиенте, так и на сервере.

Многие современные JavaScript-фреймворки, такие как Vue.js , нацелены на создание одностраничных приложений (SPA). Это сделано, чтобы улучшить взаимодействие с пользователем и сделать приложение более быстрым, поскольку пользователи могут видеть обновления страниц мгновенно. Хотя у этого есть много преимуществ, у него также есть несколько недостатков, таких как длительное «время до контента» при первоначальной загрузке приложения, когда браузер получает пакет JavaScript, а некоторые поисковые роботы поисковых систем или роботы социальных сетей не будут увидеть все загруженное приложение, когда они сканируют ваши веб-страницы.

Рендеринг JavaScript на стороне сервера подразумевает предварительную загрузку приложений JavaScript на веб-сервере и отправку визуализированного HTML-кода в качестве ответа на запрос браузера на страницу.

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

Что такое Nuxt.js

Проще говоря, Nuxt.js — это фреймворк, который помогает вам легко создавать серверные приложения Vue.js. Он абстрагирует большую часть сложной конфигурации, связанной с управлением такими вещами, как асинхронные данные, промежуточное программное обеспечение и маршрутизация. Это похоже на Angular Universal для Angular и Next.js для React .

Согласно документам Nuxt.js , «его основная сфера действия — рендеринг пользовательского интерфейса при абстрагировании от распределения клиент / сервер».

Статическая генерация

Еще одна замечательная особенность Nuxt.js — возможность генерировать статические веб-сайты с помощью команды generate . Это довольно круто, и предоставляет функции, похожие на популярные инструменты генерации статики, такие как Jekyll

Под капюшоном Nuxt.js

В дополнение к Vue.js 2.0, Nuxt.js включает в себя следующее: Vue-Router , Vuex (включается только при использовании опции сохранения ), Vue Server Renderer и vue-meta . Это замечательно, так как избавляет от необходимости вручную включать и настраивать различные библиотеки, необходимые для разработки приложения Vue.js, предоставляемого сервером. Nuxt.js делает все это из коробки, сохраняя общий размер 57kB min + gzip (60KB с vuex).

Nuxt.js также использует веб-пакет с vue-loader и babel-loader для объединения, разделения кода и минимизации кода.

Как это устроено

Вот что происходит, когда пользователь посещает приложение Nuxt.js или переходит на одну из его страниц через <nuxt-link> :

  1. Когда пользователь первоначально посещает приложение, если в nuxtServerInit определено действие nuxtServerInit, Nuxt.js вызовет его и обновит хранилище.
  2. Затем он выполняет любое существующее промежуточное программное обеспечение для посещаемой страницы. Nuxt сначала проверяет файл nuxt.config.js наличие глобального промежуточного программного обеспечения, затем проверяет соответствующий файл макета (для запрашиваемой страницы) и, наконец, проверяет страницу и ее дочерние элементы на nuxt.config.js промежуточного программного обеспечения. Промежуточное программное обеспечение имеет приоритет в этом порядке.
  3. Если посещаемый маршрут является динамическим, и для него существует метод validate() , маршрут проверяется .
  4. Затем Nuxt.js вызывает asyncData() и fetch() для загрузки данных перед отображением страницы. Метод asyncData() используется для извлечения данных и их рендеринга на стороне сервера, а метод fetch() используется для заполнения хранилища перед рендерингом страницы.
  5. На последнем этапе отображается страница (содержащая все необходимые данные).

Эти действия правильно отображаются в этой схеме, полученной из документов Nuxt:

Nuxt.js Schema

Создание бессерверного статического сайта с Nuxt.js

Давайте запачкаем руки небольшим кодом и создадим простой статически сгенерированный блог с Nuxt.js. Мы будем предполагать, что наши сообщения извлекаются из API, и будем имитировать ответ статическим файлом JSON.

Для правильного следования необходимы рабочие знания Vue.js. Вы можете проверить отличное руководство по началу работы с Vue.js 2.0 Джека Франклина, если вы новичок в этой среде. Я также буду использовать синтаксис ES6, и вы можете получить информацию об этом здесь: sitepoint.com/tag/es6/ .

Наше финальное приложение будет выглядеть так:

Nuxt SSR Blog

Весь код этой статьи можно увидеть здесь, на GitHub , и вы можете посмотреть демо здесь .

Настройка и настройка приложения

Самый простой способ начать работу с Nuxt.js — это использовать шаблон, созданный командой Nuxt. Мы можем быстро установить его в наш проект ( ssr-blog ), используя vue-cli :

 vue init nuxt/starter ssr-blog 

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

Примечание. Если у вас не установлен vue-cli, сначала вам нужно запустить npm install -g @vue/cli , чтобы установить его.

Далее мы устанавливаем зависимости проекта:

 cd ssr-blog npm install 

Теперь мы можем запустить приложение:

 npm run dev 

Если все пойдет хорошо, вы сможете посетить http: // localhost: 3000 и увидеть начальную страницу шаблона Nuxt.js. Вы даже можете просмотреть исходный код страницы, чтобы увидеть, что весь контент, сгенерированный на странице, был обработан на сервере и отправлен в виде HTML в браузер.

Далее мы можем сделать несколько простых настроек в файле nuxt.config.js . Мы добавим несколько вариантов:

 // ./nuxt.config.js module.exports = { /* * Headers of the page */ head: { titleTemplate: '%s | Awesome JS SSR Blog', // ... link: [ // ... { rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css' } ] }, // ... } 

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

Мы также применили мой текущий CSS-фреймворк, Bulma , чтобы воспользоваться некоторыми предустановленными стилями. Это было сделано с помощью опции link .

Примечание. Nuxt.js использует vue-meta для обновления заголовков и атрибутов HTML наших приложений. Таким образом, вы можете взглянуть на это для лучшего понимания того, как устанавливаются заголовки.

Теперь мы можем сделать следующие несколько шагов, добавив страницы и функции нашего блога.

Работа с макетами страниц

Сначала мы определим пользовательский базовый макет для всех наших страниц. Мы можем расширить основной макет Nuxt.js, обновив файл layouts/default.vue :

 <!-- ./layouts/default.vue --> <template> <div> <!-- navigation --> <nav class="navbar has-shadow" role="navigation" aria-label="main navigation"> <div class="container"> <div class="navbar-start"> <nuxt-link to="/" class="navbar-item"> Awesome JS SSR Blog! </nuxt-link> <nuxt-link active-class="is-active" to="/" class="navbar-item is-tab" exact>Home</nuxt-link> <nuxt-link active-class="is-active" to="/about" class="navbar-item is-tab" exact>About</nuxt-link> </div> </div> </nav> <!-- /navigation --> <!-- displays the page component --> <nuxt/> </div> </template> <style> .main-content { margin: 30px 0; } </style> 

В нашем пользовательском базовом макете мы добавляем заголовок навигации сайта. Мы используем компонент <nuxt-link> для создания ссылок на маршруты, которые мы хотим иметь в нашем блоге. Вы можете проверить документы на <nuxt-link> чтобы увидеть, как это работает.

Компонент <nuxt> действительно важен при создании макета, поскольку он отображает компонент страницы.

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

Простые страницы и маршруты

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

Создание домашней страницы блога

Мы можем добавить домашнюю страницу нашего блога, обновив файл index.vue сгенерированный шаблоном Nuxt.js в каталоге pages:

 <!-- ./pages/index.vue --> <template> <div> <section class="hero is-medium is-primary is-bold"> <div class="hero-body"> <div class="container"> <h1 class="title"> Welcome to the JavaScript SSR Blog. </h1> <h2 class="subtitle"> Hope you find something you like. </h2> </div> </div> </section> </div> </template> <script> export default { head: { title: 'Home' } } </script> <!-- Remove the CSS styles --> 

Как указывалось ранее, указание опции title здесь автоматически вставляет ее значение в значение titleTemplate перед рендерингом страницы.

Теперь мы можем перезагрузить наше приложение, чтобы увидеть изменения на главной странице.

Создание страницы About

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

Мы можем проверить это, добавив простую страницу about.vue :

 <!-- ./pages/about.vue --> <template> <div class="main-content"> <div class="container"> <h2 class="title is-2">About this website.</h2> <p>Curabitur accumsan turpis pharetra <strong>augue tincidunt</strong> blandit. Quisque condimentum maximus mi, sit amet commodo arcu rutrum id. Proin pretium urna vel cursus venenatis. Suspendisse potenti. Etiam mattis sem rhoncus lacus dapibus facilisis. Donec at dignissim dui. Ut et neque nisl.</p> <br> <h4 class="title is-4">What we hope to achieve:</h4> <ul> <li>In fermentum leo eu lectus mollis, quis dictum mi aliquet.</li> <li>Morbi eu nulla lobortis, lobortis est in, fringilla felis.</li> <li>Aliquam nec felis in sapien venenatis viverra fermentum nec lectus.</li> <li>Ut non enim metus.</li> </ul> </div> </div> </template> <script> export default { head: { title: 'About' } } </script> 

Теперь мы можем зайти на http: // localhost: 3000 / about, чтобы увидеть страницу about, без необходимости перезапускать приложение, и это здорово.

Отображение сообщений блога на главной странице

Наша текущая домашняя страница довольно проста, так что мы можем сделать ее лучше, показывая последние сообщения из блога. Мы сделаем это, создав компонент <posts> и отобразив его на странице index.vue .

Но сначала мы должны получить сохраненные записи в блоге JSON и поместить их в файл в корневой папке приложения. Файл можно скачать отсюда , или вы можете просто скопировать JSON ниже и сохранить в корневой папке как posts.json :

 [ { "id": 4, "title": "Building universal JS apps with Nuxt.js", "summary": "Get introduced to Nuxt.js, and build great SSR Apps with Vue.js.", "content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>", "author": "Jane Doe", "published": "08:00 - 07/06/2017" }, { "id": 3, "title": "Great SSR Use cases", "summary": "See simple and rich server-rendered JavaScript apps.", "content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>", "author": "Jane Doe", "published": "17:00 - 06/06/2017" }, { "id": 2, "title": "SSR in Vue.js", "summary": "Learn about SSR in Vue.js, and where Nuxt.js can make it all faster.", "content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>", "author": "Jane Doe", "published": "13:00 - 06/06/2017" }, { "id": 1, "title": "Introduction to SSR", "summary": "Learn about SSR in JavaScript and how it can be super cool.", "content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>", "author": "John Doe", "published": "11:00 - 06/06/2017" } ] 

Примечание: в идеале сообщения должны быть получены из API или ресурса. Например, Contentful — это сервис, который можно использовать для этого.

Компоненты живут в каталоге components . Там мы создадим отдельный файл <posts> :

 <!-- ./components/Posts.vue --> <template> <section class="main-content"> <div class="container"> <h1 class="title has-text-centered"> Recent Posts. </h1> <div class="columns is-multiline"> <div class="column is-half" v-for="post in posts" :key="post.id"> <div class="card"> <header class="card-header"> <p class="card-header-title"> {{ post.title }} </p> </header> <div class="card-content"> <div class="content"> {{ post.summary }} <br> <small> by <strong>{{ post.author}}</strong> \\ {{ post.published }} </small> </div> </div> <footer class="card-footer"> <nuxt-link :to="`/post/${post.id}`" class="card-footer-item"> Read More </nuxt-link> </footer> </div> </div> </div> </div> </section> </template> <script> import posts from '~/posts.json' export default { name: 'posts', data () { return { posts } } } </script> 

Мы импортируем данные записей из сохраненного файла JSON и присваиваем их значению posts в нашем компоненте. Затем мы перебираем все записи в шаблоне компонента с помощью директивы v-for и отображаем нужные нам атрибуты записи.

Примечание. Символ ~ является псевдонимом для каталога / . Вы можете просмотреть документы здесь, чтобы увидеть различные псевдонимы, которые предоставляет Nuxt.js, и с какими каталогами они связаны.

Далее мы добавляем компонент <posts> на домашнюю страницу:

 <!-- ./pages/index.vue --> <template> <div> <!-- ... --> <posts /> </div> </template> <script> import Posts from '~/components/Posts.vue' export default { components: { Posts }, // ... } </script> 

Добавление динамических маршрутов

Теперь мы добавим динамические маршруты для сообщений, чтобы мы могли получить доступ к сообщению, например, с помощью этого URL: /post/1 .

Для этого мы добавляем каталог post каталог pages и структурируем его так:

 pages └── post └── _id └── index.vue 

Это генерирует соответствующие динамические маршруты для приложения, как это:

 router: { routes: [ // ... { name: 'post-id', path: '/post/:id', component: 'pages/post/_id/index.vue' } ] } 

Обновление файла одного сообщения:

 <!-- ./pages/post/_id/index.vue --> <template> <div class="main-content"> <div class="container"> <h2 class="title is-2">{{ post.title }}</h2> <div v-html="post.content"></div> <br> <h4 class="title is-5 is-marginless">by <strong>{{ post.author }}</strong> at <strong>{{ post.published }}</strong></h4> </div> </div> </template> <script> // import posts saved JSON data import posts from '~/posts.json' export default { validate ({ params }) { return /^\d+$/.test(params.id) }, asyncData ({ params }, callback) { let post = posts.find(post => post.id === parseInt(params.id)) if (post) { callback(null, { post }) } else { callback({ statusCode: 404, message: 'Post not found' }) } }, head () { return { title: this.post.title, meta: [ { hid: 'description', name: 'description', content: this.post.summary } ] } } } </script> 

Nuxt.js добавляет некоторые пользовательские методы для компонентов нашей страницы, чтобы упростить процесс разработки. Посмотрите, как мы используем некоторые из них на одной странице поста:

  • Проверьте параметр маршрута с помощью метода validate . Наш метод validate проверяет, является ли переданный параметр маршрута числом. Если он возвращает false , Nuxt.js автоматически загрузит страницу ошибки 404. Вы можете прочитать больше об этом здесь .
  • Метод asyncData используется для извлечения данных и их рендеринга на стороне сервера перед отправкой ответа в браузер. Он может возвращать данные разными способами. В нашем случае мы используем функцию обратного вызова для возврата сообщения, имеющего тот же атрибут id параметр id маршрута. Вы можете увидеть различные способы использования этой функции здесь .
  • Как мы уже видели, мы используем метод head для установки заголовков страницы. В этом случае мы меняем заголовок страницы на заголовок поста и добавляем сводку поста в качестве мета-описания страницы.

Отлично, теперь мы можем снова посетить наш блог, чтобы увидеть, как все маршруты и страницы работают должным образом, а также просмотреть исходный код страницы, чтобы увидеть генерируемый HTML. У нас есть функциональное серверное JavaScript-приложение.

Генерация статических файлов

Далее мы можем сгенерировать статические HTML-файлы для наших страниц.

Нам нужно сделать небольшую настройку, поскольку по умолчанию Nuxt.js игнорирует динамические маршруты. Чтобы сгенерировать статические файлы для динамических маршрутов, нам нужно явно указать их в файле ./nuxt.config.js .

Мы будем использовать функцию обратного вызова, чтобы вернуть список наших динамических маршрутов:

 // ./nuxt.config.js module.exports = { // ... generate: { routes(callback) { const posts = require('./posts.json') let routes = posts.map(post => `/post/${post.id}`) callback(null, routes) } } } 

Вы можете проверить здесь полную документацию по использованию свойства generate .

Чтобы сгенерировать все маршруты, теперь мы можем запустить эту команду:

 npm run generate 

Nuxt сохраняет все созданные статические файлы в папке dist .

Развертывание на хостинге Firebase

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

Сначала установите Firebase CLI, если у вас его еще нет:

 npm install -g firebase-tools 

Чтобы подключить локальный компьютер к учетной записи Firebase и получить доступ к проектам Firebase, выполните следующую команду:

 firebase login 

Это должно открыть окно браузера и предложит вам войти. Как только вы войдете в систему, посетите https://console.firebase.google.com и нажмите Добавить проект . Сделайте соответствующий выбор в открывшемся мастере.

После создания проекта перейдите на страницу хостинга проекта по адресу https://console.firebase.google.com/project/<project name>/hosting и завершите работу с мастером начала работы .

Затем на своем ПК из корневого каталога вашего проекта выполните следующую команду:

 firebase init 

В появившемся мастере выберите «Хостинг». Затем выберите ваш недавно созданный проект из списка вариантов. Затем выберите каталог dist в качестве публичного каталога. Выберите, чтобы настроить страницу как одностраничное приложение и, наконец, выберите «Нет», когда вас спросят, хотите ли вы перезаписать dist/index.html .

Firebase запишет пару файлов конфигурации в ваш проект, а затем запустит веб-сайт по адресу https://<project name>.firebaseapp.com . Демо-приложение для этой статьи можно увидеть на nuxt-ssr-blog.firebaseapp.com .

Если у вас возникнут проблемы, вы можете найти подробные инструкции на странице быстрого запуска Firebase .

Вывод

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

Фреймворк Nuxt.js действительно хорош. Это даже рекомендуется в официальном GitBook Vue.js SSR . Я действительно с нетерпением жду возможности использовать его в других проектах по БСО и изучить все его возможности.