Серверный рендеринг обеспечивает быстрый и надежный доступ к контенту. В этом подходе веб-страницы формируются на сервере, а не в браузере пользователя. Это позволяет значительно ускорить время загрузки, что особенно критично для современных одностраничных приложений, известных как SPA (Single-Page Applications).

SPA несмотря на их удобство и функциональность сталкиваются с рядом проблем, включая SEO-оптимизацию и производительность, особенно на медленных соединениях или устройствах.

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

Плюсы серверного рендеринга:

  1. Улучшенное SEO: серверный ренеринг обеспечивает поисковым системам более доступный контент, делая веб-страницы "прозрачными" для индексации. Это особенно важно для SPA, которые традиционно сложно индексируются из-за их динамичной природы.

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

  3. Улучшенная безопасность и удобство для пользователей: серверный рендеринг повышает уровень безопасности, минимизируя риски, связанные с клиентской стороной, такие как XSS-атаки.

Реализация серверного рендеринга

Каждый этап выполняет свою уникальную роль, создавая мост между сервером и пользовательским интерфейсом.

  1. Подготовка: Первый шаг - это подготовка. Компоненты веб-приложения трансформируются из кода, который обычно исполняется в браузере, в формат, пригодный для серверного рендеринга. Это включает в себя обработку зависимостей и настройку среды исполнения на сервере.

  2. Рендеринг: Далее идет сам процесс рендеринга. Сервер обрабатывает запрос, генерируя HTML-ответ, который включает в себя результат рендеринга компонентов. Это может быть статический HTML или динамический, зависящий от данных, полученных сервером.

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

React и Vue.js — два фронтенд-фреймворка, которые прекрасно подходят для серверного рендеринга, каждый со своими уникальными особенностями.

1. React и SSR:

  • React, благодаря своей гибкости и мощной экосистеме, идеально подходит для создания динамических веб-приложений с серверным рендерингом.

  • Пример №1: Использование ReactDOMServer.renderToString() для рендеринга компонента React в строку HTML.

    import ReactDOMServer from 'react-dom/server';
    import MyComponent from './MyComponent';
    
    const html = ReactDOMServer.renderToString(<MyComponent />);
  • Пример №2: Интеграция React с Express.js для серверного рендеринга.

    import express from 'express';
    import React from 'react';
    import ReactDOMServer from 'react-dom/server';
    import MyComponent from './MyComponent';
    
    const app = express();
    app.get('/', (req, res) => {
      const html = ReactDOMServer.renderToString(<MyComponent />);
      res.send(`<div id="root">${html}</div>`);
    });
    app.listen(3000);

2. Vue.js и SSR:

  • Vue.js, с его интуитивно понятным API и легковесностью, также является отличным выбором для серверного рендеринга.

  • Пример №3: Основной шаблон для серверного рендеринга в Vue.js.

    const { createRenderer } = require('vue-server-renderer');
    const Vue = require('vue');
    
    const renderer = createRenderer();
    const app = new Vue({ template: `<div>Hello, Vue SSR!</div>` });
    
    renderer.renderToString(app, (err, html) => {
      if (err) throw err;
      console.log(html);
    });
  • Пример №4: Использование Nuxt.js для упрощения серверного рендеринга в Vue.js.

    // Это конфигурационный файл для Nuxt.js
    export default {
      ssr: true, // Включить серверный рендеринг
      // Другие настройки Nuxt.js...
    };
  • Пример №5: Интеграция Vue.js с серверным фреймворком, например, с Express.js.

    const express = require('express');
    const Vue = require('vue');
    const renderer = require('vue-server-renderer').createRenderer();
    
    const server = express();
    server.get('/', (req, res) => {
      const app = new Vue({ data: { message: 'Привет, Vue SSR!' }, template: `<div>{{ message }}</div>` });
    
      renderer.renderToString(app, (err, html) => {
        if (err) res.status(500).end('Внутренняя ошибка сервера');
        res.end(`<!DOCTYPE html><html lang="en"><body>${html}</body></html>`);
      });
    });
    server.listen(8080);

Еще пару примеров:

  1. Загрузка данных перед рендерингом на стороне сервера в React:

    import express from 'express';
    import ReactDOMServer from 'react-dom/server';
    import MyComponentWithData from './MyComponentWithData';
    
    const app = express();
    
    app.get('/', async (req, res) => {
      const data = await fetchData(); // Предполагается функция для получения данных
      const html = ReactDOMServer.renderToString(<MyComponentWithData data={data} />);
      res.send(`<div id="root">${html}</div>`);
    });
    
    app.listen(3000);
  2. Использование React Router для серверного рендеринга:

    import express from 'express';
    import ReactDOMServer from 'react-dom/server';
    import { StaticRouter } from 'react-router-dom';
    import App from './App';
    
    const app = express();
    
    app.get('*', (req, res) => {
      const context = {};
      const html = ReactDOMServer.renderToString(
        <StaticRouter location={req.url} context={context}>
          <App />
        </StaticRouter>
      );
    
      res.send(`<div id="root">${html}</div>`);
    });
    
    app.listen(3000);
  3. Использование Vue Router для серверного рендеринга:

    const Vue = require('vue');
    const VueRouter = require('vue-router');
    const server = require('express')();
    const renderer = require('vue-server-renderer').createRenderer();
    
    Vue.use(VueRouter);
    
    const router = new VueRouter({
      routes: [{ path: '/', component: { template: '<div>Главная страница</div>' } }]
    });
    
    server.get('*', (req, res) => {
      const app = new Vue({
        router,
        template: `<div id="app"><router-view></router-view></div>`
      });
    
      router.push(req.url);
    
      renderer.renderToString(app, (err, html) => {
        if (err) res.status(500).end('Внутренняя ошибка сервера');
        res.end(`<!DOCTYPE html><html lang="en"><body>${html}</body></html>`);
      });
    });
    
    server.listen(8080);
  4. Управление состоянием с Vuex в серверном рендеринге Vue.js:

    const Vue = require('vue');
    const Vuex = require('vuex');
    const renderer = require('vue-server-renderer').createRenderer();
    const server = require('express')();
    
    Vue.use(Vuex);
    
    const store = new Vuex.Store({
      state: { message: 'Привет из Vuex!' },
      mutations: {
        setMessage(state, message) {
          state.message = message;
        }
      }
    });
    
    const app = new Vue({
      store,
      template: `<div>{{ $store.state.message }}</div>`
    });
    
    server.get('/', (req, res) => {
      renderer.renderToString(app, (err, html) => {
        if (err) res.status(500).end('Внутренняя ошибка сервера');
        res.end(`<!DOCTYPE html><html lang="en"><body>${html}</body></html>`);
      });
    });
    
    server.listen(8080);

Оптимизация и масштабирование

Оптимизация и масштабирование являются позволяют минимизировать последствия блокировки цикла событий. Каждая миллисекунда задержки может повлиять на пользовательский опыт.

Примеры:

  1. Использование микросервисов для масштабирования:

    // Предположим, у нас есть несколько микросервисов, обслуживающих разные части приложения
    app.use('/api/users', userService);
    app.use('/api/products', productService);
  2. Кэширование содержимого:

    const cachedContent = cache.get('page_content');
    if (cachedContent) {
      return cachedContent;
    } else {
      const content = renderContent();
      cache.set('page_content', content);
      return content;
    }
  3. Использование очередей сообщений для асинхронной обработки задач:

    messageQueue.send('emailService', { email: 'user@example.com', content: 'Welcome!' });
    // Отправка задачи в сервис очередей для асинхронной обработки
  4. Горизонтальное масштабирование с использованием балансировщиков нагрузки:

    const cluster = require('cluster');
    if (cluster.isMaster) {
      // Создание рабочих процессов
      cluster.fork();
      cluster.fork();
    } else {
      // Запуск сервера в рабочих процессах
      app.listen(3000);
    }

Серверный рендеринг vs пререндеринг

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

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

Заключение

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

А тем, кто хочет получить практические навыки по инфраструктуре, хочу порекомендовать курсы от моих коллеги из OTUS. Напомню, что программа каждого курса разработана практикующими экспертами отрасли. Переходите в каталог и выбирайте подходящий курс.

Комментарии (3)


  1. JerryI
    21.11.2023 18:18
    +3

    А чем оно отличается от того, что можно найти на первой странице доков того же React и Vue? Если это статья-обзор, то как то узковато

    Либо заголовок должен быть “… с React и Vue”


    1. Safort
      21.11.2023 18:18

      Не редко, статьи от Otus не стоит воспринимать серьёзно. Ребята просто хотят, чтобы их блог часто мелькал на Хабре и всё)


    1. Kodzo
      21.11.2023 18:18

      Это же otus, воспринимайте их как белый шум)