Umbrella IT corporate blog
JavaScript
VueJS
October 2018 1

SSR: когда, зачем и для чего. На примере Vue

Tutorial

(Иллюстрация)

Once upon a time Несколько лет назад, когда я только начинал работать с вебом на Java, мы работали с JSP. Вся страница генерировалась на сервере и отправлялась клиенту. Но потом встал вопрос о том, что ответ приходит слишком долго…

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

И что же получается, история повторяется?

Какие есть принципы работы SSR?

1. Prerendering. В простейшем случае генерируется N HTML-файлов, которые кладутся на сервер и возвращаются как есть — то есть возвращается статика, во время запроса мы ничего не генерируем.



2. Как и в случае с JSP, на сервере генерируется полный HTML со всем контентом и возвращается клиенту. Но, чтобы не генерировать страницу на каждый запрос (коих может быть миллион и наш сервер загнется), давайте добавим кэш прокси. Например, варниш.



Когда может быть применим каждый из этих способов:

1. Когда имеет смысл генерировать пачку HTML-файлов? Очевидно, в том случае, когда данные на сайте меняются чуть реже чем никогда. Например, корпоративный сайт ларька по ремонту обуви, что за углом (да-да, тот дяденька, который меняет набойки в ларьке 2х2 метра, тоже захотел сайт фирмы — и, конечно же, со страницей миссии компании). Для такого сайта вообще не надо заморачиваться на предмет фреймворков, SSR и прочих свистелок, но это сферический пример. Что делать, если у нас блог, в котором 1к постов? Иногда мы их актуализируем, иногда добавляем новые. Сгенерировать 1к+ статичных файлов… Что-то не то. А если мы изменяем пост, то надо перегенерировать определенный файлик. Хм…

2. И вот тут нам подходит второй способ. Где мы генерируем первый раз на лету, а потом кэшируем ответ в проксирующем сервисе. Время кэширования может быть час/два/день — как угодно. Если у нас 10 000 заходов в час на пост (невероятно, правда?), то только первый запрос дойдет до сервера. Остальные получат в ответ кэшированную копию, и наш сервер с большей вероятностью будет жить. В случае обновления какого-то поста нам просто нужно сбросить закэшированную запись, чтобы по следующему реквесту сгенерировалась уже актуальная страница.

От слов к делу:


Hello world repo.

0) generate hello world

Для быстрого старта сообщество Nuxt подготовило базовые темплейты, установить любой из них можно командой:

$ vue init <template-name> <project-name>

По умолчанию предлагается started-template, его и возьмем для нашего примера. Хотя в реальном приложении мы выбрали express-template. Назовем проект незамысловато:

$ vue init nuxt-community/starter-template habr-nuxt-example
$ cd habr-nuxt-example
$ yarn # или npm install, как будет угодно
$ yarn dev

Вжух, мы сгенерировали hello world. Перейдя по урлу, можно увидеть сгенерированную страницу:
1) Webpack и Linting

Nuxt из коробки имеет настроенные вебпак с поддержкой ES6 (babel-loader), Vue однофайловые компоненты (vue-loader), а также SCSS, JSX и прочее.

Если этих возможностей недостаточно, конфиг вебпака можно расширить. Идем в nuxt.config.js, и в build.extend мы имеем возможность модифицировать конфиг.

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

Пример расширения конфига (подключение конфиг-файла для дева на основе переменной окружения):

config.plugins.push(
 new StylelintPlugin({
   files: [
     '**/*.vue',
     'assets/scss/**/*.scss'
   ],
   configFile: './.stylelintrc.dev.js'
 })
)

Остальные изменения можно посмотреть в репо по тегу, эти изменения помогут нам держать стили в порядке.

И пример конфиг-файла линтера: используем Standard JS, как общепринятое в Vue/Nuxt решение:

...
 extends: [
-    'plugin:vue/essential'
+    'standard',
+    'plugin:vue/recommended'
 ],
…

2) Для примера работы с данными будем использовать вот это API:

Подключим Axios как плагин, создаем новый файл в директории plugins:

import * as axios from 'axios'

let options = {}
// The server-side needs a full url to works
if (process.server) {
 options.baseURL = `http://${process.env.HOST || 'localhost'}:${process.env.PORT || 3000}`
}

export default axios.create(options)


И пример использования:

import axios from '~/plugins/axios'

export default {
 async asyncData ({ params }) {
   const { data } = await axios.get('https://jsonplaceholder.typicode.com/posts')

   return { data }
 }
}


Остальное в репе по тегу.

Цифры загрузки:

1) SSR + Varnish

Первый запрос:



Второй:



2) No-ssr



Второй реквест с фастли



Пустая страница пришла быстро, но потребовалось 2 секунды на то, чтобы сгенерировать на ней контент.

Conclusion


Что в итоге? Мы разобрались, как получить минимально сконфигурированное запускаемое SSR-приложение. Добавили Linting для сохранения стиля кода с самого начала жизни проекта, а также обозначили общую архитектуру. Можно писать свой гугол.
+11
18.1k 78
Comments 17
Top of the day