カスタム要素でルーティングを使用する
Liferay DXP 7.4+
カスタム要素クライアント拡張機能は、Liferay のフロントエンド インフラストラクチャを使用して、外部アプリケーションを Liferay プラットフォームに登録し、ウィジェットとしてレンダリングします。 複数のルートを含むアプリケーション (例: React Router) の場合、リモート アプリケーション プロパティを定義して、実行時にウィジェットに使用されるルートを決定できます。 これらのプロパティは、Liferayのリモートアプリケーションメニュー、またはデプロイ後のウィジェットの設定オプションからアプリケーションに設定することができます。
他のタイプのクライアント拡張機能と同様にカスタム要素または IFrame をデプロイすることは、Liferay 7.4 の ベータ機能 です。 このチュートリアルでは、カスタム要素のリモートアプリケーションを異なる方法でデプロイしますが、将来のアップデートまでは、この方法が推奨されます。
このチュートリアルでは、Liferay の create_custom_element.sh スクリプトを使用して基本的な React アプリケーションを作成します。このスクリプトは、 hello-world、 hello-foo、 hello-barの 3 つのルートを持つサンプル アプリを生成します。 アプリケーションをコンパイルし、 .js および .css ファイルをホストした後、アプリケーションを Liferay に登録し、ページウィジェットとしてデプロイします。 最後に、それぞれの代替ルートを使用するように設定します。

カスタム要素クライアントの拡張は、構築、パッケージ化、ホスティングの方法に関係なく、あらゆるテクノロジーを使用できます。 このチュートリアルでは、基本ルーティングを使用したカスタム要素アプリケーションのサンプルのみを提供しています。
create_custom_element.sh を実行するには、最新バージョンの Node.JS、 NPM、および YARNが必要です。 先に進む前に、これらのツールがインストールされていることを確認してください。
Reactアプリケーションの作成、ビルド、ホスティング
-
新しいLiferay DXP 7.4以降のコンテナを起動します。 コンテナが起動する間、次のステップに進むことができます。
docker run -it -m 8g -p 8080:8080 liferay/dxp:2025.q1.6-lts -
別の端末でこのコマンドを実行し、Reactアプリケーションを生成します。
curl -Ls https://github.com/liferay/liferay-portal/raw/master/tools/create_custom_element.sh | bash -s j1v3-custom-element react -
アプリケーションが正常に作成されたことを確認します。
スクリプトは、これらの要素で
j1v3-custom-elementという新しい React アプリケーションを作成します:j1v3-custom-element ├── node_modules ├── README.md ├── package.json ├── public │ └── index.html ├── src │ ├── common │ │ ├── services │ │ │ └── liferay │ │ │ ├── api.js │ │ │ └── liferay.js │ │ └── styles │ │ ├── hello-world.scss │ │ ├── index.scss │ │ └── variables.scss │ ├── index.js │ └── routes │ ├── hello-bar │ │ └── pages │ │ └── HelloBar.js │ ├── hello-foo │ │ └── pages │ │ └── HelloFoo.js │ └── hello-world │ └── pages │ └── HelloWorld.js └── yarn.lock -
新しい
j1v3-custom-elementフォルダに移動し、アプリケーションをビルドします。cd j1v3-custom-elementyarn build -
ビルドが成功したことを確認し、アプリケーションの
.jsと.cssファイルをメモしておきます。Creating an optimized production build... Compiled successfully. File sizes after gzip: 43.51 kB build/static/js/main.114dde4a.js 121 B build/static/css/main.9877909d.css -
メールアドレス test@liferay.com とパスワード testを使用して、
<http://localhost:8080>で Liferay にサインインします。 プロンプトが表示されたら、パスワードを learnに変更します。 -
サイト メニュー (
) を開き、 コンテンツ & データを展開して、 ドキュメントとメディアに移動します。 -
追加 (
) をクリックし、 複数ファイルのアップロードを選択します。 -
.jsと.cssのファイルをアップロードエリアにドラッグ&ドロップしてください。
-
公開をクリックします。
これにより、ファイルが Liferay ドキュメント ライブラリに追加され、リモート アプリケーションの作成に使用する一意の WebDAV URL が割り当てられます。
このチュートリアルでは、デモンストレーションの目的で、アプリケーションの静的リソースを Liferay のドキュメント ライブラリにホストします。 運用環境では、静的リソースのホスティングに最適化されたサーバー上でアプリケーションのファイルをホストする必要があります。
各ファイルの URL を表示するには、 情報 アイコン (
) をクリックし、一度に 1 つのファイルを選択します。 各ファイルのWebDAV URLをコピーし、次のステップで使用するために保存してください。

例:
http://localhost:8080/webdav/guest/document_library/main.114dde4a.jshttp://localhost:8080/webdav/guest/document_library/main.9877909d.css
アプリケーションの登録とデプロイ
-
グローバル メニュー (
) を開き、 アプリケーション タブをクリックして、 リモート アプリに移動します。 -
追加 (
) をクリックします。 -
次の値を入力します。
項目 値 名前 J1V3-Custom-Element 種類 カスタム要素 HTML 要素名 j1v3-custom-elementURL WebDAV URL for the .jsfileCSS の URL .cssファイルのWebDAV URLインスタンス化可能 ✔ ポートレットのカテゴリ名 リモートアプリケーション -
[保存]をクリックします。
保存すると、LiferayはJ1V3-Custom-Elementという名前のウィジェットを作成し、他のページウィジェットと同様にサイトページにデプロイすることができます。 選択したポートレットカテゴリ名の下に表示されます。
J1V3-Custom-Elementはインスタンス化可能なので、1つのページに多数追加し、それぞれを独立した構成にすることが可能です。 この例では、1つのページに2回ウィジェットを追加します.

routeプロパティを使用する場合
自動生成されたアプリには、3つのルートが含まれています。 hello-world、hello-foo、hello-barです。 デフォルトでは、アプリケーションは hello-world のルートを使用します。 ただし、リモートアプリケーションのプロパティを使用して、別のルートを使用するように設定することができます。 これらのプロパティは、 リモート アプリ メニュー または ウィジェットの構成オプションから設定できます。
リモートアプリケーションでルートプロパティを定義する
-
グローバル メニュー (
) を開き、 アプリケーション タブをクリックして、 リモート アプリに移動します。 -
J1V3-Custom-Elementを選択します。

-
プロパティフィールドに
route=hello-fooと入力します。
-
公開をクリックします。
-
デプロイされた両方のウィジェットが
HelloFooルートを使用することを確認します。
ポートレット設定でルートプロパティを定義する
-
J1V3-Custom-Elementウィジェットを含むページを編集します。
-
ウィジェット ヘッダーの オプション (
) → 構成をクリックします。
注Liferay DXP 2025.Q1/Portal GA132 より前では、設定オプションはウィジェットの右上隅に表示されていました。
-
プロパティフィールドに
route=hello-barと入力します。
-
[保存]をクリックします。
-
設定されたウィジェットが
hello-barルートを使用し、もう一方のウィジェットがhello-fooルートを使用したままであることを確認します。
ルートコードの分析
import React from 'react';
import {createRoot} from 'react-dom/client';
import api from './common/services/liferay/api';
import {Liferay} from './common/services/liferay/liferay';
import HelloBar from './routes/hello-bar/pages/HelloBar';
import HelloFoo from './routes/hello-foo/pages/HelloFoo';
import HelloWorld from './routes/hello-world/pages/HelloWorld';
import './common/styles/index.scss';
const App = ({route}) => {
if (route === 'hello-bar') {
return <HelloBar />;
}
if (route === 'hello-foo') {
return <HelloFoo />;
}
return (
<div>
<HelloWorld />
</div>
);
};
class WebComponent extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
createRoot(this).render(
<App
route={this.getAttribute('route')}
/>,
this
);
if (Liferay.ThemeDisplay.isSignedIn()) {
api('o/headless-admin-user/v1.0/my-user-account')
.then((response) => response.json())
.then((response) => {
if (response.givenName) {
const nameElements = document.getElementsByClassName(
'hello-world-name'
);
if (nameElements.length) {
nameElements[0].innerHTML = response.givenName;
}
}
});
}
}
}
const ELEMENT_ID = 'j1v3-custom-element';
if (!customElements.get(ELEMENT_ID)) {
customElements.define(ELEMENT_ID, WebComponent);
}
このindex.jsファイルはWebComponentクラスを作成し、HTMLElementインターフェイスを拡張します。 このクラスは、インターフェースの connectedCallback() 関数を実装します。この関数は、 ReactDOM.render を、 App をパラメーターとして呼び出します。 App が呼び出されると、定義されている "route" 属性がチェックされ、その値が利用可能なルートと比較されます。 hello-fooまたはhello-barのいずれかにマッチする場合、該当するルートを返して描画します。 そうでない場合は、hello-worldを返して描画します。
各ルートは、routesフォルダーからindex.jsファイルにインポートされます。
routes
├── hello-bar
│ └── pages
│ └── HelloBar.js
├── hello-foo
│ └── pages
│ └── HelloFoo.js
└── hello-world
└── pages
└── HelloWorld.js
HelloWorld.js
const HelloWorld = () => (
<div className="hello-world">
<h1>
Hello <span className="hello-world-name">World</span>
</h1>
</div>
);
HelloFoo.js
const HelloFoo = () => (
<div className="hello-foo">
<h1>Hello Foo</h1>
</div>
);
HelloBar.js
const HelloBar = () => (
<div className="hello-bar">
<h1>Hello Bar</h1>
</div>
);