Server side rendering на Vue.js

  • Tutorial

Сравнительно недавно Vue.js обзавёлся полноценной поддержкой серверного рендеринга. В интернете довольно мало информации о том, как его правильно готовить, так что я решил подробно описать процесс создания необходимой среды для разработки приложения с SSR на Vue.js.


Всё, о чём пойдёт речь, реализовано в репозитории на github. Я буду часто ссылаться на его исходники и, собственно, попытаюсь объяснить, что происходит и зачем это нужно :)


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


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


Ведение


Основная идея любого приложения с SSR в том, что оно должно генерировать одинаковую HTML-разметку при выполнении на сервере и на клиенте.


Данные, которые подставляются в HTML, должны быть вытянуты по API, расположенному на том же или на другом сервере/домене. Настройка и разработка API-сервера выходит за рамки этой статьи, а вот в качестве клиента для него можно взять axios или любой другой изоморфный http-клиент.


Также нужно помнить о том, что на сервере нет DOM, так что все манипуляции с document, window и прочими navigator либо вообще не должны использоваться, либо должны быть запущены только на клиенте, то есть в хуках beforeMount, mounted и т.п.


Ниже будет много букв, где я пытаюсь разъяснить, что происходит в коде. Поэтому, если буквы покажутся вам сложно читаемыми, рекомендую сразу смотреть в код :) Ссылки на соответствующие части репозитория будут даны в каждом разделе.


Конфигурация Webpack


Код


Сборка делится на 3 основных конфигурации webpack — общая, сборка для сервера и сборка для клиента. После сборки мы должны получать 2 независимых бандла с набором файлов для клиента и лишь одним js файлом для сервера.


Для каждого бандла, очевидно, нужно будет создать отдельные entry, но об этом чуть позже.


Общая сборка (base.js) включает в себя загрузчики для всей статики, шаблонов, исходников JavaScript и vue-компонентов. Стили сюда включить теоретически тоже можно, но на сервере по очевидным причинам они не нужны, поэтому они будут прописаны только для клиента.


Клиентская сборка (client.js) добавляет к общей то, что необходимо нам в браузере. В rules прописываются загрузчики для css, stylus, sass, postcss и т.п.
Также сюда можно добавить output для разделения бандла на несколько файлов, extract css, uglify и т.д. В общем, всё как обычно :)
Сюда же добавляем генерацию общего HTML шаблона с помощью html-webpack-plugin. На нём я отдельно остановлюсь чуть ниже.


Сборка для SSR (server.js) должна создавать единственный js-файл для отработки на сервере. Нас не заботит размер файла, так как его никто не будет загружать по http, поэтому всё, что обычно прописывается в конфигах для оптимизации, здесь не имеет смысла.
Нужно также указать target: node, null-loader для стилей и externals. В externals указываются все пакеты из package.json, чтобы webpack не включал установленные пакеты в сборку, так как на сервере они будут подключены из node_modules.


{
    target: 'node',
    externals: Object.keys(require('../../package.json').dependencies)
}

Общий шаблон приложения


Код


Общий шаблон — это просто общая HTML-разметка, в которую будет вставлен отрендеренный код Vue приложения. Тут важно понимать, что сервер без специально обученных библиотек ничего не знает о DOM. Поэтому в шаблон нужно вписать некую строку, которая будет простой заменой подстроки заменена на разметку приложения. В примере это просто <!--APP--> (или //APP в pug), но она может быть любой другой.


Со скриптами, стилями и тегами в head немного проще — их мы с помощью той же замены будем вставлять перед </body>/</head>.


Сборка и сервер


Для работы SSR необходим сервер (express в примере) на Node.js, который также будет заниматься сборкой проекта на лету во время разработки. Тут много кода, так что будет проще посмотреть примеры точки запуска сервера и конфигурации сервера для разработки.


Несколько тонкостей:


  • Нужно подготовить общий шаблон таким образом, чтобы плагин vue-meta на клиенте понял, что разметка уже готова и не продублировал meta теги. Для этого нужно просто вставить специальный атрибут data-vue-meta-server-rendered без значения в тег <html>. Название атрибута настраивается, так что в вашем проекте оно может быть другим (я, например, решил заменить его на data-meta-ssr, так как это короче).
  • Также в шаблон нужно подставить всё необходимое из плагина vue-meta: атрибуты для html и body, мета-теги, link, noscript и т.д… В простейшем варианте это происходит примерно так:

// ...
const {
  title, htmlAttrs, bodyAttrs, link, style, script, noscript, meta
} = context.meta.inject()
res.write(`
  <!doctype html>
  <html data-vue-meta-server-rendered ${htmlAttrs.text()}>
    <head>
      ${meta.text()}
      ${title.text()}
      ${link.text()}
      ${style.text()}
      ${script.text()}
      ${noscript.text()}
    </head>
    <body ${bodyAttrs.text()}>
    ...
`)
// ...

  • Для корректной обработки серверного бандла (который был предварительно собран с помощью webpack'а) нужно использовать vue-server-renderer, которому нужно указать файл с бандлом и его кодировку. Подробнее о параметрах можно почитать в официальной документации. Там есть как минимум один интересный параметр runInNewContext, который позволит довольно неплохо оптимизировать рендеринг, но при соблюдении определённых правил (о чём речь пойдёт ниже, в разделе про точки входа).
  • Так как все данные из API загружаются во время рендеринга, то нет необходимости загружать их повторно на клиенте. Но клиент, очевидно, не может просто вынуть их из разметки, поэтому необходимо передать ему данные вместе с разметкой. Решается эта задача максимально просто: в разметку добавляется script, где все нужные данные записываются в переменные. Сами данные обрабатываются JSON.stringify или, ещё лучше, с помощью serialize-javascript.

const serialize = require('serialize-javascript')

// ...

res.write(`<script>
    window.__INITIAL_VUEX_STATE__=${serialize(context.initialVuexState)}
</script>`);

res.write(`<script>
    window.__INITIAL_COMP_STATE__=${serialize(context.initialComponentStates)}
</script>`);

Режим разработки


В случае запуска сервера в режиме разработки сам сервер будет работать примерно так же. Отличаются лишь 2 момента — по-другому обрабатываются ошибки, возникшие при рендеринге, а так же подменяется renderer и разметка общего шаблона на новые при изменении кода приложения.


Помимо самого сервера нужно запустить webpack(clientConfig).watch для генерации сборки на лету при изменении исходников. Перед этим инициализируется webpack со всеми нужными для разработки плагинами типа HotModuleReplacementPlugin.


Также нужно сообщать клиенту о новых сборках бандла. Для этого понадобятся webpack-dev-middleware и webpack-hot-middleware. Они отвечают за доставку изменившегося кода клиенту при появлении новых сборок (то есть каждый раз, когда изменяется исходный код приложения).


Отдельно запускается webpack(serverConfig).watch и подменяется серверный бандл на новый при его изменении. В моём случае сообщаем о том, что он изменился, с помощью простого коллбэка (строка 50 в build/setup-dev-server.js, строка 73 в index.js).


Точки входа для приложения


Код


Как я упоминал выше, необходимо создать 2 отдельные входные точки (entry в webpack) приложения для SSR и для клиента. Собственно, здесь так же, как и в конфигах webpack — 3 файла с общим, серверным и клиентским кодом.


Общий код (app.js) включает общую инициализацию приложения, то есть подключает Vue-плагины, создаёт vuex store, router и новый root-компонент. Также здесь регистрируются глобальные компоненты, фильтры и директивы.


Здесь же root-компоненту нужно подмешать vue-файл с шаблоном и логикой уже самого приложения, чтобы главный компонент приложения и root-компонент стали одним целым.
Важно, что для vue-server-renderer есть опция runInNewContext, которую можно отключить, получив при этом неплохой прирост производительности. Но для его использования необходимо каждый раз снова инициализировать приложение, поэтому в app.js я возвращаю функцию, производящую инициализацию, а не готовый объект Vue-компонента. Код же, исполняемый непосредственно в этом файле, будет выполнен только один раз при запуске сервера, о чём необходимо помнить. Здесь можно регистрировать общие моменты, не зависящие от данных, получаемых в рантайме — регистрировать компоненты, фильтры, директивы, извлекать переменные окружения и т.д. и т.п.


Точка входа для клиента (client.js). Здесь создаётся приложение с помощью функции из app.js, затем грузится и выполняется всё необходимое для корректной работы в браузере.
Здесь же производится замена объекта data для компонента, который должен быть показан на данной странице и состояния vuex store.


if (window.__INITIAL_VUEX_STATE__) {
    // полностью заменяем state на возвращённый сервером
    app.$store.replaceState(window.__INITIAL_VUEX_STATE__);
    delete window.__INITIAL_VUEX_STATE__;
}

if (window.__INITIAL_COMP_STATE__) {
    app.$router.onReady(() => {
            // берём все компоненты, которые показываются на данной странице 
            // (почти всегда это единственный компонент, но мало ли)...
        const comps = app.$router.getMatchedComponents()
            // ...забираем только те, у которых есть данные для предзагрузки
            .filter(comp => typeof comp.prefetch === 'function');
        for (let i in comps)
            if (window.__INITIAL_COMP_STATE__[i])
                // собственно, записываем данные для data
                // (сама подмена $data будет происходить в специальном миксине, о нём речь пойдёт ниже)
                comps[i].prefetchedData = window.__INITIAL_COMP_STATE__[i];
        delete window.__INITIAL_COMP_STATE__;
    });
}

Завершаем код тем, что берём root-компонент и вызываем у него $mount в корневой элемент приложения. Этому элементу будет автоматически дан атрибут data-server-rendered, поэтому можно сделать так: app.$mount(document.body.querySelector('[data-server-rendered]')).


Точка входа для SSR (server.js). Здесь просто создаётся функция, которая будет принимать контекст запроса (то есть объект request из express) и инициализировать приложение. Функция должна вернуть promise, который будет выполнен в тот момент, когда все необходимые данные загружены из API, а приложение будет готово к отправке клиенту.
Порядок действий в этой функций может быть таким (код):


  1. Создаём приложение из app.js.
  2. Настраиваем baseUrl в axios таким образом, чтобы он мог обратиться к серверу API локально (при необходимости). Здесь просто нужно помнить, что браузера нет, а значит и нет объекта location, из которого можно хотя бы взять домен и протокол, так что это нужно будет прописать вручную.
  3. Задаём обработчик для vue-router ready (app.$router.onReady(...)), который будет выполнен при нахождении соответствия компонентов и URL:
    1. Берём все асинхронные компоненты для данной страницы и выполняем их функции для вытягивания асинхронных данных. Собираем возращённые промисы в массив.
    2. Ждём выполнения всех промисов в Promise.all.
    3. Резолвим, добавляя к контексту информацию из vue-meta, vuex state, а так же записываем в компоненты и в контекст данные, полученные в результате выполнения асинхронных операций.
  4. Говорим роутеру, что пришло время обработать URL из контекста (app.$router.push(context.url)).

Далее все полученные данные будут обработаны http-сервером, компоненты отдадут свою разметку, данные с разметкой будут записаны в шаблон, получившийся HTML отправится клиенту.


Компоненты и роутинг


Код для регистрации роутера и компонентов для него.


Для разработки приложения с SSR нужно исходить из того, что только root-компонент или компоненты, которые привязаны к роутам, имеют возможность асинхронно загрузить данные перед рендерингом. Для этих компонентов специальным образом нужно обрабатывать изменения роута и записывать данные, которые вернул сервер после рендеринга. Для этих целей хорошим решением будет создать mixin, который автоматически подключается к каждому компоненту при инициализации роутера. Пример кода подобного mixin'а.


В prefetch-mixin нужно добавить примерно следующее:


  • created-хук, который будет брать поле prefetchData (при инициализации приложения в это поле пишется data компонента, пришедшая с сервера после рендеринга или просто записанная напрямую во время рендеринга на сервере) и полностью заменять значения полей this.$data на значения из this.constructor.extendOptions.prefetchData, но только до того, как приложение уже полностью инициализировано, что мы можем выяснить из поля this.$root._isMounted.
  • beforeMount-хук будет вызывать prefetch только на клиенте уже после загрузки страницы в том случае, если произошёл переход на другой роут.
  • beforeRouteUpdate-хук будет вызывать prefetch только на клиенте при изменении параметров роута.

function update(vm, next, route) {
    if (!route) route = vm.$route;
    const promise = vm.$options.prefetch({
        store: vm.$store,
        props: route.params,
        route
    });
    if (!promise) return next ? next() : undefined;
    promise
        .then(data => {
            Object.assign(vm.$data, data);
            if (next) next();
        })
        .catch(err => next && next(err));
}

const mixin = {
    // подмешиваем данные компонента при первичной загрузке страницы
    created() {
        if (this.$root._isMounted || !this.constructor.extendOptions.prefetchedData) return;
        Object.assign(this.$data, this.constructor.extendOptions.prefetchedData);
    },
    // вызываем prefetch при загрузке компонента (но не делаем ничего, если данные уже подмешаны в created)
    beforeMount() {
        if (this.$root._isMounted && this.$options.prefetch) update(this);
    }
    // вызываем prefetch, если изменился параметр роута
    // в этом случае компонент не будет проинициализирован заново, так что beforeMount вызван не будет
    beforeRouteUpdate(to, from, next) {
        if (this.$options.prefetch && to.path !== from.path) update(this, next, to);
        else next();
    },
};

Дальнейшая разработка


SSR не накладывает почти никаких ограничений на разработку приложений. Достаточно просто помнить о том, что нельзя использовать браузерное API там, где код выполняется на сервере, в остальных же случаях выносить код в клиентские хуки beforeMount/mounted.


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


Могут быть проблемы с директивами, роль которых часто сводится к манипуляции с DOM, но их легко решить, отдавая альтернативную реализацию (пустую?) вместо самой директивы на сервере (docs).


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

Поделиться публикацией
Похожие публикации
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама
Комментарии 37
  • 0
    А зачем вообще использовать серверный рендеринг?
    • +2
      Даёт все возможности SPA, не жертвуя при этом оптимизацией в поисковых системах.
      • 0
        Давно слежу за темой SSR, как-то пробовал настроить SSR с реактом, много матерился (из-за неопытности, конечно). Потом долго не работал с SPA-приложениями, а сейчас как раз потихоньку изучаю Vue, разрабатывая pet-project.

        В связи с этим вопрос: а у вас есть опыт, показывающий, что такая оптимизация реально помогает с поисковиками? Просто я уже много раз слышал, что, как минимум, гугловские боты умеют выполнять js, т.е. они уже давно не просто wget'ом страницы качают. Вот и думаю, может гугл/яндекс и так смогут мой сайт посмотреть и ранжировать его не хуже, чем «классические» сайты?
        • –1
          Ну на самом деле для SEO по сути кроме разметки ничего не нужно, а с этим SSR как раз и справляется, он для этого и создан. Так что да, с оптимизацией это не просто помогает, а является одним из способов оптимизировать в принципе :)
          Есть ещё пререндеринг, но серверный рендеринг — это его эволюция, то есть пререндеринг просто можно считать устаревшим подходом.

          Насчёт интерпретации js поисковиками я слышал, но я очень скептически к этому отношусь. Представьте, сколько мощностей нужно задействовать, чтобы за адекватное время запустить каждый говносайт со всем его кодом в масштабах гугла. Ну и плюс слышал, что эта дрянь пока что не очень хорошо работает — старый добрый HTML всё равно надёжнее. По крайней мере ближайшие лет 5 точно (имхо).
          • 0
            Пререндеринг скорее как возможная оптимизация для статичных страниц, поэтому ее считать устаревшей не совсем верно. Зачем мучить сервер заставляя генерировать его одно и тоже?
            • 0
              Ну если сайт не предполагал SSR при разработке, то иного пути просто нет, придётся использовать пререндеринг. Ну или переписать сайт :)
              Я имел в виду, что брать пререндеринг при разработке нового SPA — это устаревший подход.
          • 0
            Был где-то сайт, где проверялись приемы и подходы и как это влияет на поисковики. Попробуйте поискать, но насколько я помню SSR дает значительно лучший результата, так как даже при выполнении JS они не дожидаются многих асинхронных функций
            • +1
              Кратко — это всё провокация, поисковики не умеют индексировать JS сайты. И ещё долгое время не будут уметь.
              Они могут выполнять js на сайтах, но только для обнаружения текста или факта его видимости / невидимости, но это с поисковой оптимизацией ничего общего не имеет.
              • +1
                Поисковые боты умеют только в синхронный JS, ваших аяксов никто ждать не будет.
          • 0
            Спасибо, за статью.
            Недавно на хабре вышел пост habrahabr.ru/post/338612 про использование нескольких сборок.
            Можно-ли такой подход применить во Vue ssr?
            • 0
              Так SSR же никак не ограничивает количество бандлов — их хоть 100 может быть. Так что да, легко можно использовать такой подход. Не уверен, правда, что HtmlWebpackPlugin получится под это настроить.
            • 0
              На php разработку не веду, но так будет более понятно для примера.
              glot.io/snippets/eui1on1so3
              И не нужна нода на сервере.
              • +1
                А какая связь этого куска кода с серверным рендерингом?
                • 0
                  Пример, как можно сформировать html на сервере не исполняя клиентский код на нем.
                  • 0
                    Это я и так вижу :)
                    Но связи с серверным рендерингом по-прежнему не улавливаю :)

                    Неужели все, кто пытается реализовать SSR, не заметили, как, оказывается, всё элементарно?
                    • 0
                      Пожалуй комментарий и в правду далек от содержания вашей статьи. Но уж очень хочется сократить связку web server + nodejs + app server
                      • 0
                        Это, к сожалению, неизбежно, так как нужно уметь исполнять то же самое, что и браузер, а тут выбор невелик — только nodejs. Выход — писать на js вообще всё, в частности и API.
              • 0
                Для лучшего понимания происходящего имеется русская документация о серверном рендеринге в vue — vue-ssr
                • 0
                  Вы конечно сделали все по своему, хотя у vue есть инструменты для SSR «из коробки», подробнее по ссылке выше…
                  • 0
                    Почему же по-своему, я на неё и опирался, когда всё это делал. Просто там было далеко не всё, что нужно мне, да и вообще в любом более-менее серьёзном проекте. Не описано, как подмешивать состояния компонентов (только vuex state), ни слова про взаимодействие с API и т.п.
                    Правда, этого всего и не должно быть в документации, так как её цель — описать возможности, а не давать готовый код. Второе как раз и есть задача, которую я пытаюсь решить в этой статье.

                    Но было бы правильно оставить в статье ссылку на документацию, это я сделаю в ближайшее время.
                  • 0
                    [не в ту ветку]
                    • 0
                      А можно спросить умных людей что кроется за фразой «разрабатывать SPA держа в уме SSR» или может быть статья есть классическая?

                      Чтобы говорить более конкретно пусть будет пример: дашборд каких-нибудь биржевых индексов. Первое что приходит на ум: роутинг, чтобы было удобно указывать что же именно попадает под SSR (личные кабинеты, даже если они публичны, не интересны SEO). Что-то еще?
                      • 0
                        Если исходить из вашего примера, то да, SSR должен отдавать только контент для анонимусов, всё остальное определяется/грузится уже на клиенте.

                        Мало того, можно целые разделы рендерить исключительно на клиенте, типа тех же личных кабинетов со своими внутренними роутами (на Vue это делается очень просто). С сервера в таком случае приходит пустая страница или, скажем, какой-нибудь индикатор загрузки, а на клиенте уже получаем информацию о текущем пользователе (скажем, в хуке beforeMount или mounted, которые на сервере не вызываются) и выводим в зависимости от его наличия форму для входа или непосредственно личный кабинет (<router-view />).

                        В общем-то это всё, что нужно понимать, статья тут, мне кажется, не нужна :)
                        • 0
                          Ну а причем тут только SEO? Разве не очевидно, что у SSR значительно больше преимуществ? Например, более быстрая начальная загрузка страницы, без лишних индикаторов загрузки, возможность сделать нормальный «Progressive Enhancement» приложения, вплоть до полной поддержки работы без JS. Возможность сделать приложение максимально «environment agnostic». Имхо, это уже много, тем более с современными фреймверками это не слишком сложно, просто надо чуть больше заморочится.
                          • 0
                            Не знаю, в каких случаях реально нужно обходиться без JS. Сейчас даже на недорогих моделях телефонов можно открыть сайт на фреймфорке и без особых тормозов с ним работать.
                            Environment agnostic — тоже не сказал бы. Всё равно для чтения HTML нужен браузер, который поддерживает также и JS, так что никаких дополнительных ограничений, связанных со средой выполнения, JS не накладывает. Я ни разу не встречал живого человека, который был бы одновременно в своём уме и выключал JS в браузере :)
                            Единственное, с чем глупо не согласиться — скорость первичной загрузки. Но это в случае с SPA мелочь, ради которой не стоит заморачиваться с SSR.

                            В общем, по моему мнению SEO — единственная причина использовать SSR. Я пытался придумать другие реально веские причины для этого, но так ни к чему и не пришёл.
                            • 0
                              Не знаю, в каких случаях реально нужно обходиться без JS. Сейчас даже на недорогих моделях телефонов можно открыть сайт на фреймфорке и без особых тормозов с ним работать.

                              Ну во-первых, около 1% юзеров вообще не получают JS. Делал доклад на эту тему, могу найти пруф.
                              Я ни разу не встречал живого человека, который был бы одновременно в своём уме и выключал JS в браузере :)

                              «Видишь суслика, а он есть»))) Даже на хабре полно таких людей. Представьте себе остаются люди, которые просто отключают скрипты умышлено. В зависимости от специфики вашего приложения, таких людей можно или нельзя игнорить. Правда не понятно зачем это делать, если можно просто сделать Progressive Enhancement и пусть ваше приложение умеет работать вообще без JS на клиенте.

                              Единственное, с чем глупо не согласиться — скорость первичной загрузки. Но это в случае с SPA мелочь, ради которой не стоит заморачиваться с SSR.

                              Это вы так сейчас неудачно пошутили? А можете пояснить почему же для SPA — это мелочь?

                              Скрипты для сложных веб-приложений стали весить хренову тучу Мб, а значит если у вас чистый SPA, то ваши пользователи будут довольно долго «любоваться» классным загрузчиком. Особенно на слабой мобильной сети. И в этом смысле, нужно помнить что у вас есть всего 3 секунды, чтобы их заинтересовать, а значит 2-3Мб ваших скриптов на слабом мобильном интернете приведут ваше SPA в ситуацию, когда юзеры будут тупо закрывать его не дождавшись контента. Эта проблема легко решается применением SSR и изоморфных подходов.

                              Environment agnostic — тоже не сказал бы. Всё равно для чтения HTML нужен браузер, который поддерживает также и JS, так что никаких дополнительных ограничений, связанных со средой выполнения, JS не накладывает.


                              Есть всякие Cordova/Electron/etc. и у них немного разные принципы к построению приложения относительно того же веба. И там 3Мб скриптов не передаются по сети, а значит можно делать чистый SPA. Так где появляется сеть, я уже написал выше, поддержка SSR будет очень кстати. Юзая изоморфные подходы, вам не нужно думать как лучше поступить. Если вам нужен SSR и все его плюшки — юзаем, нужен чисто клиентский SPA — юзаем, нужен чистый серверный апп — юзаем. И нет проблем. Посмотрите кстати доклад Netflix как они ускорили сайт на 50% просто выпилив реакт с клиента и оставив его на сервере.

                              В общем, по моему мнению SEO — единственная причина использовать SSR. Я пытался придумать другие реально веские причины для этого, но так ни к чему и не пришёл.

                              Да если рассуждать как вы, то SPA и SEO не нужно. Вы же наверное из тех, кто делает SPA только для кабинетов и админок.)))) Хотя во многом это уже не так и лишать юзеров более публичных веб-приложения и даже веб-сайтов возможности находить их в поисковиках и при этом иметь быстрый интерфейс и UX, это довольно глупо, при таких то возможностях, которые мы имеем сейчас.
                              • 0
                                Ну во-первых, около 1% юзеров вообще не получают JS. Делал доклад на эту тему, могу найти пруф.

                                В каком плане не получают? Доклад посмотреть было бы интересно, да!

                                «Видишь суслика, а он есть» ...

                                Я и не утверждал, что таких людей нет. Просто их недостаточно много для того, чтобы только ради них внедрять SSR. Конечно, всё будет зависеть от ЦА, но сложно представить такую ЦА, где достаточно большая доля людей без JS.

                                Это вы так сейчас неудачно пошутили? А можете пояснить почему же для SPA — это мелочь? ...

                                Нет, я серьёзно :) По двум причинам:
                                — скрипты грузятся один раз и кэшируются, то есть при всех последующих загрузках страницы проблем с этим не будет
                                — в SPA нет явных физических переходов между страницами сайта/приложения, поэтому потерпеть придётся всего один раз при открытии ресурса

                                Скрипты для сложных веб-приложений стали весить хренову тучу Мб…
                                нужно помнить что у вас есть всего 3 секунды, чтобы их заинтересовать

                                Это легко решается с помощью code splitting в webpack. То есть я не утверждаю, что проблемы нет, но есть более простые альтернативные способы их решения. SSR же — стрельба из пушки по воробьям.

                                Есть всякие Cordova/Electron/etc. и у них немного разные принципы к построению приложения относительно того же веба ...

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

                                Да если рассуждать как вы, то SPA и SEO не нужно. Вы же наверное из тех, кто делает SPA только для кабинетов и админок.))))

                                Зачем же вы так меня обижаете :(
                                Я, наоборот, топлю за то, чтобы вообще любой проект сложнее бложика делать как SPA, а проблемы с SEO решать серверным рендерингом. При должной квалификации разработчиков в человекочасах потерь не будет (скорее наоборот), зато UI/UX получит значительный прирост.

                                Вообще, мой посыл не совсем в том, что не надо использовать SSR для чего-либо кроме SEO. Я говорю о том, что все остальные проблемы, которые решает SSR не стоят того, чтобы его внедрять, так как можно обойтись меньшей кровью.

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

                                Другое дело пересаживать на SSR какой-то существующий фронтенд, тут всё значительно сложнее.
                                • 0
                                  В каком плане не получают? Доклад посмотреть было бы интересно, да!

                                  Вот FYI: gds.blog.gov.uk/2013/10/21/how-many-people-are-missing-out-on-javascript-enhancement
                                  Доклад вроде где-то на YouTube доступен, если найду, пришлю в личку.
                                  Я и не утверждал, что таких людей нет. Просто их недостаточно много для того, чтобы только ради них внедрять SSR. Конечно, всё будет зависеть от ЦА, но сложно представить такую ЦА, где достаточно большая доля людей без JS.

                                  Ну я тоже не утверждал, что SSR нужно внедрять только ради них))) Это всегда совокупность факторов. Возможно в колличественном смысле ЦА не большая, зато может оказаться важной. Вообще не нужно игнорить людей, если есть такая возможность. Ну и опять же, может это и не главное преимущество SSR, но сильно повышает «accessibility» приложения.
                                  — скрипты грузятся один раз и кэшируются, то есть при всех последующих загрузках страницы проблем с этим не будет

                                  А если не грузятся? Не успели за 3 секунды — юзер закрыл ваш ресурс, JS не успел загрузиться.
                                  — в SPA нет явных физических переходов между страницами сайта/приложения, поэтому потерпеть придётся всего один раз при открытии ресурса

                                  Почему вообще 1 раз? Кэш браузера это прекрасно, но вы вообще не дописываете аппу свою? А значит, грузиться будет не один раз, а значит если вы код доработали, юзеру опять придется ждать))) Представляю текст загрузчика: «Подождите еще 10 секунд, а потом мы будем грузиться быстро» ))))))
                                  Это легко решается с помощью code splitting в webpack. То есть я не утверждаю, что проблемы нет, но есть более простые альтернативные способы их решения. SSR же — стрельба из пушки по воробьям.

                                  Code splitting is good. Но все же это не решает проблему полностью. Плюс применение этого подхода вообще обязательно, даже в изоморфном приложении. И это будет работать быстрее на каждую загрузку. Поэтому изоморфная аппа всегда будет быстрее на старте, чем чистый SPA. Ну а в процессе работы они будут одинаково быстры. И никаких воробьев там нет, если бы «code splitting» полностью решал проблему старта приложения, то она не была бы одной из самых острых в SPA.
                                  Ну для таких целей подозреваю (не уверен), что можно просто делать разные сборки одного и того же приложения. К тому же они будут существовать параллельно с SSR, так как они вообще не имеют прямого к нему отношения. Ну и JS эти технологии прекрасно исполняют (иначе зачем они вообще), так что это принципе не аргумент в данном случае.

                                  Блин, ну я же написал, что для веба и когда у вас файлы бегают по сети, применение SSR — это очень важно, но при этом это не важно Cordova/Electron/etc. И тут с изоморфным подходом вы можете сделать сборку для тех кому важен SSR и для тех, кому он не важен. Без изменения кода и без компромиссов с самим собой. Это и называется «environment agnostic», т.е. вы можете выбирать наилучший подход для каждой среды.
                                  Зачем же вы так меня обижаете :(
                                  Я, наоборот, топлю за то, чтобы вообще любой проект сложнее бложика делать как SPA, а проблемы с SEO решать серверным рендерингом. При должной квалификации разработчиков в человекочасах потерь не будет (скорее наоборот), зато UI/UX получит значительный прирост.

                                  Сорян, обижать не хотел. Да и только что обратил внимание, что вы автор статьи. Правда теперь не совсем понимаю вашу аргиментацию. Если концентрироваться лишь на SEO, тогда ребята, которые не хотят, как они говорят «заморачиваться» с изоморфностью скажут вам, что есть phantomjs и prerender и они прекрасно решают эту проблему. Зачем тогда «из пушки по воробьям»?
                                  Вообще, мой посыл не совсем в том, что не надо использовать SSR для чего-либо кроме SEO. Я говорю о том, что все остальные проблемы, которые решает SSR не стоят того, чтобы его внедрять, так как можно обойтись меньшей кровью.

                                  Видимо для вас SEO — это главный аргумент. Для меня не менее важным является скорость загрузки при старте и здесь опыт Twitter и Netflix очень показателен. Ребята тоже заигрались с SPA. Ну и ваше «меньшей кровью» также сомнительно, потому что если prepender более-менее решает вопрос с SEO, но code splitting вообще не решает вопрос со стартом. Да код начинает грузиться параллельно, а значит быстрее, но SSR + code splitting все равно будет значительно быстрее.
                                  Но с другой стороны SSR достаточно один раз настроить и потом везде использовать без дополнительных затрат, и все новые проекты лично я бы всегда делал с поддержкой SSR, так как мне, как разработчику, у которого есть для этого готовое решение, это ничего не стоит.

                                  Именно так я и считаю.
                                  Другое дело пересаживать на SSR какой-то существующий фронтенд, тут всё значительно сложнее.

                                  На самом деле не так уж и сложно, хотя конечно зависит от проекта. Во-первых, не обязательно сразу делать все изоморфным, можно постепенно внедрять этот подход в разные части приложения. Во-вторых, это в принципе не так уж сложно, если конечно у проекта есть какая-то адекватная архитектура. У меня был старый проект, не большой, компонентов 20 и 5-6 страниц. Весь переход на изоморфность занял не больше 100 строк кода, причем вместе с серверным. Да там она не совсем «full», но преимущества итак были очевидны.
                                  • 0
                                    Я больше не буду приводить цитаты, а то слишком уж длинные комментарии получаются :)
                                    Думаю, из контекста будет понятно, на что я отвечаю.

                                    Статья конца 2013 года. Я не могу утверждать наверняка, потому что не имею такой статистики, но подозреваю, что ситуация сильно изменилась вместе с ростом качества, доступности и скорости интернета (много где появился 3G/4G, например), а так же падением популярности старых версий IE (УРА). Возможно, 0.2% людей с реально отключенным JS ещё остались, но цифра 0.9% скорее всего упала.

                                    По поводу 3-секундного скрипта, кеша и доработок приложения — если применить код-сплиттинг и определённым образом настроить вебпак, то все эти проблемы решатся. Но, конечно, глупо спорить с тем, что SSR так или иначе повысит скорость отображения контента. Просто, опять же, я к тому, что это решаемо и без SSR.

                                    Cordova и пр. — тут я просто, если честно, не понял, к чему была поднята тема. А так да, со всем согласен :)

                                    Phantom/prerender решают те же проблемы, согласен. Но я считаю SSR своего рода эволюцией пререндеринга. Это более разумное решение, которое работает значительно быстрее + имеет хороший потенциал для оптимизации + с ним удобнее работать на сервере в целом (подключать какую-то аналитику, кешировать и прочее). То есть если есть равнозначный выбор между пререндерингом и SSR, то было бы глупо выбирать первое. Но для существующих проектов с большим количеством кода пререндеринг может быть единственным решением.

                                    А SEO — да, главный аргумент лично для меня. Просто потому, что это единственный вариант писать код «без костылей» и не жертвовать SEO (ну, есть ещё пререндеринг, но свою позицию относительно него я уже описал). Но то, что он параллельно решает ряд других проблем или улучшает какие-то показатели — определённо, приятный бонус.

                                    Опыт же крупных проектов по выпиливанию/впиливанию чего-то — думаю, не совсем об этом. Технологии в вебе, особенно на фронтенде, меняются с невероятной скоростью. С ними же растут потребности, критерии качества, размеры js/css файлов,… Появление проблем из-за этого всего неизбежно с любыми технологиями.
                                    • 0
                                      Ок, давайте без цитат)))

                                      Да, статья не самая новая, однако доводы, которые там приводятся, навряд ли устарели. Сеть есть сеть и она никогда не будет работать на 100% стабильно в любой точке мира. Ну и вот более современные цифры: blockmetry.com/blog/javascript-disabled

                                      Что значит решается? Можете рассказать как code spliting может заставить ваше приложение быть быстрее чем он же + SSR? Или вы считаете что веб-приложение может быть «достаточно быстрым»? Как мне кажется, учитывая особенности веб, нужно использовать все возможности по ускорению, которые у нас имеются. Ибо мы никогда не знаем в какой среде работает наш юзер. Ну и опять же уверен, что Twitter и Netflix тоже в курсе возможностей вебпака, но видимо их им не хватило. Ну и лично я давно хочу реализовать идею, когда приложение само может автоматом переключаться между SSR и чистым SPA в зависимости от замеров качества соединения. Точной реализации пока нет, но думаю это сделать возможно в изоморфном стиле и совершенно не реально без него.

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

                                      По поводу ваших доводов о SEO — они чисто субъективны. Кому-то может оказаться важнее поддерживать юзеров без JS, а кому-то просто ускорить загрузку. Вы говорите все это фигня и решается без SSR, я говорю что SEO также решается без SSR, а вы в ответ — «мне так нравится больше». Ну ок, тогда другие доводы также нравится больше и вообще зачем крутить кучу решений, если можно один раз крутануть изоморфность и сразу решить все проблемы.
                                      • 0
                                        По первым двум абзацам. На самом деле просто надо взвешивать все за и против на конкретном проекте. Сложно говорить об этом всём абстрактно.
                                        Я просто хотел показать, что есть другая сторона, которая тоже имеет право на существование.

                                        Идея с автопереключением SSR и SPA. Интересно, но оно того стоит? Можно просто рендерить на сервере всегда, так как это никому не приносит неудобств, кроме сервера. А если сервер начинает от этого уставать, то можно кешировать. Да и на самом деле мне кажется, что в перспективе SSR сравняется по производительности с обычными шаблонизаторами, ведь по сути задача его сводится к тому, чтобы получить данные и запихать их в разметку. А весь интерактив начинает свою работу уже на клиенте.

                                        Про SSR — как ни крути, а это не то же самое, что мы делаем при построении старого доброго бэкенда с шаблонизаторами, jQuery и пр. Это всё равно развитие (= эволюция), то есть слияние всего того, что было хорошо в SPA с тем, что было хорошо в MPA. Плюс это развитие идеи пререндеринга просто потому, что SSR лучше пререндеринга почти во всём.

                                        Про SEO — да, я признаю, что это субъективно. И да, SSR решает все проблемы разом, с этим я вообще не спорил.
                                        • 0
                                          По первым двум абзацам. На самом деле просто надо взвешивать все за и против на конкретном проекте. Сложно говорить об этом всём абстрактно.
                                          Я просто хотел показать, что есть другая сторона, которая тоже имеет право на существование.

                                          Другая? А чем она другая? Ну да, вебпак поддерживает code spliting? Но его можно и даже нужно использовать вместе с изоморфностью. Полноценным решение ни для Progressive Enhancement ни для повышения «accessibility» приложения оно не является.
                                          Идея с автопереключением SSR и SPA. Интересно, но оно того стоит? Можно просто рендерить на сервере всегда, так как это никому не приносит неудобств, кроме сервера. А если сервер начинает от этого уставать, то можно кешировать.

                                          Кажется я не совсем раскрыл кейс. Понимаете, ситуация всяких много. Вот вам реальный кейс из практики: есть 2 смарт тв — один старый, 12-го года, другой более-менее новый 15-го года. Оба из них подключены в wi-fi 100% времени (т.е. сеть работает стабильно и с хорошей скоростью). Делать SPA для второго ТВ вполне себе оправданное решение, потому что во-первых в его встроенном браузере уже нормальные движки JS/HTML/CSS. Во-вторых, там более-менее производительное железо.

                                          Первый же телик слаб и движками, и железом. Поэтому дичайше тормозит просто от того, что рендарит шаблоны на клиенте. В таком случае выгоднее рендарить на сервере и получать полностью готовый html (ну или хотя бы куски HTML), сеть то прекрасная и стабильная. Даже с учетом накладных на сеть, SSR работает все равно быстрее. Что будем делать? Писать PHP приложения для второго сервера и специальный клиент для первого? Лишать первый возможностей SPA, потому что нужно поддерживать старые модели? Или все же запилим изоморфность?
                                          Про SSR — как ни крути, а это не то же самое, что мы делаем при построении старого доброго бэкенда с шаблонизаторами, jQuery и пр.

                                          А чем это не тоже самое? Тем что сейчас модно строить virtual dom? Ну личное имхо это даже хуже для сервера, но в целом просто деталь реализации. Изоморфность — да, это эволюция всех подходов, использование лучшего из обоих миров. А чисто SSR — это всего лишь то, что мы делали раньше, только на PHP. Вы же понимаете, что SSR != изоморфность?
                                          Про SEO — да, я признаю, что это субъективно. И да, SSR решает все проблемы разом, с этим я вообще не спорил.

                                          Да все субъективно, но лично я люблю решать все проблемы разом)))
                                          • 0
                                            Я о том, что просто нужно взвешивать целесообразность внедрения SSR с точки зрения трудозатрат. Чем сложнее проект и чем больше в нём legacy кода, тем больше человекочасов займёт внедрение SSR.

                                            Про телевизор понял, нагдлядно.

                                            А чем это не тоже самое?

                                            Ну как минимум тем, что фронтенд и бэкенд не пересекаются и гораздо более явно разделены. Никто не «натягивает вёрстку», не переписывает стили под CMS/фреймворки, не решает проблем с SEO и т.д. и т.п. Каждый занят своим делом: фронтендщик — пишет стили, разметку и интерактив, бэкендщик — создаёт бизнес-логику и API для неё. Изоморфность же достигается сама собой благодаря одному человеку, который один раз настроил сборку и сервер для SSR, а также разъяснил немногочисленные особенности разработки фронтендщикам. У меня этого достичь с одним лишь PHP на сервере не получалось :)
                                            SSR != изоморфность, но SSR — инструмент, позволяющий достичь изоморфности.
                                            • 0
                                              Я о том, что просто нужно взвешивать целесообразность внедрения SSR с точки зрения трудозатрат. Чем сложнее проект и чем больше в нём legacy кода, тем больше человекочасов займёт внедрение SSR.

                                              Как я и говорил ранее, изоморфность можно крутить постепенно. Шаг за шагом. Первое приложение, которое я перевел только на изоморфный SSR, вообще без других аспектов изоморфности, было еще в те времена, когда только nodejitsu о ней и говорили. Это был обычный сайт на PHP, который сперва умел рендарить шаблоны сам, потому части шаблонов этого бекенда (например список с фильтрами) перекочевали на ajax и рендаринг на клиент с помощью «усов». Потом нода продвинулась, стала более-менее рабочей и мы ее поставили вперед (frontend server), перенесли все шаблоны в «усы», а из PHP сделали чисто апи (частично оно уже было, потому что частично рендаринг был на клиенте). Вот так мы с минимальными затратами втащили в крайне legacy проект частичку изоморфности. Без реактов, вуев, ангулятов, юзая просто изоморфный шаблонизатор. Можно было бы и даальше по-тихоньку наворачивать, но не было нужды для этого проекта.
                                              Ну как минимум тем, что фронтенд и бэкенд не пересекаются и гораздо более явно разделены.

                                              Это смотря как написан ваш код. У нас и до начала использования ноды активно юзалась 3-х звенная архитектура, с обязательными frontend и backend серверами. Например одна из моих любимых конфигураций того времени — бэк-сервер на C/C++ (чистый апи поверх базы и elasticsearch) и фронт-сервер на PHP (в том время он давал наиболее простой способ шаблонизации на сервере). Сейчас у нас примерно такой же бекенд, только на Go или C/C++, ну или на кройняк PHP/Python. Дальше фронтом стоит NodeJS + ну и прибавился полноценный SPA на клиенте. Так что как можете заметить отличий не так много, просто прибавился толстый клиент. Это и есть эволюция. А то, что сейчас подают под соусом SSR — это когда толпа радостных фронтендщиков сначала дружно ломанулись на клиент и начали хренячить SPA и во все стороны орать «backendless»!!! Потом начали делать пререндер, в качестве костыля под SPA. А потом вдруг вспомнили, что можно и на сервере, что то делать и даже быстрее. Поэтому для них это все «эволюция пререндера после революции веба», а для меня это просто «эволюция веба, после ошибкок молодости (SPA)».

                                              • 0
                                                Ха-ха, ну вы уже давно как матёрый разработчик)
                                                У меня такой опыт мог бы сложиться, родись я хотя бы на пару лет пораньше. Нода появилась чуть раньше того момента, когда я нашёл первую работу по специальности) А вместе с ней пошли-поехали сборщики, фреймворки, пререндеринги и т.д.
                                                Хотя с усами без ангуляров, реактов и вуёв я тоже экспериментировал, но исключительно на клиенте. Сейчас, конечно, всё это не особо актуально.
                                                А сервера на C/C++ я вообще вживую ни разу не видел. Слышал только, что до появления PHP только на них и писали.

                                                А так да, я понимаю, что были и раньше способы. Но сейчас они становятся «народными» и большее количество людей начинает их использовать.
                                                • 0
                                                  Ха-ха, ну вы уже давно как матёрый разработчик)

                                                  Ну я далеко не самый древний старпер здесь, но 10+ лет профстажа то есть конечно.

                                                  А сервера на C/C++ я вообще вживую ни разу не видел. Слышал только, что до появления PHP только на них и писали.

                                                  Да это и сейчас актуально. Далеко не все написано на PHP, а до этого писалось на C/C++. Есть полно серверов на Java/.Net и тп. Да и до PHP как бы Perl был в угаре из ему подобных. Вообще на интерпретируемых языках писать многие типы серверов — это смерти подобно, ну либо потом костыли крутить типа HipHop. Сейчас лично мне кажется весьма перспективным Go.
                                                  А так да, я понимаю, что были и раньше способы. Но сейчас они становятся «народными» и большее количество людей начинает их использовать.

                                                  Статистики не имею, но прям чтоб «народными» есть все же сомнения. К сожалению, изоморфность в том числе — почему-то для многих это капец как сложным кажется.

                        • 0
                          Не так ветка, сорян.

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