Поиск по сайту:

Как включить рендеринг на стороне сервера для приложения React


Предупреждение. Это руководство предназначено для краткого ознакомления с ReactDOM.hydrate() и ReactDOMServer.rendertoString(). Он не предназначен для использования в производстве.

Кроме того, Next.js предлагает современный подход к созданию статических и серверных приложений, созданных с помощью React.

Введение

Отрисовка на стороне сервера (SSR) – это популярный метод рендеринга одностраничного приложения (SPA) на стороне клиента на сервере с последующей отправкой полностью обработанной страницы клиенту. . Это позволяет использовать динамические компоненты в качестве статической разметки HTML.

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

В этом руководстве вы инициализируете приложение React с помощью Create React App, а затем измените проект, чтобы включить рендеринг на стороне сервера.

В конце этого руководства у вас будет рабочий проект с клиентским приложением React и серверным приложением Express.

Предпосылки

Для выполнения этого урока вам понадобятся:

  • Node.js установлен локально, что можно сделать, следуя инструкциям по установке Node.js и созданию локальной среды разработки.

Это руководство было проверено с помощью Node v16.13.1, npm v8.1.2, react v17.0.2, @babel/core v7.16.0, webpack v4.44.2, express v4.17.1, nodemon v2.0.15 и npm-run-all v4. 1.5.

Шаг 1 — Создание приложения React и изменение компонента приложения

Во-первых, используйте npx для запуска нового приложения React, используя последнюю версию Create React App.

Назовем приложение react-ssr-example:

  1. npx create-react-app react-ssr-example

Затем cd в новый каталог:

cd react-ssr-example

Наконец, запустите новое клиентское приложение, чтобы проверить установку:

  1. npm start

Вы увидите пример приложения React, отображаемый в окне вашего браузера.

Теперь в каталоге src создадим новый компонент :

  1. nano src/Home.js

Затем добавьте следующий код в файл Home.js:

function Home(props) {
  return <h1>Hello {props.name}!</h1>;
};

export default Home;

Это создаст заголовок <h1> с сообщением Hello, адресованным имени.

Затем давайте визуализируем в компоненте . Откройте файл App.js в каталоге src:

  1. nano src/App.js

Затем замените существующие строки кода новыми строками кода:

import Home from './Home';

function App() {
  return <Home name="Sammy"/>;
}

export default App;

Это передает компонент name в компонент , поэтому сообщение, которое вы ожидаете отобразить, будет следующим:

Output
"Hello Sammy!"

В файле index.js приложения вы будете использовать метод ReactDOM hydrate вместо render, чтобы указать средству визуализации DOM, что вы намерены регидратировать приложение после рендеринга на стороне сервера.

Давайте откроем файл index.js в каталоге src:

  1. nano src/index.js

Затем замените содержимое файла index.js следующим кодом:

import React from 'react';
import ReactDOM from 'react-dom';

import App from './App';

ReactDOM.hydrate(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

На этом настройка клиентской части закончена, можно переходить к настройке серверной.

Шаг 2 — Создание экспресс-сервера и рендеринг компонента приложения

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

Примечание. react-scripts приложения Create React устанавливает версию express в качестве требования для webpack-dev-server. Чтобы избежать конфликтов дерева зависимостей, это руководство больше не включает этот шаг установки.

Затем создайте новый каталог server в корневом каталоге проекта:

  1. mkdir server

Затем внутри каталога server создайте новый файл index.js, который будет содержать код сервера Express:

  1. nano server/index.js

Добавьте необходимые импорты и определите некоторые константы:

import path from 'path';
import fs from 'fs';

import React from 'react';
import ReactDOMServer from 'react-dom/server';
import express from 'express';

import App from '../src/App';

const PORT = process.env.PORT || 3006;
const app = express();

Затем добавьте код сервера с некоторой обработкой ошибок:

// ...

app.get('/', (req, res) => {
  const app = ReactDOMServer.renderToString(<App />);
  const indexFile = path.resolve('./build/index.html');

  fs.readFile(indexFile, 'utf8', (err, data) => {
    if (err) {
      console.error('Something went wrong:', err);
      return res.status(500).send('Oops, better luck next time!');
    }

    return res.send(
      data.replace('<div id="root"></div>', `<div id="root">${app}</div>`)
    );
  });
});

app.use(express.static('./build'));

app.listen(PORT, () => {
  console.log(`Server is listening on port ${PORT}`);
});

Можно импортировать компонент из клиентского приложения непосредственно с сервера.

Здесь происходят три важные вещи:

  • Express используется для предоставления содержимого из каталога build в виде статических файлов.
  • ReactDOMServer renderToString используется для преобразования приложения в статическую строку HTML.
  • Считывается статический файл index.html из встроенного клиентского приложения. Статическое содержимое приложения внедряется в <div> с id root. Это отправляется как ответ на запрос.

Шаг 3 — Настройка сценариев webpack, Babel и npm

Чтобы серверный код работал, вам нужно будет связать и транспилировать его с помощью Babel. Чтобы выполнить это.

Примечание. В более ранней версии этого руководства устанавливались babel-core, babel-preset-env и babel-preset-react-app. С тех пор эти пакеты были заархивированы, и вместо них использовались монорепозитории.

react-scripts приложения Create React обрабатывает установку следующих пакетов: webpack, webpack-cli, webpack-node-externals, @babel/core, babel-loader, @babel/preset-env, @babel/preset-react . Чтобы избежать конфликтов дерева зависимостей, это руководство больше не включает этот шаг установки.

Затем создайте новый файл конфигурации Babel в корневом каталоге проекта:

  1. nano .babelrc.json

Затем добавьте пресеты env и react-app:

{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react"
  ]
}

Примечание. В более ранней версии этого руководства использовался файл .babelrc (без расширения файла .json). Это был файл конфигурации для Babel 6, но для Babel 7 это уже не так.

Теперь создайте конфигурацию веб-пакета для сервера, который использует Babel Loader для переноса кода. Начните с создания файла webpack.server.js в корневом каталоге проекта:

  1. nano webpack.server.js

Затем добавьте следующие настройки в файл webpack.server.js:

const path = require('path');
const nodeExternals = require('webpack-node-externals');

module.exports = {
  entry: './server/index.js',
  target: 'node',
  externals: [nodeExternals()],
  output: {
    path: path.resolve('server-build'),
    filename: 'index.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: 'babel-loader'
      }
    ]
  }
};

При такой конфигурации перенесенный пакет сервера будет выводиться в папку server-build в файле с именем index.js.

Обратите внимание на использование target: node и externals: [nodeExternals()] из webpack-node-externals, что исключает файлы из node_modules в комплекте; сервер может обращаться к этим файлам напрямую.

На этом установка зависимостей и настройка webpack и Babel завершены.

Теперь вернитесь к package.json и добавьте вспомогательные скрипты npm:

  1. nano package.json

Добавьте сценарии dev:build-server, dev:start и dev в файл package.json для сборки. и обслуживать приложение SSR:

"scripts": {
  "dev:build-server": "NODE_ENV=development webpack --config webpack.server.js --mode=development -w",
  "dev:start": "nodemon ./server-build/index.js",
  "dev": "npm-run-all --parallel build dev:*",
  // ...
},

Сценарий dev:build-server устанавливает для среды значение development и вызывает webpack с созданным ранее файлом конфигурации. Сценарий dev:start вызывает nodemon для обслуживания созданного вывода.

Сценарий dev вызывает npm-run-all для запуска parallel сценария build и всех сценариев, начинающихся с dev:* — включая dev:build-server и dev:start.

Примечание. Вам не нужно изменять существующие start, build, test и eject в файле package.json.

nodemon используется для перезапуска сервера при внесении изменений. npm-run-all используется для параллельного запуска нескольких команд.

Давайте установим эти пакеты сейчас, введя следующие команды в окне терминала:

  1. npm install nodemon@2.0.15 --save-dev
  2. npm install npm-run-all@4.1.5 --save-dev

После этого вы можете запустить следующее, чтобы создать клиентское приложение, связать и транспилировать серверный код и запустить сервер на :3006:

  1. npm run dev

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

Примечание. Здесь есть открытый вопрос.

Теперь откройте http://localhost:3006/ в своем веб-браузере и посмотрите на свое приложение, отображаемое на стороне сервера.

Ранее при просмотре исходного кода было обнаружено:

Output
<div id="root"></div>

Но теперь, с внесенными вами изменениями, исходный код показывает:

Output
<div id="root"><h1 data-reactroot="">Hello <!-- -->Sammy<!-- -->!</h1></div>

Рендеринг на стороне сервера успешно преобразовал компонент в HTML.

Заключение

В этом руководстве вы инициализировали приложение React и включили рендеринг на стороне сервера.

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

Одним из основных преимуществ использования SSR является наличие приложения, содержимое которого можно сканировать даже для сканеров, которые не выполняют код JavaScript. Это может помочь с поисковой оптимизацией (SEO) и предоставлением метаданных для каналов социальных сетей.

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

Если вы хотите узнать больше о React, загляните на нашу страницу темы React с упражнениями и проектами по программированию.