The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

ReactとPatternflyでQuarkusアプリにEyecandyを追加する

コンテナ化された分散型のQuarkusアプリケーションで一般的なパターンとして、別のフロントエンドアプリケーションのための効率的でスケーラブルなバックエンドとして機能することがあります。Kubernetesの世界では、フロントエンドアプリケーションはReact、Angular、Vue.jsなどの純粋なウェブレイヤーPodであり、すべてのRESTコールをQuarkusのサービスレイヤーPodに委ねることができます。

frontend pod pattern

このアプローチには、独立したコンテナのスケーリングと独立したライフサイクルという利点がありますが、小規模なアプリケーションには過剰なエンジニアリングとなる場合があります。

最新のWeb GUI技術に妥協することなく、自己完結型の小さなCRUDアプリケーションを作りたいと思っているのではないでしょうか? Angularでこれを実現する方法を見てきましたが、少なくともGitHubの星の数において、人気の点でAngularを上回っているReactはどうでしょうか?今回は、Reactを統合するだけでなく、 Patternflyと呼ばれるWebコンポーネントフレームワークを使用する方法を紹介します。Patternflyは、リッチで一貫性のあるインタラクティブなGUIを作成するためのパターン、コンポーネント、スタイルを集めたものです。

React/Patternflyのテーブルに表示される原子パーティクルオブジェクトを提供するRESTエンドポイントを持つQuarkus Appを作成してみましょう。最終的なアプリケーションのソースコードは こちらにあります。

ステップ1 - Quarkusプロジェクトの生成

スタータープロジェクトを生成するには、 https://code.quarkus.io にアクセスします。Maven Groupとして "io.quarkus" 、Artifactとして "quarkus-react" を入力します。エクステンションのリストで、 RESTEasy JAX-RSRESTEasy JSON-B を選択します。その後、プロジェクトを生成してダウンロードし、ローカル・マシンで解凍して、お気に入りのIDEでプロジェクト・フォルダを開きます。

ステップ2 - Quarkus RESTエンドポイントの追加

サンプルの GreetingResource.java が存在するJavaパッケージフォルダ/src/main/java/io/quarkusに、 Particle.java という名前の新しいBeanクラスを以下の内容で作成します。

package io.quarkus; public class Particle { private String name; public void setName(String name) { this.name = name; } public String getName() { return this.name; } }

ここで、 ParticleResource.java という新しいRESTリソースクラスを作成し、いくつかのテストパーティクルを返します(ここでは原子物理学的な意味合いは無視します)。

package io.quarkus; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Set; import javax.ws.rs.GET; import javax.ws.rs.Path; @Path("/particles") public class ParticleResource { @GET public Set<Particle> getUsers() { Set <Particle> particleList = Collections.newSetFromMap(Collections.synchronizedMap(new LinkedHashMap<>())); Particle particle = new Particle(); particle.setName("Graviton"); particleList.add(particle); Particle particle2 = new Particle(); particle2.setName("Pentaquark"); particleList.add(particle2); return particleList; } }

開発モードでQuarkusを起動して、すべてが動作するかどうかをテストします。

$ mvn quarkus:dev

新しい端末で、エンドポイントを呼び出して、パーティクルの応答を確認します。

$ curl http://localhost:8080/particles [{"name":"Graviton"},{"name":"Pentaquark"}]

Quarkusのデータレイヤーの準備ができたので、次はReactのGUIを作りましょう。

ステップ3 - Reactプロジェクトの生成

お使いのシステムに Node.jsnpm がインストールされていることを確認してください。必要に応じて、 公式ドキュメントを参照してください。

プロジェクト内に新しいフォルダ/src/main/ webapp を作成し、これをReactプロジェクトのベースフォルダとします。このフォルダで別のターミナルを開き、Reactプロジェクトイニシャライザを実行して、Patternfly Nodeモジュールを追加します。

$ npx create-react-app . $ npm install @patternfly/patternfly --save
Reactアプリを起動すると、デフォルトではポート3000で実行されます。その後、ポート8080でQuarkusのエンドポイントにアクセスしようとすると、 CORSセキュリティポリシーのためにブラウザがこれを阻止します。本番環境では、コンパイルされた静的なReactアプリがポート8080でQuarkusから提供されるため、これは問題になりませんが、開発中はこれが問題になります。

幸いなことに、Reactには未知のエンドポイントへのすべてのリクエストを別のURLに転送する proxy というちょっとした機能があります。 webapp フォルダで package.json ファイルを開き、proxyの行を追加して、すべてのリクエストをQuarkusのポート8080に転送します。

{ "name": "webapp", "version": "0.1.0", "private": true, "dependencies": { "@testing-library/jest-dom": "^5.11.4", "@testing-library/react": "^11.1.0", "@testing-library/user-event": "^12.1.10", "react": "^17.0.1", "react-dom": "^17.0.1", "react-scripts": "4.0.3", "web-vitals": "^1.0.1" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, "proxy": "http://localhost:8080/", "eslintConfig": { "extends": [ "react-app", "react-app/jest" ] }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } }

ステップ4 - Patternflyのテーブルコンポーネントを作成して、データで埋める

Reactプロジェクトの /webapp/index.js にPatternflyのCSSをインポートします。

... import './index.css'; import '@patternfly/patternfly/patternfly.css'; import App from './App'; ...

webapp/srcに components という新しいフォルダを作り、その中に particles.js というファイルを作り、パーティクルオブジェクトのリストをループさせてPatternflyのテーブルを生成します。

import React from 'react' const Particles = ({ particles }) => { return ( <div> <center><h1>Particles List</h1></center> <table class="pf-c-table pf-m-grid-md" role="grid" aria-label="Supersonic Subatomic Particles" id="table-basic"> <caption>Supersonic Subatomic Particles</caption> <thead> <tr role="row"> <th role="columnheader" scope="col">Name</th> </tr> </thead> {particles.map((particle) => ( <tbody role="rowgroup"> <tr role="row"> <td role="cell" data-label="Particle name">{particle.name}</td> </tr> </tbody> ))} </table> </div> ) }; export default Particles

次に、 /webapp/src/App.js を調整して、Quarkusサービスのエンドポイントを呼び出し、レスポンスデータを使ってパーティクルコンポーネントをレンダリングします。

import React, {Component} from 'react'; import Particles from './components/particles' class App extends Component { state = { particles: [] } componentDidMount() { fetch('/particles') .then(res => res.json()) .then((data) => { this.setState({ particles: data }) }) .catch(console.log) } render () { return ( <Particles particles={this.state.particles} /> ); } } export default App;

これで、Reactの開発モードでGUIをテストする準備が整いました。

別のターミナルでQuarkusがまだ起動していることを確認します。

/webapp フォルダ内で実行します。

$ npm start

ブラウザで http://localhost:3000 を開きます。開かない場合は、そのURLに移動してください。Quarkusのパーティクルバックエンドからテーブルが動的に入力されているのがわかると思います。ブラウザの開発者ツールでは、データが実際に http://localhost:3000/particles から取得されていることがわかります。

patternfly table

現在、ダブルデベロッパーモードで運用しています。JavaとJavascriptのどちらかのコードに加えられた変更は、すぐに適用されます。これは開発者にとって至福の時ではないでしょうか。

しかし、コンテナを使ったデプロイについてはどうでしょうか?新しいGUIアプリが完成したら、実行可能なjarやイメージを作成するために、いくつかの調整が必要になります。

ステップ5 - プロジェクトの本番ビルドへの準備

webapp/package.json にprodのビルドフェーズを追加:

... "eject": "react-scripts eject", "prod": "react-scripts build --dest && rsync -a build/* ../resources/META-INF/resources" }, "proxy": "http://localhost:8080/", ...

これにより、静的なReactアセットのプロダクションビルドが行われ、Quarkusのデフォルトの静的ファイル用ディレクトリにコピーされます。

rsyncコマンドは、Linux専用です。他のOSの場合は、同等のコマンドで代用してください。

最後のステップでは、優れた frontend-maven-pluginを pom.xml に追加して、通常の maven ビルドから React のビルドフェーズを起動します。npmとnodeのバージョンを、ローカルにインストールされているものに合わせて調整します。mavenのインストールフェーズでは、実際にこれらの2つのパッケージがインストールされますが、これはCI/CDビルドやこのプロジェクトの起動時に便利です。

<build> ... <plugin> <groupId>com.github.eirslett</groupId> <artifactId>frontend-maven-plugin</artifactId> <version>1.11.2</version> <configuration> <workingDirectory>${project.basedir}/src/main/webapp</workingDirectory> <installDirectory>target</installDirectory> </configuration> <executions> <execution> <id>install node and npm</id> <goals> <goal>install-node-and-npm</goal> </goals> <configuration> <nodeVersion>v14.15.4</nodeVersion> <npmVersion>6.14.10</npmVersion> </configuration> </execution> <execution> <id>npm install</id> <goals> <goal>npm</goal> </goals> <configuration> <arguments>install</arguments> </configuration> </execution> <execution> <id>npm run build</id> <goals> <goal>npm</goal> </goals> <configuration> <arguments>run prod</arguments> </configuration> </execution> </executions> </plugin> </build>

それでは、実行可能なjarをビルドしてみましょう。

$ mvn clean package

他の稼働中の環境をすべて停止してポートを空け、実行します。

$ java -jar target/quarkus-app/quarkus-run.jar

ブラウザで http://localhost:8080 を開くと、最適化された単一のQuarkus jarから実行されているテーブルが表示されます。

まとめ

いくつかの簡単なステップで、ReactとPatternflyの力を使って、Quarkusアプリに洗練された見た目のインタラクティブなGUIを追加することができます。

このアプリを次は ネイティブにコンパイルして、極めて軽量なWebアプリを展開するのはどうでしょうか。あるいは、他の Patternflyコンポーネントを使用して、より洗練されたウェブインターフェイスを作成することもできます。いずれにしても、Quarkusアプリを輝かせるためには、あなたの創造性以外に制限はありません。