One place for hosting & domains

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

      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アプリを呼び出しましょう。

      • npx create-react-app@3.4.1 my-ssr-app

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

      cd my-ssr-app
      

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

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

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

      次に、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ファイルを開きます。

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

      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ファイルを開きましょう。

      次に、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を使用します。端末ウィンドウに次のコマンドを入力して、プロジェクトに追加しましょう。

      • npm install express@4.17.1

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

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

      次に、Expressサーバーコードを含む新しい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スクリプトの設定

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

      • 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を使用して次のように行います。

      • 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の設定ファイルを作成します。

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

      .babelrc.json

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

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

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

      その後、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スクリプトを追加します。

      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を使用して複数のコマンドを並行して実行します。

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

      • npm install nodemon@2.0.4 npm-run-all@4.1.5 --save-dev

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

      • yarn add nodemon@2.0.4 npm-run-all@4.1.5 --dev

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

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

      サーバーの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 トピックページをご覧ください。



      Source link