Что такое SSR
SSR – (с англ. Server Side Rendering) технология, позволяющая выполнять на сервере JavaScript код для достижения каких-либо целей.
Зачем нужен SSR и что такое SEO
SSR в первую очередь необходим для продвижения сайта в интернете. Есть такое направление в маркетинге как SEO. И чаще всего, SSR необходим именно для этого.
SEO – (с англ. Search Engine Optimization) это оптимизация сайта под нужды поисковой системы. Само по себе, SEO продвижение – это целое самостоятельное направление в маркетинге с большой концентрацией капитала бизнеса, поэтому для многих это очень важная тема. Особенно если бизнес генерирует деньги в интернете.
Видите ли, когда поисковый робот делает запрос к сайту, сделанному на реактивных фреймворках по типу: Vue, React, Angular, то он видит примерно это:
Никакого контента, только полупустой HTML. Хотя, если зайти на сайт с точки зрения обычного человека, мы увидим много текста и картинки.
А вот та же самая страница, но с уже включенным SSR:
Как видите, тут контент есть. Что вообще происходит?
Все просто – сайты, сделанные на JavaScript, обычно, инициализируются в реальном времени на стороне клиента. То есть, в браузере у пользователя. Поэтому поисковая система просто не может грамотно считать контент сайта, и значит, дать ему корректное место в поисковой выдаче. Тут вряд ли можно рассчитывать на первое место.
Автор не прав, поисковые системы индексируют JavaScript сайты…
Раздел для тех, кто где-то видел или читал какие-то новости на этому тему. Да, вы в целом правы. Но есть огромное но…
Поисковые системы это делают крайне неохотно, в том же Google можно ждать индексации сайта неделями, а то и месяцами. SEO-специалисты, как представители бизнеса, просто затюкают бедного программиста разными вопросами. Ведь им нужно быстро, здесь и сейчас.
Дьявол кроется в деталях. Чтобы поисковой системе проиндексировать JavaScript-сайт, ей нужны большие мощности. Сначала нужно сделать запрос к сайту, понять, что тут нет контента и это JavaScript-сайт. После этого надо выкачать сайт, куда-то сложить, запустить исполнительную среду JavaScript и только потом считать контент.
А теперь представьте классический сайт на PHP, C#, Python. Сделал запрос – получил контент. Все.
Как рендерить JavaScript на сервере
С помощью Node.js. Не любите Node.js? Извините, других способов у нас для вас нет.
Хотя внутри Node.js за исполнение JavaScript отвечает движок V8, можете его скачать с GitHub и засунуть в свой проект. Только учтите: V8 написан на С++. Как вы свяжите между собой кучу инструментов, мы представляем лишь примерно, но точно можем сказать что вам будет очень «весело».
Технически, возможно добавить SSR и в Laravel + Vue проект (помним, Laravel это PHP), но это будет выглядеть как-то так. Сомнительный монолит получится. Да и вам все равно потребуется Node.js, как ни крути. Так что, будем работать с Node.js.
Добавляем SSR во Vue приложение
Перед тем как начать, мы с вами сейчас создадим простое двухстраничное Vue-приложение. Это нужно лишь для того, чтобы вы поняли принцип рендеринга контента. Можете взять свое, но лучше давайте начнем вместе с простой базы, так вы сделаете меньше ошибок и будет понятно, что за что отвечает. А иначе, вопросов будет просто миллион.
Создаем Vue приложение
Инициализируем Vue приложение с помощью команды:
Далее нам зададут некоторые вопросы, отвечаем на них:
- Project name. Пишите любое.
- Add TypeScript? Нет.
- Add JSX Support? Нет.
- Add Vue Router for Single Page Application development? Обязательно да.
- Add Pinia for state management? Нет, если надо, позже сами добавите.
- Add Vitest for Unit Testing? Нет.
- Add an End-to-End Testing Solution? Нет.
- Add ESLint for code quality? Как хотите, автор использует всегда.
- Add Prettier for code formatting? Как хотите.
Теперь переходим в папку с проектом, устанавливаем пакеты и запускаем приложение в режиме разработки (команды вводите по порядку):
У нас с вами появился такой проект, который нужен:
Мы имеем App.vue
как шаблон и несколько страниц добавленных через router/index.js
: HomeView.vue
и AboutView.vue
.
Если мы сейчас нажмем в браузере «Посмотреть код страницы», то не увидим никакого текста в нашем базовом приложении:
Хотя в компонентах текст есть:
Создаем сервер для рендеринга JavaScript
Для начала идем в package.json и добавляем туда строчку:
Должно получится как-то так:
Это для того чтобы в Node.js файлах использовать конструкцию import
.
Теперь надо создать сервер. Пусть будет Express:
В папке src создайте файл server.js
со следующим содержимым:
Давайте обсудим, что же здесь написано. Это очень важно.
На 22 строке функция start()
запускает Express-сервер, предварительно запуская внутри себя Vite-сервер на 29 строке. Сам Vite-сервер – это некое дополнительное приложение, которое умеет компилировать Vue-файлы.
По идее, если через Node.js вызвать файл:
в котором будем import
файла с расширением .vue
, то произойдет ошибка, так как нам нужно заранее предсобрать наше приложение особым способом через Vite (что мы и делаем).
Вообще, вся магия происходит с 40 по 51 строчку. В первую очередь, с помощью функции getIndexHTML()
, которую мы чуть выше реализовали. Мы берем наш index.html
из корня проекта, для того чтобы через регулярные выражения в нужное место установить отрендеренный контент. Да, нам нужно немного модернизировать index.html
. Для этого вставьте под тег title
конструкцию:
И между <div id="app"></div>
конструкцию:
Должно выйти так:
В preload-links
полетят стили и еще всякие полезные ссылки, собираемые Vite. А в app-html
, собранное с помощью SSR, – приложение.
Кого-то может смутить пустая переменная manifest
. Все так и должно быть. Это не конечный вид файла, и чтобы вас не запутать, мы даем информацию постепенно.
За сам рендер JavaScript отвечает функция vite.ssrLoadModule()
. В нее мы передаем путь до нашей специальной версии приложения – entry point
для SSR. Да, мы сейчас говорим про файл main-server.js
, которого у вас еще нету.
В папке src
создайте еще один файл main-server.js
с таким содержимым:
По документации Vite, функция vite.ssrLoadModule()
возвращает другие экспортируемые функции из передаваемого файла. Поэтому внутри main-server.js
мы объявляем функцию render()
и в ней напишем классический SSR сервер из документации Vue.js.
Сама функция render()
будет вызываться из файла server.js
.
Внутри main-server.js
у многих могут вызывать вопросы две функции: renderPreloadLinks()
и renderPreloadLink()
. Хотя они и выглядят страшно, но на самом деле выполняют простую роль: они помогают нам и подготавливают ссылки на .css
файлы. Все ссылки на чанки стилей будут находиться в манифесте. Мы его просто тут читаем. Понимаем, вопросов много, но пока у нас нет манифеста, мы его сделаем чуть позже, и все станет сразу в разы понятней.
К сожалению, это еще не все (хотя уже финишная прямая). Даже если мы сейчас попытаемся запустить сервер, то ничего хорошего не произойдет. Нам надо еще перенастроить наш router/index.js
. Для этого откройте этот файл.
Смотрите на 5 строку, раздел history
. Тут используется функция createWebHistory()
. Под капотом у этой функции есть использование глобальных переменных document
и window
. Только вот беда: когда мы будем собирать наше приложение через SSR-мод с помощью Node.js, мы не сможем обратиться к этим переменным. Просто потому, что в Node.js нет их. Вместо window
в Node.js есть global
и process
, но там совсем другое содержимое. А document
вообще является DOM API, которого тем более там нет… это же не браузер.
Поэтому мы должны поменять createWebHistory()
на сreateMemoryHistory()
, но только для SSR, дабы в обычном режиме приложение не сломалось. Поэтому модернизируйте файл router/index.js
таким способом:
Теперь можете запустить наше творение командой:
Во-первых, сервер запустился под адресом localhost:3000
, и если вы перейдете на него и откроете исходный код, то увидите результат своего труда:
Первый заход на сайт будет отдавать контент компонента, на который мы попали. На клиентской стороне реактивность сохраняется за счет гидрации.
Во-вторых, если нажимать F5, то как-то некрасиво встают стили. Мы это исправим за счет манифеста. В режиме разработки мы поработаем и так, а для production сделаем все чуть красивее.
В-третьих, если вы меняете файлы, Vite подхватывает изменения и делает Hot Reload. Ну, кроме файла server.js
… тут, если хотите, то же самое – надо поставить nodemon и запускать server.js
уже через него. Как-то так:
P.S: Это по желанию.
Финал: сборка для production
Замените содержимое server.js
на новое:
Тут не так много правок, как может показаться. В самом вверху мы добавили переменную isProd
.
С помощью этой переменной мы будем понимать в каком режиме мы сейчас функционируем. По-хорошему, для production нужно заранее собрать наше приложение через Vite и больше не использовать Vite сервер (там ведь много лишнего под капотом). После сборки наше приложение помещается в папку dist
и мы будем просто тянуть файлы оттуда. Посмотрите на строки 20, 28, 36 и 57. Тут как раз у нас еще и манифест появился.
Теперь давайте соберем наше приложение в боевом режиме. Давайте внесем корректировки в package.json
:
Должно получится так:
Теперь вместо:
Можно использовать:
А для production есть команда:
Но только перед тем как ее запустить, выполните команду:
Ибо без сборки нечего «обслуживать».
В целом на этом все, можем поздравить вас с реализацией своего SSR без всяких фреймворков.
Бонус: альтернативные способы внедрения SSR
Вообще, если лень проходить по этому туториалу и все кажется слишком сложным, то можно рассмотреть готовые инструменты для внедрения SSR.
Например, в рамках Vue 3 существуют такие инструменты как Nuxt и Quasar. Данные инструменты позволяют не создавать всякие Express сервера, а просто работать с Vue, как привыкли. Минусы такого подхода лишь в том, что не вы сами настраиваете Express сервер, а разработчик фреймворка. Поэтому, вы, как программист, придерживаетесь чужой логики (но это не всегда плохо).
Итог
Надеемся, этот душный туториал не прошел зря, и вы научились магии SSR в JavaScript. Вот ссылка готового проекта на GitHub. Если будут вопросы, пишите в комментариях, автор постарается помочь.
Комментарии