// Tutorial //

Reactアプリのサーバー側レンダリングを有効にする方法

Published on January 12, 2021
Default avatar
By Alligator.io
Developer and author at DigitalOcean.
日本語
Reactアプリのサーバー側レンダリングを有効にする方法

はじめに

サーバー側レンダリング(SSR)は、サーバー上のクライアント側_シングルページアプリケーション_(SPA)をレンダリングし、完全にレンダリングされたページをクライアントに送信するための一般的な手法です。これにより、動的コンポーネントを静的HTMLマークアップとして提供できます。

このアプローチは、JavaScriptのインデックス作成が適切に行われない場合、検索エンジンの最適化(SEO)に役立ちます。また、大規模なJavaScriptバンドルのダウンロードが低速ネットワークによって損なわれている場合にも有効な場合があります。

このチュートリアルでは、Create React Appを使用しReactアプリを初期化した後、プロジェクトを変更してサーバー側レンダリングを有効にします。

このチュートリアルを終了すると、クライアント側 のReactアプリとサーバー側のExpressアプリを使用した作業プロジェクトが作成されます。

注意: 一方Next.jsは、Reactで構築された静的なサーバーレンダリングアプリケーションを作成するための最新のアプローチを提供します。

前提条件

このチュートリアルを実行するには、次のものが必要です。

このチュートリアルは、Node v14.4.0、npm v6.14.5で検証済です。

ステップ 1 — Reactアプリの作成とアプリコンポーネントの変更

まず、npxを用いて、最新バージョンのCreate React Appを使用して新しいReactアプリを起動します。

my-ssr-appアプリを呼び出しましょう。

  1. npx create-react-app@3.4.1 my-ssr-app

次に、cdで新しいディレクトリに移動します。

cd my-ssr-app

最後に、インストールを確認するために、新しいクライアント側アプリを起動します。

  1. npm start

ブラウザウィンドウに、サンプルReactアプリが表示されます。

それでは、<Home>コンポーネントを作成しましょう。

  1. nano src/Home.js

次に、Home.jsファイルに次のコードを追加します。

src/Home.js
import React from 'react';

export default props => {
  return <h1>Hello {props.name}!</h1>;
};

これにより、nameに対して「Hello」メッセージが付いた<h1>見出しが作成されます。

次に、<App>コンポーネントで<Home>をレンダリングしましょう。App.jsファイルを開きます。

  1. nano src/App.js

次に、既存のコード行をこれらの新しいコード行に置き換えます。

src/App.js
import React from 'react';
import Home from './Home';

export default () => {
  return <Home name="Sammy" />;
};

これにより、name<Home>コンポーネントに渡されるため、メッセージは、「Hello Sammy!」と表示されるはずです。

このアプリのindex.jsファイルでは、サーバー側のレンダリング後にアプリを再ハイドレーションすることをDOMレンダラーに示すために、renderの代わりに、ReactDOMのhydrateメソッドを使用します。

index.jsファイルを開きましょう。

  1. nano index.js

次に、index.jsファイルの内容を次のコードに置き換えます。

index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

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

これで、クライアント側のセットアップは終了です。次にサーバー側のセットアップに進みます。

ステップ 2 — Expressサーバーの作成とアプリコンポーネントのレンダリング

アプリの準備が整ったので、レンダリングされたバージョンを送信するサーバーをセットアップしましょう。サーバーにはExpressを使用します。端末ウィンドウに次のコマンドを入力して、プロジェクトに追加しましょう。

  1. npm install express@4.17.1

または、yarnを使用して次のように行います。

  1. yarn add express@4.17.1

次に、アプリのsrcディレクトリの横にserverディレクトリを作成します。

  1. mkdir server

次に、Expressサーバーコードを含む新しいindex.jsファイルを作成します。

  1. nano server/index.js

いくつかの定数を必要とし、定義するインポートを追加します。

server/index.js
import path from 'path';
import fs from 'fs';

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

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

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

次に、エラー処理を含むサーバーコードを追加します。

server/index.js
// ...

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}`);
});

ご覧のとおり、<App>コンポーネントをサーバーのクライアントアプリから直接インポートすることができます。

ここでは3つの重要なことが起こっています。

  • buildディレクトリのコンテンツを静的ファイルとして提供するようにExpressに指示します。
  • ReactDOMServerrenderToStringメソッドを使用して、アプリを静的なHTML文字列にレンダリングします。
  • 次に、構築されたクライアントアプリから静的index.htmlファイルを読み取り、id「root」<div>にアプリの静的コンテンツを挿入し、リクエストへの応答として送信します。

ステップ 3 — webpack、Babel、およびnpmスクリプトの設定

サーバーコードを機能させるには、webpackBabelを使用して、サーバーコードをバンドルしてトランスパイルする必要があります。これを実行するには、端末ウィンドウに次のコマンド を入力して、プロジェクトに開発の依存関係を追加しましょう。

  1. npm install webpack@4.42.0 webpack-cli@3.3.12 webpack-node-externals@1.7.2 @babel/core@7.10.4 babel-loader@8.1.0 @babel/preset-env@7.10.4 @babel/preset-react@7.10.4 --save-dev

または、yarnを使用して次のように行います。

  1. yarn add webpack@4.42.0 webpack-cli@3.3.12 webpack-node-externals@1.7.2 @babel/core@7.10.4 babel-loader@8.1.0 @babel/preset-env@7.10.4 @babel/preset-react@7.10.4 --dev

**注:**このチュートリアルの以前のバージョンは、babel-corebabel-preset-env、およびbabel-preset-react-appをインストールしました。これらのパッケージはその後アーカイブされ、代わりにモノリポジトリのバージョンが使用されます。

次に、Babelの設定ファイルを作成します。

  1. nano .babelrc.json

次に、envreact-appプリセットを追加します。

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

**注意:**このチュートリアルの以前のバージョンでは、.babelrcファイル(.jsonファイル拡張子なし)を使用していました。これはBabel 6の設定ファイルでしたが、Babel 7では当てはまりません。

次に、Babel Loaderを使用してコードをトランスパイルするサーバーのwebpack設定を作成します。ファイルの作成から始めます。

  1. nano webpack.server.js

その後、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'
      }
    ]
  }
};

この設定により、トランスパイルされたサーバーバンドルは、index.jsというファイルのserver-buildフォルダに出力されます。

webpack-node-externals以降のtarget: 'node'externals: [nodeExternals()] の使用に注意してください。これは、バンドルのnode_modulesからファイルを除外します。サーバーはこれらのファイルに直接アクセスできます。

これにより、依存関係のインストールとwebpackおよびBabelの設定は完了です。

次に、package.jsonに再度アクセスして、ヘルパーnpmスクリプトを追加します。

  1. nano package.json

SSRアプリケーションを簡単に構築して提供するために、dev:build-serverdev:startdev scriptsをpackage.jsonファイルに追加します。

package.json
"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:*",
  ...
},

サーバーに変更を加えた場合は、nodemonを使用してサーバーを再起動します。そして、npm-run-allを使用して複数のコマンドを並行して実行します。

端末ウィンドウで次のコマンドを入力して、これらのパッケージを今すぐインストールしましょう。

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

または、yarnを使用して次のように行います。

  1. yarn add nodemon@2.0.4 npm-run-all@4.1.5 --dev

このようにして、次のコマンドを実行して、クライアント側のアプリを構築し、サーバーコードをバンドルしてトランスパイルし、:3006でサーバーを起動できます。

  1. npm run dev

または、yarnを使用して次のように行います。

  1. yarn run dev

サーバーのwebpack設定により変更を監視し、サーバーは変更時に再起動します。ただし、クライアントアプリの場合は、現在のところ、変更を加えるたびに構築する必要があります。ここに、未解決の課題があります。

ここで、Webブラウザでhttp://localhost:3006/を開くと、サーバー側のレンダリングアプリが表示されます。

前回、ソースコードは次のように表示しました。

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

しかし今回は、変更を加えたことで、ソースコードは次のように表示します。

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

サーバー側のレンダリングにより、<App>コンポーネントがHTMLに正常に変換されました。

まとめ

このチュートリアルでは、Reactアプリを初期化し、サーバー側のレンダリングを有効にしました。

この投稿では、実行できることの内容に軽く触れただけです。ルーティング、データフェッチ、またはReduxもサーバーサイドのレンダリングアプリの一部になる必要があると、作業は少し複雑になりがちです。

SSRの使用の主な利点の1つは、JavaScriptコードを実行しないクローラーでも、コンテンツをクロールできるアプリケーションがあることです。これは、検索エンジン最適化(SEO)と、ソーシャルメディアチャネルへのメタデータの提供に役立ちます。

最初のリクエストで、サーバーから完全にロードされたアプリケーションが送信されるため、SSRはパフォーマンスの向上にもとても役立ちます。重要なアプリケーションの場合、SSRには少し複雑になる可能性のあるセットアップが必要であり、サーバーに大きな負荷がかかるため、有用性が異なる場合があります。Reactアプリにサーバー側のレンダリングを使用するかどうかは、特定のニーズと、どのトレイドオフがユースケースにとって最適であるかに依存します。

React について詳しく知りたい場合は、How To Code in React.js(React.js のコーディング方法) シリーズを参照するか、演習とプログラミングプロジェクトの React トピックページをご覧ください。


Want to learn more? Join the DigitalOcean Community!

Join our DigitalOcean community of over a million developers for free! Get help and share knowledge in our Questions & Answers section, find tutorials and tools that will help you grow as a developer and scale your project or business, and subscribe to topics of interest.

Sign up
About the authors
Default avatar
Developer and author at DigitalOcean.

Default avatar
Developer and author at DigitalOcean.

Still looking for an answer?

Was this helpful?
Leave a comment

This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!