ホームページ > ウェブフロントエンド > jsチュートリアル > React と esbuild を使用した SSR へのシンプルなアプローチ

React と esbuild を使用した SSR へのシンプルなアプローチ

Barbara Streisand
リリース: 2024-12-30 20:56:14
オリジナル
645 人が閲覧しました

このブログでは、React の最新機能を活用して、最小限のツールとフレームワークで軽量で柔軟な React アプリケーションを作成する方法を探ります。 Next.js や Remix などのフレームワークは多くのユースケースに優れていますが、このガイドは、同様の機能を保持しながら完全な制御を行うことに興味がある人向けです。

React 19 がリリースされ、SSR をサポートする新機能が追加されたため、最小限のツールで SSR をサポートする React アプリケーションを作成して実験することにしました。その前に、Next.js が提供する考慮すべき重要な機能を調べてみましょう。

Feature Next.js
SSR (Server-Side Rendering) Built-in with minimal setup.
SSG (Static Site Generation) Built-in with getStaticProps.
Routing File-based routing.
Code Splitting Automatic.
Image Optimization Built-in with next/image.
Performance Optimizations Automatic (e.g., prefetching, critical CSS).
SEO Built-in tools like next/head.

これらの機能に基づいて、最小限のセットアップを作成します。ステップバイステップのガイドは次のとおりです:

目次

  • セットアップ
  • esbuild の構成
  • Express アプリとルーティング
  • React アプリ
  • 走る
  • 次のステップ
  • 参考文献

注: このチュートリアルの内容は、私のリポジトリ https://github.com/willyelm/react-app で見つけることができます

設定

セットアップの前提条件として、Node.js がインストールされており、次のパッケージが必要です:

  • react: コンポーネントベースのインタラクティブな UI ライブラリ。
  • react-dom: React 機能を使用して SSR コンテンツをハイドレートします。
  • react-router-dom: React でルートを処理します。
  • express: 静的 API および REST API 用の Node.js シンプル サーバー。
  • esbuild: TypeScript をトランスパイルし、JS、CSS、SVG、およびその他のファイルをバンドルします。
  • typescript: ソース コードに入力を追加します。

私たちのセットアップは、静的ファイル、パブリック ファイル、および REST API を提供するために Express を使用してルーティングを処理します。次に、react-router-dom を使用してすべてのリクエストを処理します。ブラウザにロードされると、クライアント バンドルは事前レンダリングされたコンテンツをハイドレートし、コンポーネントをインタラクティブにします。このアイデアを図で表したものが次のとおりです。

A Simple Approach to SSR with React and esbuild

この図は、Express アプリがサーバー上で React コンポーネントを事前レンダリングし、HTML を返すことによってリクエストをどのように処理するかを示しています。クライアント側では、React がこれらの事前レンダリングされたコンポーネントをハイドレートして対話性を可能にします。

この図を念頭に置いて、フォルダー構造を作成してみましょう。

react-app/             # This will be our workspace directory.
  - public/            
  - scripts/           
    - build.js         # Bundle our server and client scripts.
    - config.js        # esbuild config to bundle.
    - dev.js           # Bundle on watch mode and run server.
  - src/
    - App/             # Our components will be here.
      - App.tsx        # The main application with browser routing.
      - Home.tsx.      # Our default page component.
      - NotFound.tsx   # Fallback page for unmatched routes.
    - index.tsx        # Hydrate our pre-rendered client app.
    - main.tsx         # Server app with SSR components.
    - style.css        # Initial stylesheet.   
  package.json
  tsconfig.json
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

依存関係を追加して、package.json をセットアップしましょう:

{
  "name": "react-app",
  "type": "module",
  "devDependencies": {
    "@types/express": "^5.0.0",
    "@types/node": "^22.10.2",
    "@types/react": "^19.0.2",
    "@types/react-dom": "^19.0.2",
    "esbuild": "^0.24.2",
    "typescript": "^5.7.2"
  },
  "dependencies": {
    "express": "^4.21.2",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "react-router-dom": "^7.1.0"
  },
  "scripts": {
    "build": "node scripts/build",
    "dev": "node scripts/dev",
    "start": "node dist/main.js"
  }
}
ログイン後にコピー
ログイン後にコピー

注: Node.js が ESM スクリプトを実行できるようにするには、「type」:「module」プロパティが必要です。

Typescript を使用するので、tsconfig.json ファイルを構成します。

{
  "compilerOptions": {
    "esModuleInterop": true,
    "verbatimModuleSyntax": true,
    "noEmit": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "strict": true,
    "lib": ["DOM", "DOM.Iterable", "ES2022"],
    "target": "ES2022",
    "module": "ES2022",
    "moduleResolution": "bundler",
    "jsx": "react-jsx",
    "baseUrl": ".",
    "paths": {
      "src": [
        "./src/"
      ]
    }
  },
  "include": [
    "src"
  ],
  "exclude": [
    "node_modules"
  ]
}
ログイン後にコピー
ログイン後にコピー

エスビルドの構成

なぜエスビルドなのか?他のツールと比較して、esbuild は最小限の機能を維持し、非常に高速で (現時点で最速のバンドラー)、デフォルトで typescript と esm をサポートします。

この設定では、esbuild を使用して開発スクリプトとビルド スクリプトを作成し、クライアント バンドルとサーバー バンドルの両方をトランスパイルします。このセクションでは、ワークスペースの script フォルダーで作業します。

scripts/config.js: このファイルには、スクリプトで共有されるクライアントとサーバーのバンドルの基本構成が含まれます。

import path from 'node:path';
// Working dir
const workspace = process.cwd();
// Server bundle configuration
export const serverConfig = {
  bundle: true,
  platform: 'node', 
  format: 'esm',        // Support esm packages
  packages: 'external', // Omit node packages from our node bundle
  logLevel: 'error',
  sourcemap: 'external',
  entryPoints: {
    main: path.join(workspace, 'src', 'main.tsx') // Express app
  },
  tsconfig: path.join(workspace, 'tsconfig.json'),
  outdir: path.join(workspace, 'dist')
};

// Client bundle configuration
export const clientConfig = {
  bundle: true,
  platform: 'browser',
  format: 'esm',
  sourcemap: 'external',
  logLevel: 'error',
  tsconfig: path.join(workspace, 'tsconfig.json'),
  entryPoints: {
    index: path.join(workspace, 'src', 'index.tsx'), // Client react app
    style: path.join(workspace, 'src', 'style.css')  // Stylesheet
  },
  outdir: path.join(workspace, 'dist', 'static'),    // Served as /static by express
};
ログイン後にコピー
ログイン後にコピー

scripts/dev.js: このスクリプトはクライアント アプリとサーバー アプリの両方をバンドルし、メイン サーバー スクリプトを監視モードで実行します。

react-app/             # This will be our workspace directory.
  - public/            
  - scripts/           
    - build.js         # Bundle our server and client scripts.
    - config.js        # esbuild config to bundle.
    - dev.js           # Bundle on watch mode and run server.
  - src/
    - App/             # Our components will be here.
      - App.tsx        # The main application with browser routing.
      - Home.tsx.      # Our default page component.
      - NotFound.tsx   # Fallback page for unmatched routes.
    - index.tsx        # Hydrate our pre-rendered client app.
    - main.tsx         # Server app with SSR components.
    - style.css        # Initial stylesheet.   
  package.json
  tsconfig.json
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

このスクリプトを使用すると、ワークスペースの package.json で設定されたとおりに npm run dev を実行できるはずです。

scripts/build.js: dev と似ていますが、必要なのは minify を有効にすることだけです。

{
  "name": "react-app",
  "type": "module",
  "devDependencies": {
    "@types/express": "^5.0.0",
    "@types/node": "^22.10.2",
    "@types/react": "^19.0.2",
    "@types/react-dom": "^19.0.2",
    "esbuild": "^0.24.2",
    "typescript": "^5.7.2"
  },
  "dependencies": {
    "express": "^4.21.2",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "react-router-dom": "^7.1.0"
  },
  "scripts": {
    "build": "node scripts/build",
    "dev": "node scripts/dev",
    "start": "node dist/main.js"
  }
}
ログイン後にコピー
ログイン後にコピー

このスクリプトは、npm run build を実行し、npm start を使用してアプリを実行することにより、本番環境で使用できる dist バンドルを生成します。

ノードとクライアント アプリの両方をバンドルするように esbuild を設定したので、Express サーバーの作成を開始して React SSR を実装しましょう。

エクスプレスアプリとルーティング

これは、静的ファイルを提供し、サーバー ルートを処理し、react-router-dom を使用してルートするための Express 静的およびミドルウェア アプローチを使用したシンプルなアプリケーションです。

src/main.tsx: これは、サーバーを初期化し、Express でルートを処理し、React SSR を実装するメインの Node.js アプリケーションです。

{
  "compilerOptions": {
    "esModuleInterop": true,
    "verbatimModuleSyntax": true,
    "noEmit": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "strict": true,
    "lib": ["DOM", "DOM.Iterable", "ES2022"],
    "target": "ES2022",
    "module": "ES2022",
    "moduleResolution": "bundler",
    "jsx": "react-jsx",
    "baseUrl": ".",
    "paths": {
      "src": [
        "./src/"
      ]
    }
  },
  "include": [
    "src"
  ],
  "exclude": [
    "node_modules"
  ]
}
ログイン後にコピー
ログイン後にコピー

反応アプリ

反応アプリは、react-router-dom を使用してルートを処理します。アプリはホームページとハイドレーションをテストするための NotFound ページで構成されます。ホームページにカウンター ボタンを追加し、React 19 を利用します。メタタグのタイトルと説明を更新します。

src/App/Home.tsx: 非常に最小限の FunctionComponent。

import path from 'node:path';
// Working dir
const workspace = process.cwd();
// Server bundle configuration
export const serverConfig = {
  bundle: true,
  platform: 'node', 
  format: 'esm',        // Support esm packages
  packages: 'external', // Omit node packages from our node bundle
  logLevel: 'error',
  sourcemap: 'external',
  entryPoints: {
    main: path.join(workspace, 'src', 'main.tsx') // Express app
  },
  tsconfig: path.join(workspace, 'tsconfig.json'),
  outdir: path.join(workspace, 'dist')
};

// Client bundle configuration
export const clientConfig = {
  bundle: true,
  platform: 'browser',
  format: 'esm',
  sourcemap: 'external',
  logLevel: 'error',
  tsconfig: path.join(workspace, 'tsconfig.json'),
  entryPoints: {
    index: path.join(workspace, 'src', 'index.tsx'), // Client react app
    style: path.join(workspace, 'src', 'style.css')  // Stylesheet
  },
  outdir: path.join(workspace, 'dist', 'static'),    // Served as /static by express
};
ログイン後にコピー
ログイン後にコピー

src/App/NotFound.tsx: ページが見つからない場合のデフォルトの FunctionComponent。

import { spawn } from 'node:child_process';
import path from 'node:path';
import { context } from 'esbuild';
import { serverConfig, clientConfig } from './config.js';
// Working dir
const workspace = process.cwd();
// Dev process
async function dev() {
  // Build server in watch mode
  const serverContext = await context(serverConfig);
  serverContext.watch();
  // Build client in watch mode
  const clientContext = await context(clientConfig);
  clientContext.watch();
  // Run server
  const childProcess = spawn('node', [
    '--watch',
    path.join(workspace, 'dist', 'main.js')
  ], {
    stdio: 'inherit'
  });
  // Kill child process on program interruption
  process.on('SIGINT', () => {
    if (childProcess) {
      childProcess.kill();
    }
    process.exit(0);
  });
}
// Start the dev process
dev();
ログイン後にコピー

src/App/App.tsx:react-router-dom を使用してアプリをセットアップします。

import { build } from 'esbuild';
import { clientConfig, serverConfig } from './config.js';
// build process
async function bundle() {
  // Build server
  await build({
    ...serverConfig,
    minify: true
  });
  // Build client
  await build({
    ...clientConfig,
    minify: true
  });
}
// Start the build process
bundle();
ログイン後にコピー

走る

最後に、esbuild スクリプトを設定し、Express サーバーをセットアップし、React SSR を実装しました。サーバーを実行できます:

import path from 'node:path';
import express, { type Request, type Response } from 'express';
import { renderToPipeableStream } from 'react-dom/server';
import { StaticRouter } from 'react-router';
import { App } from './App/App';

const app = express(); // Create Express App
const port = 3000; // Port to listen
const workspace = process.cwd(); // workspace
// Serve static files like js bundles and css files
app.use('/static', express.static(path.join(workspace, 'dist', 'static')));
// Server files from the /public folder
app.use(express.static(path.join(workspace, 'public')));
// Fallback to render the SSR react app
app.use((request: Request, response: Response) => {
  // React SSR rendering as a stream
  const { pipe } = renderToPipeableStream(
    <html lang="en">
      <head>
        <meta charSet="UTF-8" />
        <link rel='stylesheet' href={`/static/style.css`} />
      </head>
      <body>
        <base href="/" />
        <div>


<p>src/index.tsx: On the client side to activate our components and make them interactive we need to "hydrate".<br>
</p>
<pre class="brush:php;toolbar:false">import { hydrateRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router';
import { App } from './App/App';
// Hydrate pre-renderer #app element
hydrateRoot(
  document.getElementById('app') as HTMLElement,
  <BrowserRouter>
    <App />
  </BrowserRouter>
);
ログイン後にコピー

これにより、[アプリ] がポート 3000 でリッスンしているというメッセージが表示されます。
に移動します http://localhost:3000 で確認してください。

SSR および SEO メタ タグのテスト:

A Simple Approach to SSR with React and esbuild

このチュートリアルのソース コードは、私のリポジトリ willyelm/react-app にもあります

A Simple Approach to SSR with React and esbuild ウィリエルム / 反応アプリ

SSR と esbuild を使用したシンプルな反応アプリのセットアップ

このプロジェクトは、react@19、react-router-dom@7 などの最新機能を利用して SSR を構成します。

依存関係

  • react: コンポーネントベースのインタラクティブな UI ライブラリ。
  • react-dom: React 機能を使用して SSR コンテンツをハイドレートします。
  • react-router-dom: React でルートを処理します。
  • express: 静的 API および REST API 用の Node.js シンプル サーバー。
  • esbuild: TypeScript を Transile し、JS、CSS、SVG、およびその他のファイルをバンドルします。
  • typescript: ソース コードに入力を追加します。

プロジェクトの構造

react-app/             # This will be our workspace directory.
  - public/            
  - scripts/           
    - build.js         # Bundle our server and client scripts.
    - config.js        # esbuild config to bundle.
    - dev.js           # Bundle on watch mode and run server.
  - src/
    - App/             # Our components will be here.
      - App.tsx        # The main application with browser routing.
      - Home.tsx.      # Our default page component.
      - NotFound.tsx   # Fallback page for unmatched routes.
    - index.tsx        # Hydrate our pre-rendered client app.
    - main.tsx         # Server app with SSR components.
    - style.css        # Initial stylesheet.   
  package.json
  tsconfig.json
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
全画面モードに入る 全画面モードを終了します
GitHub で表示

次のステップ

このガイドでは、最小限で柔軟なセットアップに重点を置き、esbuild と Express を使用して SSR を備えた React アプリを構築しました。 React 19、React Router DOM 7、esbuild などの最新ツールを使用して、大規模なフレームワークのオーバーヘッドを回避しながら、高速で効率的なワークフローを実現しました。

この実装を拡張して以下を含めることができます:

  • TailwindCSS: スタイリング用に tailwindcss をサポートするように PostCSS と esbuild を構成します。
  • Jest: Jest と @testing-library を使用した単体テストを追加します。
  • Playwright: Playwright を使用してエンドツーエンドのテストを構成します。
  • SSG: SSG (静的サイト生成) を実装して、パフォーマンスとサーバーの負荷を向上させます。
  • HMR: 開発モードの esbuild で HMR (ホット モジュール交換) をサポートし、効率を高めます。

読んでいただきありがとうございます。コーディングを楽しんでください。

参考文献

  • リアクト 19
  • React ルーター DOM
  • リアクトSSR
  • Express.js
  • TypeScript
  • エスビルド

以上がReact と esbuild を使用した SSR へのシンプルなアプローチの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート