Что такое SSR?

👨‍💻 Frontend Developer 🟠 Может встретиться 🎚️ Средний
#React #Next.js #SSR

Краткий ответ

SSR (Server-Side Rendering) — это технология рендеринга веб-страниц на сервере с отправкой готового HTML клиенту:

  1. Рендеринг на сервере — HTML генерируется до отправки 🖥️
  2. Быстрая загрузка — контент виден сразу ⚡
  3. SEO-оптимизация — поисковики видят готовый контент 🔍
  4. Гидратация — React подключается к готовой разметке 💧
  5. Улучшенная производительность — особенно на медленных устройствах 📱
  6. Лучший UX — пользователь видит контент быстрее 👁️
// Компонент рендерится на сервере
function HomePage({ posts }) {
  return (
    <div>
      <h1>Блог</h1>
      {posts.map(post => (
        <article key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.excerpt}</p>
        </article>
      ))}
    </div>
  );
}

Полный ответ

SSR — это как готовый обед, который подают в ресторане, а не ингредиенты для самостоятельного приготовления! Сервер заранее готовит HTML и отправляет его браузеру. 🍽️

Как работает SSR

// 1. Запрос приходит на сервер
app.get('/', async (req, res) => {
  // 2. Получаем данные
  const posts = await fetchPosts();
  
  // 3. Рендерим компонент в HTML
  const html = renderToString(
    <HomePage posts={posts} />
  );
  
  // 4. Отправляем готовый HTML
  res.send(`
    <!DOCTYPE html>
    <html>
      <body>
        <div id="root">${html}</div>
        <script src="/bundle.js"></script>
      </body>
    </html>
  `);
});

SSR vs CSR (Client-Side Rendering)

// CSR - рендеринг на клиенте
function App() {
  const [posts, setPosts] = useState([]);
  
  useEffect(() => {
    // Данные загружаются после рендера
    fetchPosts().then(setPosts);
  }, []);
  
  return (
    <div>
      {posts.length ? (
        posts.map(post => <Post key={post.id} {...post} />)
      ) : (
        <div>Загрузка...</div>
      )}
    </div>
  );
}
 
// SSR - данные уже есть
function App({ posts }) {
  // Контент сразу готов
  return (
    <div>
      {posts.map(post => (
        <Post key={post.id} {...post} />
      ))}
    </div>
  );
}

Гидратация (Hydration)

// На сервере
const html = renderToString(<App data={data} />);
 
// На клиенте - гидратация
import { hydrateRoot } from 'react-dom/client';
 
hydrateRoot(
  document.getElementById('root'),
  <App data={window.__INITIAL_DATA__} />
);

Next.js — популярный SSR фреймворк

// pages/index.js
export default function Home({ posts }) {
  return (
    <div>
      <h1>Главная страница</h1>
      {posts.map(post => (
        <div key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.content}</p>
        </div>
      ))}
    </div>
  );
}
 
// Функция выполняется на сервере
export async function getServerSideProps() {
  const posts = await fetch('https://api.example.com/posts')
    .then(res => res.json());
  
  return {
    props: { posts }
  };
}

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

// Генерация во время сборки
export async function getStaticProps() {
  const posts = await fetchPosts();
  
  return {
    props: { posts },
    revalidate: 60 // Обновление каждые 60 секунд
  };
}
 
// Динамические маршруты
export async function getStaticPaths() {
  const posts = await fetchPosts();
  
  return {
    paths: posts.map(post => ({
      params: { id: post.id.toString() }
    })),
    fallback: 'blocking'
  };
}

Преимущества SSR

  1. Быстрый First Contentful Paint
  2. Лучшее SEO — поисковики видят контент 🔍
  3. Социальные сети — правильные превью 📱
  4. Производительность на слабых устройствах 📲
  5. Доступность — работает без JavaScript 👥
// SEO-дружественный компонент
function ProductPage({ product }) {
  return (
    <>
      <Head>
        <title>{product.name} - Магазин</title>
        <meta name="description" content={product.description} />
        <meta property="og:title" content={product.name} />
        <meta property="og:image" content={product.image} />
      </Head>
      
      <main>
        <h1>{product.name}</h1>
        <img src={product.image} alt={product.name} />
        <p>{product.description}</p>
        <span>Цена: {product.price}₽</span>
      </main>
    </>
  );
}

Недостатки SSR

  1. Сложность сервера — нужна серверная инфраструктура 🖥️
  2. Время ответа — сервер должен обработать запрос ⏱️
  3. Нагрузка на сервер — каждый запрос требует рендеринга 💪
  4. Сложность кеширования — динамический контент 🗄️

Стратегии рендеринга

// 1. Полный SSR
export async function getServerSideProps(context) {
  const data = await fetchUserData(context.req);
  return { props: { data } };
}
 
// 2. Статическая генерация
export async function getStaticProps() {
  const data = await fetchStaticData();
  return { 
    props: { data },
    revalidate: 3600 // ISR
  };
}
 
// 3. Гибридный подход
function Page({ staticData }) {
  const [dynamicData, setDynamicData] = useState(null);
  
  useEffect(() => {
    fetchDynamicData().then(setDynamicData);
  }, []);
  
  return (
    <div>
      <StaticContent data={staticData} />
      {dynamicData && <DynamicContent data={dynamicData} />}
    </div>
  );
}

Оптимизация SSR

// Кеширование
import { cache } from 'react';
 
const fetchPosts = cache(async () => {
  const response = await fetch('/api/posts');
  return response.json();
});
 
// Потоковый рендеринг
import { renderToPipeableStream } from 'react-dom/server';
 
app.get('/', (req, res) => {
  const stream = renderToPipeableStream(
    <App />,
    {
      onShellReady() {
        res.setHeader('Content-Type', 'text/html');
        stream.pipe(res);
      }
    }
  );
});

Лучшие практики

  1. Используйте кеширование для статического контента 🗄️
  2. Оптимизируйте запросы к базе данных 🚀
  3. Реализуйте потоковый рендеринг для больших страниц 🌊
  4. Разделяйте статический и динамический контент ⚖️

Частые ошибки

Неправильно:

// Использование browser-only API
function Component() {
  const width = window.innerWidth; // Ошибка на сервере
  return <div>Ширина: {width}</div>;
}

Правильно:

function Component() {
  const [width, setWidth] = useState(0);
  
  useEffect(() => {
    setWidth(window.innerWidth);
  }, []);
  
  return <div>Ширина: {width || 'Загрузка...'}</div>;
}

Заключение

SSR — мощная технология для улучшения производительности и SEO:

  • Быстрая загрузка — контент виден сразу
  • SEO-оптимизация — поисковики индексируют контент
  • Лучший UX — особенно на медленных соединениях
  • Гибкость — можно комбинировать с CSR

Выбирайте SSR для контентных сайтов, блогов и интернет-магазинов! 🎯