mcpField
C
cloudinary-react

cloudinary-react

github.com/cloudinary-devs開発13665 回インストール6 週間前に更新
リポジトリ

cloudinary-react について

cloudinary-react は、Cloudinary 機能を構築・デバッグする React 開発者向けのスキルです。画像、動画、アップロード、変換の設定例と、複数のバンドラーに関するトラブルシューティングを扱います。

主な機能

  1. 01再利用可能な Cloudinary インスタンスの設定
  2. 02Upload Widget の導入
  3. 03署名付き・署名なしアップロードの実装
  4. 04画像と動画の変換
  5. 05環境変数やプレーヤーの問題の調査

活用シーン

  1. 01React アプリで変換済み画像を表示
  2. 02アプリに Cloudinary アップロード機能を追加
  3. 03Upload Widget や動画プレーヤーのエラーを調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/cloudinary-devs/skills --skill cloudinary-react

インストール後、Claude Code で/cloudinary-reactを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
signed-uploads.md
troubleshooting.md
typescript-patterns.md
video-player.md

詳細

Cloudinary React スキル

使用する場面

  • ユーザーが React アプリ(Vite、Create React App、Parcel など)で Cloudinary を構築またはデバッグしている場合。
  • アップロードウィジェット、AdvancedImage/AdvancedVideo、変換、オーバーレイ、画像ギャラリー、ビデオプレーヤー、署名付き/署名なしアップロードの実装や修正を行う場合。
  • 「createUploadWidget is not a function」、@cloudinary/url-gen からの誤ったインポート、アップロードプリセットの問題、ビデオプレーヤーの DOM エラーなどが発生した場合。

クイックスタート

よく使われる操作:

  1. セットアップ:cld インスタンスを含む設定ファイルを作成します(「プロジェクトのセットアップ」セクションを参照)。
  2. 画像の表示:const img = cld.image('id').resize(fill().width(800)); <AdvancedImage cldImg={img} />
  3. アップロードウィジェット:index.html にスクリプトを追加し、useEffect で createUploadWidget をポーリングします。
  4. 画像オーバーレイ:source(text(...)) または source(image(...)) を使います。正確なパスは「インポート参照表」を参照してください。
  5. 署名付きアップロード:references/signed-uploads.md を参照してください。
  6. トラブルシューティング:references/troubleshooting.md を参照してください。

TypeScript の場合:references/typescript-patterns.md を参照してください。 ビデオプレーヤーの場合:references/video-player.md を参照してください。

手順

React で Cloudinary を扱う場合は、以下のパターンとルールに従ってください。指定されたインポートパスとコードパターンを正確に使用し、サブパスを推測したり、存在しない API を作成したりしないでください。


Cloudinary React SDK のパターンとよくあるエラー

対象範囲:このルールは、ブラウザーのアップロードウィジェットを使用する React(ウェブ) に適用されます。デフォルトは Vite です(create-cloudinary-react は Vite を使用します)。ほかのバンドラー(Create React App、Next.js、Parcel など)でも機能しますが、変更が必要なのは 環境変数の読み取り方法のみです。詳しくは、以下の「ほかのバンドラー(Vite 以外)」を参照してください。ルールのみを参照するユーザーは、再利用可能な Cloudinary インスタンス、環境変数、アップロードウィジェット(署名なし/署名付き)、ビデオプレーヤーについて、「プロジェクトのセットアップ(ルールのみ/CLI なし)」を参照してください。React Native のアップロード(署名付きアップロードを含む)については、https://cloudinary.com/documentation/react_native_image_and_video_upload?install_source=skillspack&referrer=react-skill#signed_upload を参照してください。「シークレットを公開せず、バックエンドで署名を生成する」という原則は同じですが、React Native では upload() メソッドとバックエンド SDK の扱いが異なります。

公式ドキュメント

完全な API リファレンスとすべての設定オプションについては、llms.txt 経由で Cloudinary のドキュメントを参照してください:https://cloudinary.com/documentation/llms.txt?install_source=skillspack&referrer=react-skill

このスキルでは、React のパターンとよくあるエラーについて説明します。詳細な API オプション(アップロードウィジェットのすべての設定プロパティ、ビデオプレーヤー API のメソッドなど)については、llms.txt から利用できるドキュメントの Markdown ファイルを参照してください。

重要なリファレンス

**@cloudinary/url-gen の基本ルール:**オーバーレイまたは変換のコードを生成するときは、これらのルールにある「Import reference」テーブルと「Canonical overlay block」のみを使用してください。インポートパスと使用パターンをそのままコピーし、パスを推測したり導き出したりしないでください(例:text と image は actions/overlay ではなく qualifiers/source からインポートします。Position は positioning/Position ではなく qualifiers/position からインポートします)。


📋 パターン(正しい方法)

プロジェクトのセットアップ(ルールのみ/CLI なし)

ユーザーが create-cloudinary-react CLI を使用せず、これらのルールのみを利用している場合は、正しい設定、環境変数、ウィジェットのセットアップを行えるよう、以下を生成してください。

1. 環境変数(.env)
プロジェクトのルートに、Vite のプレフィックスを付けた .env ファイルを作成します(クライアントからのアクセスに必須です)。

  • VITE_CLOUDINARY_CLOUD_NAME=my_cloud(必須 — 実際のクラウド名を使用してください。401 エラーの原因となる文字列 your_cloud_name は絶対に使用しないでください)
  • VITE_CLOUDINARY_UPLOAD_PRESET=my_preset(任意。署名なしアップロードウィジェットには必須です — 実際のプリセット名を使用してください)
  • .env を追加または変更した後は、開発サーバーを再起動してください。コードでは process.env ではなく、import.meta.env.VITE_* を使用します。
  • 再起動後もブラウザーで環境変数が空の場合:Vite が古い値をキャッシュしている可能性があります。node_modules/.vite/ を消去し、開発サーバーを再起動して、ハードリフレッシュ(Cmd+Shift+R / Ctrl+Shift+F5)を行ってください。それでも空の場合は、「Common Errors」の「Vite env not reaching client」を参照してください。

2. 再利用可能な Cloudinary インスタンス(設定)
アプリの他の箇所で単一の cld インスタンスを使用できるように、設定ファイル(例:src/cloudinary/config.ts)を作成します。

import { Cloudinary } from '@cloudinary/url-gen';

const cloudName = import.meta.env.VITE_CLOUDINARY_CLOUD_NAME;
if (!cloudName) {
  throw new Error('VITE_CLOUDINARY_CLOUD_NAME is not set. Add it to .env with the VITE_ prefix.');
}

export const cld = new Cloudinary({ cloud: { cloudName } });
export const uploadPreset = import.meta.env.VITE_CLOUDINARY_UPLOAD_PRESET || '';
  • 再利用可能なインスタンスにはこのパターンを使用してください。それ以外の場所では、import { cld } from './cloudinary/config'(またはユーザーが選んだパス)を記述し、cld.image(publicId)/cld.video(publicId) を呼び出します。 3. アップロードウィジェット(署名なし、一から実装)

厳守するパターン(必ず以下のとおりにしてください):

  1. index.html にスクリプトを追加する(必須):index.html に <script src="https://upload-widget.cloudinary.com/global/all.js" async></script> を追加してください。React からの動的なスクリプト読み込みだけに頼らないでください。不安定です。
  2. useEffect でポーリングする(必須):useEffect 内で setInterval を使って(例:100ms ごとに)、typeof window.cloudinary?.createUploadWidget === 'function' になるまでポーリングしてください。その後にのみウィジェットを作成します。単一のチェック(onload 内でのチェックも含む)では信頼できません。createUploadWidget が追加される前に window.cloudinary が存在することがあるためです。
  3. タイムアウトを追加する:タイムアウト(例:10秒)を設定し、スクリプトが読み込まれない場合はポーリングを停止してエラーを表示してください。クリーンアップ時にインターバルとタイムアウトの両方をクリアします。
  4. ウィジェットは一度だけ作成する:createUploadWidget が利用可能になったらウィジェットを作成し、ref に保存してください。インターバルとタイムアウトをクリアします。オプションには { cloudName, uploadPreset, sources: ['local', 'camera', 'url'], multiple: false } を渡します。
  5. クリック時に開く:ボタンにクリックリスナーを設定し、widgetRef.current?.open() を呼び出してください。useEffect のクリーンアップ時にリスナーを削除します。

❌ してはいけないこと:window.cloudinary だけをチェックする(不十分);onload で一度だけチェックする(信頼できない);index.html へのスクリプト追加を省略する;タイムアウトなしでポーリングし続ける。

  • 署名付きアップロード:uploadPreset だけを使わないでください。「Secure (Signed) Uploads」にあるパターンを使います(関数としての uploadSignature、api_key の取得、サーバーで署名に upload_preset を含める)。

4. ビデオプレーヤー

  • 命令型のビデオ要素のみを使用します(document.createElement で作成し、コンテナーの ref に追加して、videoPlayer に渡します)。完全なパターンについては「Cloudinary Video Player (The Player)」を参照してください。

5. ルールのみを確認するユーザー向けの概要

  • 環境変数:バンドラーのクライアント用環境変数プレフィックスとアクセス方法を使用します(Vite の場合:VITE_ + import.meta.env.VITE_*;Vite 以外の場合は「Other bundlers」を参照)。
  • 再利用可能なインスタンス:@cloudinary/url-gen から cld(および必要に応じて uploadPreset)を作成してエクスポートする設定ファイルを1つ用意し、すべての箇所で使用します。
  • アップロードウィジェット:index.html にスクリプトを追加する(必須);useEffect で createUploadWidget が関数になるまでポーリングし、その後ウィジェットを一度だけ作成して ref に保存する;署名なしの場合は cloudName + uploadPreset;署名付きの場合は uploadSignature 関数とバックエンドを使用する。
  • ビデオプレーヤー:命令型のビデオ要素(createElement で作成し、コンテナーの ref に追加して、videoPlayer に渡す);クリーンアップ時に破棄して removeChild を実行する;初期化に失敗した場合は AdvancedVideo にフォールバックする。

Vite を使用していない場合: 設定ファイルおよび環境変数を読み取るすべての箇所で、バンドラーのクライアント用環境変数プレフィックスとアクセス方法を使用してください。例:Create React App → REACT_APP_CLOUDINARY_CLOUD_NAME、process.env.REACT_APP_CLOUDINARY_CLOUD_NAME;Next.js(クライアント)→ NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME、process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME。それ以外(cld インスタンス、ウィジェットのオプション、ビデオプレーヤー)は同じです。

環境変数

  • デフォルト:Vite — Vite では VITE_ プレフィックスが必要です。process.env ではなく、import.meta.env.VITE_CLOUDINARY_CLOUD_NAME を使用してください。.env を変更した後は、開発サーバーを再起動してください。
  • ✅ 正しい例(Vite):.env に VITE_CLOUDINARY_CLOUD_NAME=mycloud を設定し、import.meta.env.VITE_CLOUDINARY_CLOUD_NAME を使用します。
  • ❌ 誤り:VITE_CLOUDINARY_CLOUD_NAME=your_cloud_name — リテラルのプレースホルダー your_cloud_name は絶対に使用しないでください。401 エラーの原因になります。Cloudinary ダッシュボードに表示されている実際のクラウド名を使用してください。
  • ⚠️ Vite の環境変数がクライアントに反映されない場合:再起動後もブラウザーで import.meta.env.VITE_CLOUDINARY_CLOUD_NAME が undefined のままの場合は、以下を行ってください。
    1. Vite のキャッシュをクリアします:rm -rf node_modules/.vite/(または node_modules/.vite フォルダーを削除します)
    2. 開発サーバーを再起動します:npm run dev
    3. ブラウザーを強制的に再読み込みします:Cmd+Shift+R(Mac)または Ctrl+Shift+F5(Windows/Linux)
    4. それでも空の場合は、静的設定で回避します(開発用にクラウド名をハードコードした cloudinaryConfig.ts を作成し、後で環境変数に戻します)。「よくあるエラー」→「VITE_ プレフィックスが必要、または環境変数が undefined」の項目も参照してください。

その他のバンドラー(Vite 以外)

  • 変更するのは環境変数へのアクセス方法のみです。 再利用可能な cld、Upload Widget、Video Player、オーバーレイ、署名付きアップロードなど、その他すべてのパターンはバンドラーに依存しません。
  • Create React App:REACT_APP_ プレフィックスを使用します。process.env.REACT_APP_CLOUDINARY_CLOUD_NAME、process.env.REACT_APP_CLOUDINARY_UPLOAD_PRESET でアクセスします。.env の変更後は、開発サーバーを再起動してください。
  • Next.js(クライアント):クライアント側では NEXT_PUBLIC_ プレフィックスを使用します。process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME などでアクセスします。サーバー側では NEXT_PUBLIC_ を付けずに process.env.CLOUDINARY_* を使用できます。
  • Parcel / その他:「クライアントに環境変数を公開する方法」について、バンドラーのドキュメントを確認してください(多くの場合、プレフィックスまたは許可リストが必要です)。そのプレフィックスと、ドキュメントに記載されたアクセス方法(例:process.env.*)を使用してください。
  • 設定ファイル:src/cloudinary/config.ts(または同等のファイル)で、使用するバンドラーの環境変数 API を使ってクラウド名とアップロードプリセットを読み込みます(例:CRA の場合は process.env.REACT_APP_CLOUDINARY_CLOUD_NAME)。new Cloudinary({ cloud: { cloudName } }) とエクスポートは同じです。変更するのは環境変数を読み込む行だけです。

アップロードプリセット

  • Unsigned = クライアントのみでのアップロード(バックエンド不要)。Signed = バックエンドが必要で、より安全です。どちらを使うべきかについては、以下の**「署名付きアップロードと署名なしアップロード」**を参照してください。
  • ✅ 簡単なクライアントアップロード用に、署名なしアップロードプリセットを作成します:https://console.cloudinary.com/app/settings/upload/presets
  • ✅ .env にプリセットを設定します:VITE_CLOUDINARY_UPLOAD_PRESET=your-preset-name
  • ✅ コードで使用します:import { uploadPreset } from './cloudinary/config'
  • ⚠️ アップロードプリセットがない場合、Upload Widget にエラーメッセージが表示されます。
  • ⚠️ クライアント側で使用するには、アップロードプリセットを「Unsigned」モードに設定する必要があります(API キーやシークレットは不要です)。
  • 署名なしアップロードに失敗した場合:まず、ユーザーがアップロードプリセットを設定したことを確認してください。
    1. .env に VITE_CLOUDINARY_UPLOAD_PRESET が設定されていますか?(プリセット名と完全に一致している必要があります)
    2. ダッシュボードの「Settings」→「Upload」→「Upload presets」にプリセットがありますか?
    3. プリセットは**「Unsigned」**(「Signed」ではない)に設定されていますか?
    4. .env の追加または更新後に、開発サーバーを再起動しましたか?

Cloudinary パッケージのインストール

  • ✅ 最新バージョンをインストールする:Cloudinary パッケージを追加するときは、npm install <package> のようにバージョンを指定せず、npm が互換性のある最新バージョンをインストールするようにします(例:npm install cloudinary-video-player)。package.json では、今後のインストールで互換性のある最新バージョンが取得されるよう、キャレット範囲を指定します(例:"cloudinary-video-player": "^1.0.0")。npm に存在することを確認していない限り、正確なバージョンを固定しないでください。
  • ✅ パッケージ名のみを使用する:次の名前のみを使用してください:@cloudinary/react、@cloudinary/url-gen、cloudinary-video-player(単独のプレーヤー)、cloudinary(Node のサーバーサイド専用)。名前を推測して作らないでください(例:@cloudinary/video-player は使用しないでください)。
  • ❌ 誤り:npm install [email protected] または "cloudinary-video-player": "1.2.3"(バージョンの固定)— バージョンが存在しない場合があり、インストールが失敗します。
  • ✅ 正しい例:npm install cloudinary-video-player(バージョン指定なし)、または package.json に "cloudinary-video-player": "^1.0.0"(キャレット=互換性のある最新バージョン)を指定します。

インポートパターン

  • ✅ Cloudinary インスタンスをインポートする:import { cld } from './cloudinary/config'
  • ✅ コンポーネントをインポートする:import { AdvancedImage, AdvancedVideo } from '@cloudinary/react'
  • ✅ プラグインをインポートする:import { responsive, lazyload, placeholder } from '@cloudinary/react'
  • ✅ 変換とオーバーレイには、「Import reference: @cloudinary/url-gen」と以下の「Canonical overlay block」に記載されている正確なパスのみを使用してください。サブパスを推測しないでください(例:text と image は actions/overlay ではなく qualifiers/source にあります)。

インポートの参照:@cloudinary/url-gen(以下の正確なパスのみを使用)

ルール: @cloudinary/url-gen のインポートパスを作り出したり、推測したりしないでください。以下の表と標準ブロックに記載されたパスのみを使用してください。インポート文は正確にコピーし、パスから類推して作成しないでください(例:@cloudinary/url-gen/overlay がエクスポートするのは source のみです。text と image は qualifiers/source から、Position は positioning/Position ではなく qualifiers/position からインポートします)。誤ったパスを指定すると、「module not found」または「does not exist」というエラーが発生します。

用途正確なインポート
Cloudinary インスタンス(設定)import { Cloudinary } from '@cloudinary/url-gen';
リサイズ(fill)import { fill } from '@cloudinary/url-gen/actions/resize';
リサイズ(scale、オーバーレイ用)import { scale } from '@cloudinary/url-gen/actions/resize';
配信形式/品質import { format, quality } from '@cloudinary/url-gen/actions/delivery';
フォーマット修飾子(auto)import { auto } from '@cloudinary/url-gen/qualifiers/format';
品質修飾子(auto)import { auto as autoQuality } from '@cloudinary/url-gen/qualifiers/quality';
エフェクト(例:ぼかし)import { blur } from '@cloudinary/url-gen/actions/effect';
オーバーレイのソースimport { source } from '@cloudinary/url-gen/actions/overlay';
オーバーレイのテキスト/画像(ソースタイプ)import { text, image } from '@cloudinary/url-gen/qualifiers/source';
オーバーレイ画像の変換import { Transformation } from '@cloudinary/url-gen/transformation/Transformation';
位置(オーバーレイ)import { Position } from '@cloudinary/url-gen/qualifiers/position';
グラビティ/方位import { compass } from '@cloudinary/url-gen/qualifiers/gravity';
テキストスタイル(オーバーレイ)import { TextStyle } from '@cloudinary/url-gen/qualifiers/textStyle';
型import type { CloudinaryImage, CloudinaryVideo } from '@cloudinary/url-gen';

標準のオーバーレイブロック(以下のインポートとパターンを正確にコピーしてください):

// Overlay imports — text/image from qualifiers/source, NOT actions/overlay
import { source } from '@cloudinary/url-gen/actions/overlay';
import { text, image } from '@cloudinary/url-gen/qualifiers/source';
import { Position } from '@cloudinary/url-gen/qualifiers/position';
import { TextStyle } from '@cloudinary/url-gen/qualifiers/textStyle';
import { compass } from '@cloudinary/url-gen/qualifiers/gravity';
import { Transformation } from '@cloudinary/url-gen/transformation/Transformation';
import { scale } from '@cloudinary/url-gen/actions/resize';

// Text overlay (compass with underscores: 'south_east', 'center')
cld.image('id').overlay(
  source(text('Hello', new TextStyle('Arial', 60).fontWeight('bold')).textColor('white'))
    .position(new Position().gravity(compass('center')))
);

// Image overlay (logo/image with resize)
cld.image('id').overlay(
  source(image('logo').transformation(new Transformation().resize(scale().width(100))))
    .position(new Position().gravity(compass('south_east')).offsetX(20).offsetY(20))
);
  • コンポーネント(AdvancedImage、AdvancedVideo、プラグイン)は @cloudinary/url-gen ではなく @cloudinary/react からインポートします。
  • 変換アクションと修飾子(リサイズ、配信、エフェクト、オーバーレイなど)は、上記の正確なサブパスを使って @cloudinary/url-gen/actions/* および @cloudinary/url-gen/qualifiers/* からインポートします。
  • インポートに失敗した場合は、パッケージのバージョン(package.json 内の @cloudinary/url-gen)と、Cloudinary URL-Gen SDK のドキュメント、またはTransformation Builder のリファレンスを確認してください。

画像と動画のインスタンスの作成

  • ✅ 画像インスタンスを作成:const img = cld.image(publicId)
  • ✅ 動画インスタンスを作成:const video = cld.video(publicId)(画像と同じパターンです)
  • ✅ Public ID の形式:フォルダーにはスラッシュを使用します(例:'folder/subfolder/image')
  • ✅ Public ID は大文字と小文字を区別します。ファイル拡張子は含めないでください
  • ✅ サンプルアセット:Cloudinary では samples/ 以下にサンプルアセットが用意されている場合があります。存在しない可能性があるものとして扱ってください(ユーザーが削除する場合があります)。必ず読み込みエラーに対処し、代替手段を用意してください(Image gallery を参照)。アセットが存在する場合は、先にアップロードを求めず、例やデモに使用してください。
  • ✅ 利用可能な場合があるサンプルの Public ID(ギャラリーやデモに使用し、見つからない場合は onError に対処してください):
    • 画像:samples/cloudinary-icon、samples/two-ladies、samples/food/spices、samples/landscapes/beach-boat、samples/bike、samples/landscapes/girl-urban-view、samples/animals/reindeer、samples/food/pot-mussels
    • 動画:samples/elephants
  • ✅ デフォルト/最も信頼性の高い方法:単一の画像には samples/cloudinary-icon から始め、ギャラリーやバリエーションには上記のリストを使用してください。ユーザーがアセットをアップロード済みの場合は、そちらを優先してください。
  • ✅ 例:
    const displayImage = cld.image('samples/cloudinary-icon');
    const displayVideo = cld.video('samples/elephants');
    // Gallery: e.g. ['samples/bike', 'samples/landscapes/beach-boat', 'samples/food/spices', ...]
    

変換パターン

画像の変換
  • ✅ 画像インスタンスに変換をチェーンします:
    const img = cld.image('id')
      .resize(fill().width(800).height(600))
      .effect(blur(800))
      .delivery(format(auto()))
      .delivery(quality(autoQuality()));
    
  • ✅ コンポーネントに渡します:<AdvancedImage cldImg={img} />
動画の変換
  • ✅ 動画インスタンスに変換をチェーンします(画像と同じパターンです):
    const video = cld.video('id')
      .resize(fill().width(800).height(600))
      .delivery(format(auto()));
    
  • ✅ コンポーネントに渡します:<AdvancedVideo cldVid={video} />
  • ✅ 動画の変換は画像の変換と同じ方法で機能します
変換に関するベストプラクティス
  • ✅ フォーマットと品質には、別々の.delivery()呼び出しを使用する必要があります
  • ✅ ユーザーが特定のフォーマットや品質を指定していない限り、最後に必ず自動フォーマットと自動品質を設定します:.delivery(format(auto())).delivery(quality(autoQuality()))
  • ✅ ユーザーが焦点を指定していない限り、gravity(auto())を使用します
  • ✅ 同じ変換構文を画像と動画の両方に使用できます

プラグインのパターン

  • ✅ ユーザーが遅延読み込みやレスポンシブ画像を求めた場合:@cloudinary/reactのCloudinaryプラグイン(responsive()、lazyload()、placeholder())をAdvancedImageと併せて使用します。ネイティブのloading="lazy"やCSSのみのレスポンシブ対応だけを使用しないでください。Cloudinaryプラグインは、Cloudinary URLに対してブレークポイント、遅延読み込み、プレースホルダーを処理します。
  • ✅ プラグインは@cloudinary/reactからインポートします
  • ✅ プラグインは配列として渡します:plugins={[responsive(), lazyload(), placeholder()]}
  • ✅ 推奨されるプラグインの順序:
    1. responsive() - 最初(ブレークポイントを処理)
    2. placeholder() - 2番目(読み込み中にプレースホルダーを表示)
    3. lazyload() - 3番目(ビューポート内に入るまで読み込みを遅延)
    4. accessibility() - 最後(必要な場合)
  • ✅ レイアウトシフトを防ぐため、必ずwidth属性とheight属性を追加します
  • ✅ 例:
    <AdvancedImage
      cldImg={img}
      plugins={[responsive(), placeholder({ mode: 'blur' }), lazyload()]}
      width={800}
      height={600}
    />
    

レスポンシブ画像のパターン

  • ✅ レスポンシブ画像:CSSだけで対応するのではなく、fill()リサイズとCloudinaryのresponsive()プラグインを使用します。遅延読み込み:loading="lazy"だけでなく、AdvancedImageとCloudinaryのlazyload()プラグインを使用します。
  • ✅ fill()リサイズとresponsive()プラグインを使用します
  • ✅ placeholder()プラグインとlazyload()プラグインを組み合わせます
  • ✅ 例:
    const img = cld.image('id').resize(fill().width(800));
    <AdvancedImage 
      cldImg={img} 
      plugins={[responsive(), placeholder({ mode: 'blur' }), lazyload()]} 
      width={800}
      height={600}
    />
    

遅延読み込みとレスポンシブ対応を備えた画像ギャラリー

  • ✅ ユーザーが遅延読み込みとレスポンシブ対応を備えた画像ギャラリーを求めた場合:AdvancedImageとCloudinaryのプラグイン(responsive()、lazyload()、placeholder()。「プラグインのパターン」を参照)を使用します。レスポンシブプラグインにはfill()リサイズを使用します。レイアウトシフトを防ぐため、width属性とheight属性を追加します。
  • ✅ ギャラリーのサンプルアセット:「画像と動画インスタンスの作成」にあるサンプルのパブリックID(例:samples/bike、samples/landscapes/beach-boat、samples/food/spices、samples/two-ladies、samples/landscapes/girl-urban-view、samples/animals/reindeer、samples/food/pot-mussels、samples/cloudinary-icon)を使用します。サンプルが存在しない場合もあることを前提としてください。ユーザーが削除する可能性があります。まず、信頼性の高いサンプル(例:samples/cloudinary-icon)か短いリストから始めます。onError処理を追加し、読み込みに失敗した画像を削除または非表示にします。利用可能な場合は、サンプルよりもアップロード済みのアセット(例:UploadWidgetからのもの)を優先します。
  • ✅ 読み込みエラーに対処する:AdvancedImageでonErrorを使用して、読み込みに失敗した画像を非表示または削除します(例:失敗した画像のpublicIdを除外するように状態を設定する、または親要素を非表示にする)。ユーザーへのフィードバック(例:「読み込めない画像があります。お持ちの画像をアップロードしてみてください!」)と、ユーザーが独自の画像を追加できるアップロード機能を用意します。
  • ✅ フォールバック:ギャラリーのデフォルトリストには、サンプルリストの一部(例:['samples/cloudinary-icon', 'samples/bike', 'samples/landscapes/beach-boat'])を使用できます。ユーザーがアップロードしたら、result.public_idを追加します。画像の読み込みに失敗した場合は、リストから削除するか非表示にして、UIに壊れた画像が表示されないようにします。

画像オーバーレイ(テキストまたはロゴ)

  • ✅ ユーザーがテキストまたはロゴの画像オーバーレイを求めた場合:@cloudinary/url-gen のオーバーレイ API を使用します。このルールの**「インポートのリファレンス」表と「標準のオーバーレイブロック」**から、インポートとパターンをコピーしてください。actions/overlay から text や image をインポートしないでください。これらは qualifiers/source のものです。actions/overlay からインポートするのは source のみです。
  • ✅ actions/overlay から source を、qualifiers/source から text と image をインポートします。また、qualifiers/position から Position、qualifiers/textStyle から TextStyle、qualifiers/gravity から compass、transformation/Transformation から Transformation、actions/resize から scale をインポートします。
  • ✅ compass() は、アンダースコアを含む文字列値を受け取ります:compass('center')、compass('south_east')、compass('north_west')。❌ 誤り:compass(southEast) または 'southEast'(キャメルケースは使いません)。
  • ✅ オーバーレイ画像:.transformation() の中で new Transformation() を使用します:image('logo').transformation(new Transformation().resize(scale().width(100)))。❌ 誤り:image('logo').transformation().resize(...)(.transformation() はチェーン可能なオブジェクトを返しません)。
  • ✅ テキストオーバーレイ:fontWeight は TextStyle に指定します:new TextStyle('Arial', 60).fontWeight('bold')。textColor はテキストソースに指定します(text(...) の後につなげます):text('Hello', new TextStyle('Arial', 60)).textColor('white')。
  • ✅ Position は source(...) の後につなげます。内部には指定しません:source(image('logo').transformation(...)).position(new Position().gravity(compass('south_east')).offsetX(20).offsetY(20))。
  • ✅ 画像オーバーレイのパターン:baseImage.overlay(source(image('id').transformation(new Transformation().resize(scale().width(100)))).position(new Position().gravity(compass('south_east')).offsetX(20).offsetY(20)))。(必要に応じて、@cloudinary/url-gen/actions/resize から scale をインポートします。)
  • ✅ テキストオーバーレイのパターン:baseImage.overlay(source(text('Your Text', new TextStyle('Arial', 60).fontWeight('bold')).textColor('white')).position(new Position().gravity(compass('center'))))。
  • ✅ ドキュメント:React の画像変換と、オーバーレイ構文の変換リファレンス。

アップロードウィジェットのパターン

  • ✅ コンポーネントを使用します:import { UploadWidget } from './cloudinary/UploadWidget'

厳密な初期化パターン(必ずこのとおりにしてください):

  1. ✅ index.html にスクリプトを追加(必須):
<script src="https://upload-widget.cloudinary.com/global/all.js" async></script>
  1. ✅ useEffect で createUploadWidget が利用可能になるまでポーリング(必須):setInterval(例:100ms ごと)を使って、typeof window.cloudinary?.createUploadWidget === 'function' を確認します。これが true を返した場合にのみ、ウィジェットを作成します。準備ができたらインターバルをクリアします。
  2. ✅ タイムアウトを追加(例:10秒)。スクリプトが読み込まれなかった場合はポーリングを停止し、エラー状態を表示します。クリーンアップ時と準備完了時に、インターバルとタイムアウトの両方をクリアします。
  3. ✅ ウィジェットは一度だけ作成し、ref に保存します。クリーンアップでは、インターバルとタイムアウトをクリアし、クリックリスナーを削除します。

❌ 禁止事項:window.cloudinary のみを確認する(関数がまだ設定されていない可能性があります)、onload で一度だけ確認する(タイミングが安定しません)、index.html を省略して動的な読み込みだけに頼る、タイムアウトなしでポーリングを続ける。

  • ✅ ダッシュボードの settings/upload/presets で署名なしのアップロードプリセットを作成します
  • ✅ .env に追加します:VITE_CLOUDINARY_UPLOAD_PRESET=your_preset_name
  • ✅ コールバックを処理します:
    <UploadWidget
      onUploadSuccess={(result) => {
        console.log('Public ID:', result.public_id);
      }}
      onUploadError={(error) => {
        console.error('Upload failed:', error);
      }}
    />
    
  • ✅ アップロード結果には、public_id、secure_url、width、height などが含まれます。

アップロードウィジェットの設定オプション全般(createUploadWidget のすべてのプロパティ)については、公式リファレンスを参照してください:https://cloudinary.com/documentation/upload_widget_reference.md?install_source=skillspack&referrer=react-skill

署名付きアップロードと署名なしアップロード(使い分け)

署名なしアップロード(よりシンプルで、バックエンド不要):

  • 使用する場面:手早いプロトタイプ、リスクの低いアプリ、またはプリセット名を知っている人なら誰でもアップロードできるようにする場合。
  • プリセット:Cloudinary ダッシュボード(Settings → Upload → Upload presets)でUnsignedアップロードプリセットを作成します。プリセット名を .env の VITE_CLOUDINARY_UPLOAD_PRESET に設定します。
  • クライアント:ウィジェットに必要なのは cloudName と uploadPreset のみです。API キーやシークレットは不要で、バックエンドも必要ありません。
  • トレードオフ:プリセット名を知っている人なら誰でもアップロードできます。それを許容できる場合にのみ使用してください。

署名付きアップロード(より安全で、バックエンドが必要):

  • 使用する場面:本番アプリ、認証済みユーザーを利用する場合、またはアップロードできるユーザーを制御する必要がある場合。
  • プリセット:ダッシュボードでSignedアップロードプリセットを作成します。バックエンドが API シークレットを使って署名を生成します。クライアントにシークレットが公開されることはありません。
  • クライアント:ウィジェットには、バックエンドから取得する api_key、uploadPreset、およびアップロードのたびにバックエンドを呼び出す uploadSignature 関数を設定します。API シークレットはサーバー上だけに置きます。
  • トレードオフ:リクエストの署名にバックエンド(Node/Express、Next.js API route など)が必要です。より安全で、署名によって各アップロードが検証されます。

目安:ユーザーから「secure」または「signed」アップロードを明示的に求められない限り、デフォルトでは署名なしアップロードを使用してください。署名付きアップロードをデフォルトにしないでください。実行中のバックエンドが必要なため、設定直後は動作しません。ユーザーがセキュアなアップロードや署名付きアップロードを明示的に求めている場合、またはアップロードできるユーザーを制限する必要がある場合にのみ、署名付きを使用してください。

セキュア(署名付き)アップロード

**使用する場面:**本番アプリ、認証済みユーザーを利用する場合、またはアップロードできるユーザーを制御する必要がある場合(署名なしアップロードより安全です)。

基本ルール:

  1. API シークレットを決して公開またはコミットしないでください(サーバー専用です)
  2. API キー/シークレットには .gitignore 内の server/.env を使用してください
  3. API キーはクライアントに送信できますが、API シークレットはサーバー上だけに置く必要があります

簡単な実装方法:

  • signatureEndpoint ではなく、uploadSignature を関数として使用します
  • ウィジェットを作成する前に、サーバーから api_key を取得します
  • ウィジェットの設定に uploadPreset を含めます
  • サーバー側で署名対象のパラメーターに upload_preset を含めます
  • サーバー側では Cloudinary Node.js SDK v2 を使用します

完全な実装パターン、クライアント/サーバーのコード例、トラブルシューティングについては、references/signed-uploads.md を参照してください。

動画のパターン

  • ✅ 動画を表示する → AdvancedVideo(@cloudinary/react)を使用します。これは動画を表示するだけのコンポーネントです(変換を適用することもできます)。本格的なプレーヤーではありません。
  • ✅ 動画プレーヤーを使う → Cloudinary Video Player(cloudinary-video-player)を使用します。こちらが実際のプレーヤーです(スタイル付き UI、コントロール、プレイリストなど)。
⚠️ 重要:2 つの異なる方法

1. AdvancedVideo(@cloudinary/react)— 動画の表示に使用

  • AdvancedImage に似た React コンポーネントです。Cloudinary の変換を適用した動画を表示します
  • 完全な「プレーヤー」ではなく、動画表示機能です(オプションでコントロールを付けられるネイティブ HTML5 動画)
  • 使用する場面:ユーザーが動画を表示したい場合です。画像で cld.image() を使うのと同様に、cld.video() を使用します

2. Cloudinary Video Player(cloudinary-video-player)— プレーヤー

  • フル機能の動画プレーヤーです(スタイル付き UI、コントロール、プレイリスト)。ユーザーが「動画プレーヤー」を求めている場合に使用します。
  • 命令型の動画要素のみを使用してください(document.createElement で作成し、コンテナーの ref に追加します)。React が管理する <video ref> を渡さないでください。下記の「Cloudinary Video Player(プレーヤー)」を参照してください。
AdvancedVideo(React SDK — 動画の表示用)
  • ✅ 目的:Cloudinary の変換(サイズ変更、エフェクトなど)を適用した動画を表示します。完全なプレーヤーではなく、動画の表示に使用します。プレーヤーが必要な場合は、Cloudinary Video Player を使用してください。
  • ✅ パッケージ:@cloudinary/react(AdvancedImage と同じ)
  • ✅ インポート:import { AdvancedVideo } from '@cloudinary/react'
  • ✅ CSS のインポートは不要:AdvancedVideo はネイティブの HTML5 video を使用するため、CSS のインポートは必要ありません。
  • ❌ 誤り:import '@cloudinary/react/dist/cld-video-player.css'(このパスは存在しません)
  • ✅ 動画インスタンスの作成:const video = cld.video(publicId)(cld.image() と同様)
  • ✅ 変換の適用:画像と同じように、変換をチェーンします。
    const video = cld.video('video-id')
      .resize(fill().width(800).height(600))
      .delivery(format(auto()));
    
  • ✅ コンポーネントの使用:
    <AdvancedVideo
      cldVid={video}
      controls
      autoplay
      muted
    />
    
  • ✅ ドキュメント:https://cloudinary.com/documentation/react_video_transformations.md?install_source=skillspack&referrer=react-skill
Cloudinary Video Player(プレーヤー)

動画プレーヤー(スタイル付き UI、コントロール、プレイリスト)を求められた場合に使用します。動画を表示するだけの場合は、代わりに AdvancedVideo を使用してください。

重要なルール:命令型要素のみ

  • ❌ React が管理する <video ref> を渡さないでください(removeChild エラーの原因になります)
  • ✅ document.createElement('video') を使用し、コンテナーの ref に追加してから、videoPlayer(el, ...) に渡してください

クイックセットアップ:

  • パッケージ:npm install cloudinary-video-player
  • インポート:import { videoPlayer } from 'cloudinary-video-player' と CSS
  • ソース:player.source({ publicId })(文字列ではなくオブジェクト)
  • クリーンアップ:player.dispose() を呼び出してから、if (el.parentNode) el.parentNode.removeChild(el) を実行します
  • 常に posterOptions: { transformation: { startOffset: '0' }, posterColor: '#0f0f0f' } を含めてください

完全な実装パターン、クリーンアップ、エラー処理、トラブルシューティングについては、references/video-player.md を参照してください。

どちらを使うべきですか?
  • ✅ AdvancedVideo を使用する場合:動画を表示したい場合(完全なプレーヤーは不要)。変換を適用して動画を表示するだけです。
  • ✅ Cloudinary Video Player を使用する場合:スタイル付き UI、コントロール、オプション機能(プレイリスト、広告など)を備えた実際の動画プレーヤーを求められた場合。

TypeScript のパターン

TypeScript の基本的な使い方:

  • 型のインポート:import type { CloudinaryImage, CloudinaryVideo } from '@cloudinary/url-gen'
  • アップロード結果:CloudinaryUploadResult インターフェースを定義します
  • 環境変数:ImportMetaEnv インターフェースを含む vite-env.d.ts を作成します
  • any を避ける:適切なインターフェース、または型ガードと併用した unknown を使用します
  • ref の型:useRef<HTMLVideoElement>(null)、ウィジェットには useRef<unknown>(null) を使用します

TypeScript の完全なパターン、型ガード、ref の型指定、エラーの解決方法については、references/typescript-patterns.md を参照してください。

ベストプラクティス

  • ✅ レスポンシブ画像には、重力の自動調整を伴う fill() によるサイズ変更を常に使用します
  • ✅ ユーザーが形式または画質を指定しない限り、変換の最後には常に .delivery(format(auto())).delivery(quality(autoQuality())) を付けます
  • ✅ placeholder() と lazyload() プラグインを併用します
  • ✅ AdvancedImage には常に width と height 属性を追加します
  • ✅ アップロード成功時には、完全な URL ではなく public_id を保存します
  • ✅ 動画プレーヤー:命令型要素のみを使用し、useLayoutEffect のクリーンアップで dispose を呼び出して、if (el.parentNode) el.parentNode.removeChild(el) で要素を削除します。ポスターを確実に表示するため、transformation: { startOffset: '0' } と posterColor: '#0f0f0f' を含む posterOptions を常に指定します
  • ✅ オートコンプリートとエラー検出の改善のため、TypeScript を使用します
  • ✅ 型が利用できない場合は、any より unknown を優先します
  • ✅ 実行時の型チェックには型ガードを使用します
  • ✅ Cloudinary API のレスポンスにはインターフェースを定義します
  • ✅ 環境変数の型指定には vite-env.d.ts を作成します
  • ✅ ref には適切な HTML 要素の型を使用します

⚠️ よくあるエラーと解決方法

詳しいエラーの解決方法とトラブルシューティングについては、references/troubleshooting.md を参照してください。

エラーのクイックリファレンス

環境変数のエラー
  • 環境変数:プレフィックスが誤っている、VITE_ がない、再起動していない → 正しいバンドラープレフィックスを使用し、再起動して、キャッシュをクリアします
  • インポート:パッケージ/パスが誤っている → インポート参照表の正確なパスを使用します
  • アップロードウィジェット:「createUploadWidget is not a function」 → setInterval でポーリングし、window.cloudinary だけをチェックしないでください
  • 変換:動作しない → 正しくチェーンし、v2 構文を使用して、フォーマットと品質を分けます
  • ビデオプレーヤー:removeChild エラー → React の ref ではなく、命令型の要素(createElement)を使用します
  • TypeScript:型エラー → references/typescript-patterns.md を参照してください
  • 署名付きアップロード:署名が無効 → references/signed-uploads.md を参照してください

よくある問題

  1. 環境変数が未定義:node_modules/.vite/ をクリアし、開発サーバーを再起動して、ブラウザーをハードリロードします
  2. 「createUploadWidget is not a function」:typeof window.cloudinary?.createUploadWidget === 'function' になるまで setInterval でポーリングします
  3. インポートの誤り:インポート参照表に記載されたパスのみを使用してください。サブパスを推測しないでください
  4. アップロードに失敗する:プリセットが存在すること、(署名なしの場合は)Unsigned であること、開発サーバーが再起動されていることを確認します
  5. ビデオプレーヤーのエラー:命令型の要素のみを使用し、posterOptions を含めます
  6. オーバーレイの問題:actions/overlay ではなく、qualifiers/source から text/image をインポートします

詳細な解決策を含むトラブルシューティングについては、references/troubleshooting.md を参照してください

コメント