CMS

DrupalとReactの連携方法|JSON:APIのヘッドレス構成と埋め込み手順

DrupalとReactを組み合わせる方法は、大きく2つに分かれます。DrupalをJSON:APIのバックエンドに徹させ、画面はReactが全部持つヘッドレス(デカップルド)構成と、既存のDrupalサイトを残したまま一部のブロックにReactアプリを埋め込む構成です。どちらを選ぶかで、必要なモジュール・ビルド手順・つまずく場所がまるごと変わります。この記事では両方の手順を分けて追い、CORSエラーやビルド成果物の読み込みといった実装で詰まる箇所まで扱います。WordPressとReactの連携方法:ヘッドレス構成とテーマ組み込みの使い分けと同じ判断軸をDrupalに当てはめた内容です。掲載しているコード例は、Drupal 11.4.4のコアに存在しないAPIとReact 19で削除されたAPIを使わない書き方へ差し替えています。

まとめ

結論から言えば、サイト全体をReactで作り直すならヘッドレス構成、既存Drupalサイトに動的な機能を1つ足したいだけなら埋め込み構成です。埋め込みで済む要件にヘッドレスを持ち込むと、SEO対応・プレビュー・キャッシュを自前で作り直すことになり、割に合いません。

  • ヘッドレス構成:Drupal側は jsonapi を有効化するだけで /jsonapi/node/article が生える。JSON:APIはDrupal 8.7からコア同梱で、追加ダウンロードは不要
  • 埋め込み構成:ビルド成果物を *.libraries.yml で宣言し、#attached で添付する。drupal_add_js() はDrupal 11のコアに存在しない
  • CORSエラーはフロントエンドでは直らない。Drupal側の sites/default/services.ymlcors.config(既定は enabled: false)で許可する
  • Reactアプリの雛形に create-react-app は使わない。2025年2月14日にReact公式が非推奨とし、現在はViteなどのビルドツールが推奨

ヘッドレスCMSという選択そのものを検討している段階なら、ヘッドレスCMSとは?従来型CMSとの違い・主要サービス比較と選び方【2026年最新】で全体像を押さえてからDrupalに絞ると判断が早くなります。以下では、両方式の実装手順に加えて、Drupal 7時代のコードをそのまま貼ると動かなくなる箇所も個別に指摘していきます。

DrupalとReactの連携: 初心者向け完全ガイド

DrupalとReactの連携は、現代のウェブ開発において非常に重要なスキルセットです。
このガイドでは、初心者向けにDrupalとReactの基本的な連携方法について解説します。
Drupalは強力なコンテンツ管理システム(CMS)として知られ、Reactは動的なユーザーインターフェースを構築するためのJavaScriptライブラリです。
これらを組み合わせることで、柔軟で高度なウェブアプリケーションを開発することが可能です。

DrupalとReactの連携の基本概要

DrupalとReactを連携するためには、まずそれぞれの基本的な概念を理解する必要があります。
Drupalはバックエンドでコンテンツ管理を行い、Reactはフロントエンドでユーザーインターフェースを構築します。
この連携により、ヘッドレスCMSとしてのDrupalの利点を活かしつつ、ReactのリアクティブなUIを実現できます。

なぜDrupalとReactを連携するのか

DrupalとReactを連携する主な理由は、柔軟性とパフォーマンスです。
Drupalは強力なコンテンツ管理機能を提供し、Reactは迅速なUIレンダリングを可能にします。
この組み合わせにより、エディターやデベロッパーは効率的にコンテンツを管理しつつ、ユーザーに対して優れたエクスペリエンスを提供できます。

DrupalとReactの連携に必要なツールとセットアップ方法

DrupalとReactを連携するためには、いくつかのツールと設定が必要です。
まず、DrupalのAPIモジュールを有効にし、JSON:APIなどのエンドポイントを設定します。
次に、Reactアプリケーションを作成し、AxiosなどのHTTPクライアントを使用してDrupalのAPIと通信します。
これにより、データを取得して表示することが可能になります。

実際のプロジェクトにおけるDrupalとReactの連携事例

実際のプロジェクトでのDrupalとReactの連携事例として、ニュースサイトやEコマースプラットフォームが挙げられます。
例えば、ニュースサイトでは、Drupalで記事を管理し、Reactで記事一覧や詳細ページを動的にレンダリングすることができます。
これにより、ユーザーは素早く記事を閲覧でき、管理者は効率的にコンテンツを更新できます。

トラブルシューティング: よくある問題とその解決方法

DrupalとReactの連携において、よくある問題としては、API通信の失敗やデータの整合性の問題があります。
これらの問題を解決するためには、まずエラーメッセージを確認し、適切なデバッグ手法を用いることが重要です。
また、APIエンドポイントの設定や認証方法を見直すことも有効です。

DrupalとReactコンポーネントの統合方法と実例

DrupalとReactの統合は、ウェブ開発者にとって魅力的なスキルです。
このセクションでは、DrupalとReactコンポーネントの統合方法について具体的な例を交えて解説します。
Drupalは豊富な機能を持つCMSであり、ReactはインタラクティブなUIを提供します。
これらを組み合わせることで、両方の利点を活かしたウェブアプリケーションを構築できます。

DrupalとReactコンポーネントの基本的な統合手法

DrupalとReactの統合の基本は、DrupalのデータをReactコンポーネントに供給することです。
まず、DrupalでRESTful Web Servicesモジュールを有効にし、必要なエンドポイントを設定します。
次に、Reactアプリケーションを作成し、AxiosなどのHTTPクライアントを使用してDrupalのエンドポイントからデータを取得します。

// Reactでデータを取得する例
import React, { useEffect, useState } from 'react';
import axios from 'axios';

const DrupalData = () => {
  const [data, setData] = useState([]);

  useEffect(() => {
    axios.get('https://your-drupal-site.com/jsonapi/node/article')
      .then(response => {
        setData(response.data.data);
      })
      .catch(error => {
        console.error('Error fetching data from Drupal:', error);
      });
  }, []);

  return (
    <div>
      <h1>Drupal Articles</h1>
      <ul>
        {data.map(item => (
          <li key={item.id}>{item.attributes.title}</li>
        ))}
      </ul>
    </div>
  );
};

export default DrupalData;

このコードは、DrupalのJSON:APIエンドポイントから記事データを取得し、Reactコンポーネントで表示する基本的な例です。

DrupalモジュールとReactの統合ポイント

Drupalモジュールを利用することで、Reactとの統合をさらに強化できます。
特に、Viewsモジュールは強力で、カスタムAPIエンドポイントを簡単に作成できます。
例えば、特定の条件に基づいたデータを取得するためのビューを設定し、それをReactアプリケーションで使用することができます。

// Drupalのカスタムモジュール例
function mymodule_views_data_alter(&$data) {
  // ビューのデータをカスタマイズ
  $data['node']['table']['group'] = t('Content');
}

このように、Drupalのカスタムモジュールを使用してビューのデータをカスタマイズし、Reactアプリケーションで効率的に使用できます。

具体的なコード例と解説

次に、具体的なコード例を通じて、DrupalとReactの統合をさらに詳しく見ていきましょう。
以下は、ReactコンポーネントがDrupalからデータを取得して表示する例です。

import React, { useEffect, useState } from 'react';
import axios from 'axios';

const ArticleList = () => {
  const [articles, setArticles] = useState([]);

  useEffect(() => {
    axios.get('https://your-drupal-site.com/jsonapi/node/article')
      .then(response => {
        setArticles(response.data.data);
      })
      .catch(error => {
        console.error('Error fetching articles:', error);
      });
  }, []);

  return (
    <div>
      <h2>Article List</h2>
      <ul>
        {articles.map(article => (
          <li key={article.id}>
            <h3>{article.attributes.title}</h3>
            <p>{article.attributes.body.value}</p>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default ArticleList;

このReactコンポーネントは、DrupalのJSON:APIエンドポイントから記事のリストを取得し、それを画面に表示します。
これにより、動的なデータ表示が可能となります。

一般的なエラーとその解決方法

DrupalとReactの統合中に発生する一般的なエラーには、APIリクエストの失敗やデータの不整合があります。
これらのエラーを解決するための最初のステップは、ブラウザのデベロッパーツールを使用してエラーメッセージを確認することです。
多くの場合、CORSエラーが発生することがあります。
この場合、Drupalのサービス設定を見直し、適切なCORSポリシーを適用する必要があります。

# sites/default/services.yml — CORSの許可設定
cors.config:
  enabled: true
  allowedHeaders: ['Content-Type', 'Authorization']
  allowedMethods: ['GET', 'POST', 'OPTIONS']
  allowedOrigins: ['https://your-react-app.example.com']
  allowedOriginsPatterns: []
  exposedHeaders: false
  maxAge: false
  supportsCredentials: false

cors.config は既定で enabled: false なので、まず有効化が要ります。
設定後は drush cr でキャッシュを再構築しないと反映されません。
exposedHeadersmaxAge の既定値は false で、値を渡すときは
exposedHeaders: ['Content-Type'] のように配列で書きます。true は受け付けません。
allowedOrigins['*'] のまま本番に出すと、任意のサイトからAPIを叩かれます。
公開読み取り専用のエンドポイントでない限り、フロントエンドのオリジンを明示してください。
あわせて、エンドポイントのパスと認証トークンが正しいかも確認します。

Reactコンポーネントの再利用性とメンテナンス

Reactコンポーネントの再利用性とメンテナンス性を高めるためには、コンポーネントを小さく、シンプルに保つことが重要です。
また、コンポーネントの状態管理にはReact Hooksを活用し、必要に応じてReduxなどの状態管理ライブラリを使用することを検討してください。

import React, { useState } from 'react';

const Article = ({ title, body }) => {
  return (
    <div>
      <h3>{title}</h3>
      <p>{body}</p>
    </div>
  );
};

const ArticleList = ({ articles }) => {
  return (
    <div>
      <h2>Article List</h2>
      {articles.map(article => (
        <Article key={article.id} title={article.attributes.title} body={article.attributes.body.value} />
      ))}
    </div>
  );
};

export default ArticleList;

このように、コンポーネントを分割することで再利用性が高まり、メンテナンスもしやすくなります。

DrupalとReactの比較: それぞれの強みと使いどころ

DrupalとReactは、それぞれ異なる目的に最適化された強力なツールです。
このセクションでは、これらの技術の強みとそれぞれが最も適しているユースケースについて詳しく見ていきます。
Drupalはバックエンドのコンテンツ管理システムとして、Reactはフロントエンドのユーザーインターフェース構築ツールとして広く使用されています。

Drupalの強みとユースケース

Drupalの最大の強みは、その強力なコンテンツ管理機能にあります。
特に、大規模なウェブサイトや複雑なコンテンツ構造を持つプロジェクトにおいて、その真価を発揮します。
Drupalは、コンテンツタイプ、タクソノミー、ビューなど、豊富な機能を提供し、サイト管理者が柔軟にコンテンツを管理できるようにします。

// mymodule.install — カスタムコンテンツタイプをインストール時に作成する
use Drupal\node\Entity\NodeType;

function mymodule_install() {
  NodeType::create([
    'type' => 'custom_content_type',
    'name' => 'Custom Content Type',
    'description' => 'A custom content type for demonstration.',
  ])->save();
}

このコードは、コンテンツタイプを設定エンティティとして作成する例です。
コンテンツタイプはDrupal 8以降、node.type.* の設定エンティティになりました。
Drupal 7で使われていた node_add_type() はDrupal 11.4.4のコアに存在しないため、
古い記事のコードをそのまま貼ると未定義関数エラーになります。
プロパティも type / name / description が正で、base は受け取りません。

Reactの強みとユースケース

Reactの強みは、その高速なレンダリングと再利用可能なコンポーネントベースのアーキテクチャにあります。
Reactは、動的でインタラクティブなユーザーインターフェースを迅速に構築するのに最適です。
特に、シングルページアプリケーション(SPA)や、リアルタイム更新が必要なアプリケーションに適しています。

// Reactでシンプルなコンポーネントを作成する例
import React from 'react';

const HelloWorld = () => {
  return (
    <div>
      <h1>Hello, World!</h1>
    </div>
  );
};

export default HelloWorld;

このコードは、Reactでシンプルな「Hello, World!」コンポーネントを作成する基本的な例です。
Reactのコンポーネントは再利用可能で、他のコンポーネントに簡単に組み込むことができます。

DrupalとReactのパフォーマンス比較

DrupalとReactのパフォーマンスは、それぞれのユースケースに応じて異なります。
Drupalはサーバーサイドレンダリングを行うため、初期読み込みが遅くなることがありますが、バックエンド処理が強力です。
一方、Reactはクライアントサイドレンダリングを行い、初期読み込みが速く、ユーザーインターフェースのレスポンスが迅速です。

// Reactのパフォーマンス最適化の例
import React, { useMemo } from 'react';

const ExpensiveComponent = ({ items }) => {
  const computedItems = useMemo(() => {
    return items.map(item => item * 2); // 計算が高コストな処理
  }, [items]);

  return (
    <div>
      {computedItems.map((item, index) => (
        <div key={index}>{item}</div>
      ))}
    </div>
  );
};

export default ExpensiveComponent;

このコードは、ReactのuseMemoフックを使用してパフォーマンスを最適化する例です。
高コストな計算処理を最小限に抑えることで、UIのレンダリングを効率化します。

DrupalとReactのセキュリティ面での比較

セキュリティは、ウェブアプリケーション開発において非常に重要な要素です。
Drupalは、堅牢なセキュリティ機能を提供し、多くのセキュリティアップデートが定期的に行われます。
特に、ユーザー認証やアクセス制御において優れています。
一方、Reactはクライアントサイドで動作するため、適切なセキュリティ対策が必要です。
例えば、XSS(クロスサイトスクリプティング)攻撃に対する対策が重要です。

// ReactでXSS対策を行う例
import React from 'react';
import DOMPurify from 'dompurify';

const SafeComponent = ({ htmlContent }) => {
  const cleanHTML = DOMPurify.sanitize(htmlContent);

  return (
    <div dangerouslySetInnerHTML={{ __html: cleanHTML }} />
  );
};

export default SafeComponent;

このコードは、ReactでDOMPurifyを使用して、XSS攻撃に対する対策を行う例です。
ユーザー入力を表示する際には、必ずサニタイズすることで、セキュリティを強化します。

プロジェクトにおけるDrupalとReactの選択基準

プロジェクトにおいてDrupalとReactのどちらを選択するかは、プロジェクトの要件に大きく依存します。
大規模なコンテンツ管理が必要な場合はDrupalが適しており、動的でインタラクティブなユーザーインターフェースが求められる場合はReactが適しています。
また、両者を組み合わせることで、両方の利点を活かしたハイブリッドアプローチも可能です。

# mymodule.routing.yml — 経路の定義
mymodule.page:
  path: '/mymodule'
  defaults:
    _controller: '\Drupal\mymodule\Controller\MyModuleController::page'
    _title: 'My Module'
  requirements:
    _access: 'TRUE'
// src/Controller/MyModuleController.php — 経路が呼ぶ処理
namespace Drupal\mymodule\Controller;

use Drupal\Core\Controller\ControllerBase;

class MyModuleController extends ControllerBase {

  public function page() {
    return ['#markup' => $this->t('Welcome to my custom module!')];
  }

}

この2ファイルが、カスタムのURLを1本生やす最小構成です。
経路の宣言(YAML)と処理(コントローラークラス)が分かれている点がDrupal 7と大きく違います。
Drupal 7の hook_menu() はDrupal 11.4.4のコアに存在せず、実装しても呼ばれません。

// Reactで基本的な状態管理を行う例
import React, { useState } from 'react';

const Counter = () => {
  const [count, setCount] = useState(0);

  return (
    <div>
      <h1>{count}</h1>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
};

export default Counter;

このコードは、Reactで基本的な状態管理を行う例です。
useStateフックを使用してコンポーネントの状態を管理し、ユーザーインターフェースを更新します。

DrupalとReactでデカップルドアーキテクチャを構築する方法

デカップルドアーキテクチャは、フロントエンドとバックエンドを明確に分離することで、各部分を独立して開発およびデプロイできる利点があります。
このセクションでは、DrupalとReactを使用してデカップルドアーキテクチャを構築する方法を詳しく解説します。

デカップルドアーキテクチャの基本概念

デカップルドアーキテクチャでは、バックエンドとフロントエンドが独立したシステムとして機能します。
Drupalはバックエンドでコンテンツ管理を担当し、Reactはフロントエンドでユーザーインターフェースを提供します。
この構成により、開発者はそれぞれの部分を独立して開発でき、異なる技術スタックを利用することが可能です。

// src/main.jsx — React 19 でのエントリーポイント
import { createRoot } from 'react-dom/client';
import App from './App';

const root = createRoot(document.getElementById('root'));
root.render(<App />);
# Drupal側のエンドポイントを生やす
drush en jsonapi
drush cr

このコードは、ReactアプリケーションのエントリーポイントとDrupalのAPIエンドポイントの用意です。
これにより、フロントエンドとバックエンドが独立して機能します。
JSON:APIはDrupal 8.7でコア入りしているため追加ダウンロードは不要で、有効化するだけで
/jsonapi/node/article のようなエンドポイントが設定不要で生えます。
なお ReactDOM.render() はReact 18で非推奨になり、React 19で削除されました。
現在は react-dom/clientcreateRoot() を使います。
プレフィックスを /api などへ変えたい場合は、コア外のJSON:API Extrasを導入したうえで
drush cset jsonapi_extras.settings path_prefix api と設定します。
古い記事にある $settings['jsonapi_extras']['api']['prefix'] の行はどこからも読まれず、
settings.phpに書いてもプレフィックスは変わりません。

DrupalとReactのデカップルド構成の利点

デカップルド構成の主な利点は、スケーラビリティと柔軟性の向上です。
バックエンドとフロントエンドが独立しているため、それぞれをスケールアップやスケールアウトすることが容易です。
また、異なるチームが独立して作業できるため、開発の効率が向上します。
さらに、新しい技術を導入する際にも柔軟に対応できます。

// Axiosを使ったDrupal APIからのデータ取得例
import axios from 'axios';

const fetchArticles = async () => {
  try {
    const response = await axios.get('https://your-drupal-site.com/jsonapi/node/article');
    console.log(response.data);
  } catch (error) {
    console.error('Error fetching articles:', error);
  }
};

fetchArticles();

このコードは、Axiosを使用してDrupal APIからデータを取得する基本的な例です。
フロントエンドとバックエンドが独立しているため、このようにAPIを介してデータをやり取りします。

デカップルドDrupalのセットアップ手順

デカップルドDrupalのセットアップ手順は以下の通りです。
まず、Drupalサイトをインストールし、必要なモジュールを有効にします。
次に、Reactアプリケーションを作成し、APIクライアントを設定します。
最後に、両者を連携させ、必要なデータを取得して表示します。

1. Drupalのインストールとモジュールの有効化

   drush site-install
   drush en jsonapi
   

2. Reactアプリケーションの作成

   npm create vite@latest my-app -- --template react
   cd my-app
   npm install
   

3. Axiosのインストールと設定

   npm install axios
   

4. APIクライアントの設定

   import axios from 'axios';

   const apiClient = axios.create({
     baseURL: 'https://your-drupal-site.com/jsonapi',
     headers: {
       'Content-Type': 'application/vnd.api+json',
     },
   });

   export default apiClient;
   

5. データの取得と表示

   import React, { useEffect, useState } from 'react';
   import apiClient from './apiClient';

   const ArticleList = () => {
     const [articles, setArticles] = useState([]);

     useEffect(() => {
       apiClient.get('/node/article')
         .then(response => {
           setArticles(response.data.data);
         })
         .catch(error => {
           console.error('Error fetching articles:', error);
         });
     }, []);

     return (
       <div>
         <h2>Article List</h2>
         <ul>
           {articles.map(article => (
             <li key={article.id}>{article.attributes.title}</li>
           ))}
         </ul>
       </div>
     );
   };

   export default ArticleList;
   

このセットアップ手順を通じて、デカップルドDrupalとReactの統合が完了します。

デカップルド構成におけるデータ管理方法

デカップルド構成では、データ管理が重要な課題となります。
バックエンドのDrupalはデータの保存と提供を担当し、フロントエンドのReactはそのデータを表示します。
データの一貫性と同期を保つために、GraphQLやJSON:APIを使用して効率的なデータ通信を行うことが推奨されます。

// GraphQLを使用してデータを取得する例
import { ApolloClient, InMemoryCache, gql } from '@apollo/client';

const client = new ApolloClient({
  uri: 'https://your-drupal-site.com/graphql',
  cache: new InMemoryCache()
});

client.query({
  query: gql`
    query {
      articles(limit: 10) {
        items {
          id
          title
        }
      }
    }
  `
}).then(response => {
  console.log(response.data);
});

このコードは、Apollo ClientでGraphQLエンドポイントを叩く例です。
GraphQLを使用することで、必要なデータのみを効率的に取得できます。
ただしJSON:APIと違い、GraphQLはコアに入っていません。コントリビュートモジュールのGraphQLを追加したうえで、
自分でスキーマ(*.graphqls)とリゾルバを定義する必要があります。
上のクエリはモジュール同梱のサンプルスキーマに合わせた形で、そのまま使える汎用フィールドではありません。
クエリのフィールド名は自分が定義したスキーマ次第になります。
エンドポイントのパスもGraphQL Serverの設定エンティティで決めるため、/graphql 固定ではありません。
コンテンツを読むだけならコア同梱のJSON:APIで済むことが多く、GraphQLは
複数エンティティを1リクエストにまとめたい場合の選択肢と考えてください。

デカップルドアーキテクチャのベストプラクティス

デカップルドアーキテクチャのベストプラクティスには、コードの分離、効率的なデータ通信、セキュリティ対策などが含まれます。
フロントエンドとバックエンドのコードベースを明確に分離し、それぞれ独立して開発およびデプロイできるようにします。
また、効率的なデータ通信を行うために、GraphQLやJSON:APIなどの適切なプロトコルを使用し、セキュリティ対策として認証と認可を適切に実装します。

// Reactでのコンポーネント分離例
import React from 'react';

const Article = ({ title, body }) => {
  return (
    <div>
      <h3>{title}</h3>
      <p>{body}</p>
    </div>
  );
};

const ArticleList = ({ articles }) => {
  return (
    <div>
      {articles.map(article => (
        <Article key={article.id} title={article.title} body={article.body} />
      ))}
    </div>
  );
};

export default ArticleList;

このコードは、Reactでコンポーネントを分離する例です。
コンポーネントを分離することで、再利用性が向上し、コードのメンテナンスが容易になります。

DrupalにReactアプリを埋め込む方法: ステップバイステップガイド

DrupalにReactアプリを埋め込むことで、既存のDrupalサイトに動的な機能を追加できます。
このセクションでは、ReactアプリをDrupalに埋め込むための具体的な手順をステップバイステップで解説します。

DrupalにReactアプリを埋め込むための前提条件

まず、DrupalにReactアプリを埋め込むためには、いくつかの前提条件を満たす必要があります。
Drupalサイトが既にインストールされており、適切なモジュール(例:JSON:API、RESTful Web Services)が有効になっていることを確認します。
また、Reactアプリケーションが作成され、ビルドされた状態であることも必要です。

# 必要なDrupalモジュールの有効化
drush en jsonapi
drush en rest

このコマンドは、Drupalで必要なモジュールを有効にする例です。
jsonapirest はどちらもDrupal 11のコアに同梱されているので、追加ダウンロードは要りません。
JSON:APIだけで足りるケースが多く、rest は独自の経路や書式が必要なときに足します。

Reactアプリの準備と構築手順

次に、Reactアプリケーションを準備し、ビルドします。
Reactアプリケーションは、npmやyarnを使用して依存関係をインストールし、ビルドします。

# Reactアプリケーションのビルド
npm install
npm run build

このコマンドは、Reactアプリケーションをビルドする例です。
Viteの既定では dist ディレクトリに静的ファイルが出力されます(build.outDir で変更可)。
このディレクトリの中身をDrupalモジュールやテーマ配下へ配置し、次の手順でアセットライブラリとして読み込みます。

ReactアプリをDrupalに埋め込む具体的な手順

ビルドされたReactアプリケーションをDrupalに埋め込むためには、カスタムモジュールを作成し、Drupalのテーマやブロックを利用してReactアプリケーションを表示します。

# mymodule.libraries.yml — ビルド成果物をアセットライブラリとして宣言
react_app:
  version: 1.0.0
  js:
    js/react-app.js: { attributes: { type: module } }
  css:
    theme:
      css/react-app.css: {}
// mymodule.module — ライブラリを添付する
function mymodule_preprocess_page(&$variables) {
  $variables['#attached']['library'][] = 'mymodule/react_app';
}

Drupal 8以降、アセットの読み込みは *.libraries.yml での宣言と #attached での添付に一本化されました。
記事や古いスニペットに残る drupal_add_js()drupal_add_css()drupal_get_path()
いずれもDrupal 11.4.4のコアに存在せず、そのまま貼ると致命的エラーで白画面になります。
attributestype: module は必須です。Viteが吐くバンドルはESモジュールで、
importimport.meta を含みます。これを通常のスクリプトとして読み込むと
Cannot use import statement outside a module で停止します。
モジュールスクリプトは既定で遅延実行されるため、defer は不要です。
version はキャッシュ更新の鍵になるので、アプリのリリース版に合わせて上げてください。
マウント先の div はブロックプラグインかTwigテンプレート側に置き、
JavaScriptからは document.getElementById('react-app') で拾わせます。
なお hook_preprocess_page() での添付は全ページが対象になります。
特定のページだけで読ませたいなら、ブロックプラグインの #attached に寄せてください。
ファイル名の扱いにも注意が必要です。Viteの既定の出力先は dist で、
dist/assets にハッシュ付きのファイル名で吐かれます。
build.rollupOptions.output で固定名にするか、build.manifest を有効にして
マニフェストから実ファイル名を読む必要があります。

埋め込み後のReactアプリの動作確認

ReactアプリケーションをDrupalに埋め込んだ後は、動作確認を行います。
ブラウザでDrupalサイトを開き、Reactアプリケーションが正しく表示され、動作していることを確認します。
また、コンソールやネットワークタブを確認し、エラーが発生していないかを確認します。

# Drupalサイトのキャッシュクリア
drush cr

このコマンドは、Drupalサイトのキャッシュをクリアする例です。
キャッシュをクリアすることで、最新の変更が反映されます。

Reactアプリ埋め込み時のよくある問題とその解決策

ReactアプリケーションをDrupalに埋め込む際によく発生する問題として、CORSエラーやパスの不整合があります。
パスの不整合は、Reactアプリケーションのルーティング設定を見直すことで解決できます。
CORSは、フロントエンド側ではなくDrupal側で解く問題です。

// src/apiClient.js — クライアント側は通常のヘッダーだけを送る
import axios from 'axios';

const apiClient = axios.create({
  baseURL: 'https://your-drupal-site.com/jsonapi',
  headers: {
    'Content-Type': 'application/vnd.api+json',
  },
});

export default apiClient;

ここで注意したいのが、Access-Control-Allow-Origin をクライアントのリクエストヘッダーに足す書き方です。
これはブラウザに向けてサーバーが返すレスポンスヘッダーなので、クライアントから送っても効果がありません。
むしろプリフライトの許可ヘッダーに含まれず、CORSエラーが増えることさえあります。
許可はDrupal側の sites/default/services.ymlallowedOrigins にフロントエンドのオリジンを列挙して与えます。
JSON:APIのContent-Typeは application/vnd.api+json です。

DrupalとReactの連携によるパフォーマンス最適化手法

DrupalとReactの連携によるパフォーマンス最適化は、ウェブアプリケーションの効率を向上させるために重要です。
このセクションでは、パフォーマンス最適化の基本原則から、具体的な技術、ツールの活用方法までを詳しく解説します。

パフォーマンス最適化の基本原則

パフォーマンス最適化の基本原則は、リソースの効率的な使用とユーザーエクスペリエンスの向上にあります。
具体的には、リクエストの最小化、レスポンスタイムの短縮、アセットの圧縮とキャッシュが重要です。
これにより、ページの読み込み速度を向上させ、ユーザーが快適にサイトを利用できるようになります。

// Reactでコンポーネントのパフォーマンスを最適化する例
import React, { memo } from 'react';

const ExpensiveComponent = memo(({ data }) => {
  // 高コストなレンダリング処理
  return <div>{data}</div>;
});

export default ExpensiveComponent;

このコードは、Reactのmemo関数を使用して高コストなレンダリング処理を最適化する例です。
memoを使用することで、コンポーネントが不必要に再レンダリングされるのを防ぎます。

DrupalとReactの連携によるパフォーマンス向上技術

DrupalとReactの連携によるパフォーマンス向上技術には、サーバーサイドレンダリング(SSR)やコードスプリッティングがあります。
SSRは、初回のページロード時にサーバーでReactコンポーネントをレンダリングし、HTMLをクライアントに送信する手法です。
これにより、ページの読み込み時間が短縮され、SEOも改善されます。

// Reactでサーバーサイドレンダリングを実装する例
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import App from './App';

const html = ReactDOMServer.renderToString(<App />);
console.log(html);

このコードは、Reactでサーバーサイドレンダリングを実装する基本的な例です。
ReactDOMServer.renderToStringを使用して、Reactコンポーネントをサーバー側でレンダリングします。

キャッシュ戦略とその実装方法

キャッシュ戦略は、パフォーマンス最適化において非常に重要です。
キャッシュを適切に設定することで、サーバーへのリクエストを減らし、ページの読み込み速度を向上させることができます。
Drupalでは、キャッシュ設定を調整するためのさまざまなオプションが用意されています。

// Drupalでキャッシュ設定を調整する例
$settings['cache']['bins']['render'] = 'cache.backend.redis';
$settings['cache']['bins']['dynamic_page_cache'] = 'cache.backend.redis';

このコードは、DrupalでRedisをキャッシュバックエンドにする例です。
cache.backend.redis というサービスはコアには無く、コントリビュートモジュールのRedisを
導入して初めて使えます。未導入のままsettings.phpに書くとサイトが起動しなくなるので、
モジュールの導入と接続先の設定を先に済ませてください。

パフォーマンス測定と監視ツールの活用方法

パフォーマンス測定と監視は、最適化の効果を確認するために重要です。
Google LighthouseやNew Relicなどのツールを使用して、ウェブサイトのパフォーマンスを測定し、改善点を特定します。
これらのツールを使用することで、ページの読み込み速度やレスポンスタイムを詳細に分析できます。

// lighthouse.mjs — Lighthouseでパフォーマンスを測定する
import lighthouse from 'lighthouse';
import * as chromeLauncher from 'chrome-launcher';

const chrome = await chromeLauncher.launch({ chromeFlags: ['--headless'] });
const results = await lighthouse('https://example.com', { port: chrome.port });
console.log(results.lhr.categories.performance.score);
await chrome.kill();

このコードは、Lighthouseで指定したURLのパフォーマンスレポートを生成する例です。
Lighthouseはv10でESM専用(package.jsonが type: module)になりました。
そのため require('lighthouse') は関数ではなく名前空間オブジェクトを返し、
古い記事のとおりに呼ぶと lighthouse is not a function で落ちます。
拡張子を .mjs にするか、package.jsonに type: module を書いて import で読み込んでください。

リアルタイムパフォーマンスチューニングのケーススタディ

リアルタイムパフォーマンスチューニングでは、実際のユーザーからのフィードバックを基に即座に調整を行います。
例えば、ユーザーの動作ログを分析してパフォーマンスのボトルネックを特定し、迅速に対応することで、ユーザーエクスペリエンスを継続的に改善します。

// New Relicを使用してリアルタイムでパフォーマンスを監視する例
import newrelic from 'newrelic';

newrelic.startWebTransaction('/api/data', () => {
  // APIリクエストの処理
  fetch('https://example.com/api/data')
    .then(response => response.json())
    .then(data => {
      console.log(data);
      newrelic.endTransaction();
    })
    .catch(error => {
      newrelic.noticeError(error);
    });
});

このコードは、New Relicでリクエスト処理をトランザクションとして記録する例です。
注意したいのは、ESモジュールのアプリでは import newrelic from 'newrelic' を書くだけでは計測が始まらない点です。
node --experimental-loader newrelic/esm-loader.mjs -r newrelic your-program.js のように
起動時にローダーを渡す必要があり、設定ファイルの拡張子も .cjs にします
(エージェント9.1.0以降・Node.js 16.12.0以降)。
この指定を忘れると、エラーもなく計測データだけが空のままになります。

以上の手法を組み合わせることで、DrupalとReactの連携によるパフォーマンス最適化が効果的に実現できます。
パフォーマンス最適化は、ユーザーエクスペリエンスを向上させ、サイトの信頼性と効率を高めるために不可欠です。

よくある質問

DrupalとReactを連携するのに、どのモジュールが必要ですか?

基本はコア同梱の jsonapi だけです。drush en jsonapi で有効化すると /jsonapi/node/article のようなエンドポイントが設定不要で生えます。独自のパスやレスポンス形式が必要なときに、同じくコアの restserialization を足します。GraphQLを使う場合だけ、コア外のコントリビュートモジュールを別途導入する必要があります。

ヘッドレス構成とテーマ埋め込みは、どちらを選べばよいですか?

判断軸は「Drupalが描く画面をどれだけ残すか」です。管理画面のプレビュー、Drupalのキャッシュ、既存テーマの資産を使い続けたいなら埋め込みを選びます。フロントエンドを別チーム・別デプロイで回したい、あるいはWeb以外のクライアントにも同じデータを配りたいならヘッドレスです。検索エンジンからの流入が主要な導線のサイトでヘッドレスにする場合は、サーバーサイドレンダリングか事前生成の仕組みを別途用意する前提で見積もってください。

DrupalとReactの連携でCORSエラーが出ます。どこを直せばよいですか?

Drupal側の sites/default/services.yml です。cors.config は既定で enabled: false なので、有効化して allowedOrigins にReactアプリのオリジンを書き、drush cr でキャッシュを再構築します。React側に Access-Control-Allow-Origin を足す対処法が出回っていますが、これはサーバーが返すレスポンスヘッダーなので、クライアントから送っても効きません。

create-react-appは今も使えますか?

新規プロジェクトでは使わないでください。React公式が2025年2月14日にCreate React Appの非推奨を告知しており、新規インストール時には非推奨の警告が表示されます。クライアントサイドだけのSPAを作るなら npm create vite@latest my-app -- --template react でViteの雛形を使うのが手早い選択です。フレームワークとしてはNext.js・React Router・Expoが公式に案内されています。

DrupalをSPAのバックエンドにすると、SEOはどうなりますか?

クライアントサイドレンダリングだけで組むと、初回のHTMLに本文が乗らないため、クロールと評価が遅れる要因になります。記事コンテンツで検索流入を取るサイトなら、Next.jsなどでサーバーサイドレンダリングか静的生成を挟み、HTMLに本文を含めた状態で返す構成が前提になります。逆に、会員向けのダッシュボードのように検索流入を想定しない画面であれば、クライアントサイドレンダリングのままで問題ありません。

関連記事

資料請求

RELATED POSTS 関連記事