フロントエンドをカスタマイズする
シンプルな Dapp の作成、ビルド、デプロイの基本的な方法を理解しデフォルトのプロジェクトファイルとサンプルのフロントエンドにも慣れたところで、プロジェクトのフロントエンドのユーザーエクスペリエンスをカスタマイズするさまざまな方法を試してみたくなったのではないでしょうか。
このチュートリアルでは、 React フレームワークを使って、デフォルトのサンプル Dapp の新しいフロントエンドを作成し、表示されるインターフェイスをカスタマイズするための基本的な修正方法を説明します。 後のチュートリアルでは、ここで紹介したテクニックをさらに発展させていきますが、CSS 、HTML 、JavaScript 、React や他のフレームワークを使ってユーザーインターフェースを構築する方法をすでに知っている場合は、このチュートリアルを読み飛ばしても構いません。
このチュートリアルでは、React フレームワークを使用して、 Canister スマートコントラクトの Document Object Model (DOM) を管理する方法を説明します。 React には独自のカスタム DOM 構文があるため、 JSX で書かれたフロントエンドコードをコンパイルするためには、 webpack の設定を変更する必要があります。React と JSX の使い方の学習については、 React のウェブサイト の Getting start を参照してください。 |
始める前に
チュートリアルを始める前に、以下のことを確認してください:
-
フロントエンド開発のために
node.js
がインストールされており、プロジェクトでnpm install
を使用してパッケージをインストールすることができること。 ローカルのオペレーティングシステムやパッケージマネージャに node をインストールする方法については、Node のウェブサイトを参照してください。 -
DFINITY Canister SDK パッケージを ダウンロード&インストール からダウンロードしてインストールする。
-
IDE として Visual Studio Code を使用している場合、 言語編集プラグインのインストール で説明されているように、Motoko の Visual Studio Code プラグインがインストールされていること。
-
ローカルコンピュータ上で実行されている DFINITY Canister SDK プロセスをすべて停止していること。
このチュートリアルでは、 DFINITY Canister SDK のバージョン 0.8.0 以降を使用する必要があります。
|
このチュートリアルは約30分で終了します。
新しいプロジェクト生成
カスタムフロントエンド Dapp 用の新しいプロジェクトディレクトリを作成する:
-
ローカルコンピューターでターミナルシェルを開きます(まだ開いていない場合)。
-
Internet Computer プロジェクトで使用しているフォルダがあれば、そのフォルダに変更します。
-
以下のコマンドを実行して、ローカルに
node.js
がインストールされていることを確認します:which node which npm
もし
node.js
がインストールされていない場合は、次のステップに進む前にダウンロードしてインストールする必要があります。 お使いのローカル OS やパッケージマネージャーに合わせて node をインストールする方法については、 Node のウェブサイトをご覧ください。 -
次のコマンドを実行して、新しいプロジェクトを作成します:
dfx new custom_greeting
+ dfx new custom_greeting+
コマンドは、新しいcustom_greeting
プロジェクトを作成します。 -
以下のコマンドを実行して、プロジェクト・ディレクトリに移動します:
cd custom_greeting
React フレームワークのインストール
これまで React を使ったことがない場合は、フロントエンドのコードを編集する前に、Reactイントロダクション チュートリアルや React ウェブサイト を調べてみるといいでしょう。
必要なフレームワークモジュールをインストールする:
-
以下のコマンドを実行して、 React モジュールをインストールします:
npm install --save react react-dom
-
以下のコマンドを実行して、必要な TypeScript 言語のコンパイラ・ローダをインストールします:
npm install --save-dev typescript ts-loader
これらのモジュールをインストールする代わりに、デフォルトの package.json
ファイルを編集して、プロジェクトの依存関係を追加することができます。{ "name": "custom_greeting_assets", "version": "0.1.0", "description": "Internet Computer starter application", "keywords": [ "Internet Computer", "Motoko", "JavaScript", "Canister" ], "scripts": { "build": "webpack", "prebuild": "npm run copy:types", "start": "webpack serve --mode development --env development", "prestart": "npm run copy:types", "copy:types": "rsync -avr .dfx/$(echo ${DFX_NETWORK:-'**'})/canisters/** --exclude='assets/' --exclude='idl/' --exclude='*.wasm' --delete src/declarations" }, "devDependencies": { "@dfinity/agent": "0.10.0", "@dfinity/candid": "0.10.0", "@dfinity/principal": "0.10.0", "assert": "2.0.0", "buffer": "6.0.3", "copy-webpack-plugin": "^9.0.1", "events": "3.3.0", "html-webpack-plugin": "5.3.1", "process": "0.11.10", "stream-browserify": "3.0.0", "terser-webpack-plugin": "5.1.1", "util": "0.12.3", "webpack": "5.24.4", "webpack-cli": "4.5.0", "webpack-dev-server": "^3.11.2" }, "browserslist": [ "last 2 chrome version", "last 2 firefox version", "last 2 safari version", "last 2 edge version" ], "dependencies": { "react": "^17.0.2", "react-dom": "^17.0.2", "ts-loader": "^9.2.3", "typescript": "^4.3.5" } }
初期設定の確認
このチュートリアルで React を使用するための変更を行う前に、プロジェクトの dfx.json
設定ファイルにあるデフォルトのフロントエンド設定を確認しましょう。
デフォルトの dfx.json
設定ファイルを確認するには以下の様にします:
-
設定ファイル
dfx.json
をテキストエディターで開きます。 -
また、
canisters
キーには、custom_greeting_assets
Canister の設定が含まれています。{ "canisters": { ... "custom_greeting_assets": { "dependencies": [ "custom_greeting" ], "frontend": { "entrypoint": "src/custom_greeting_assets/src/index.html" }, "source": [ "src/custom_greeting_assets/assets", "dist/custom_greeting_assets/" ], "type": "assets" } } }
このセクションの設定を見てみましょう。
-
プロジェクトのフロントエンドアセットは、独自の Canister にコンパイルされます。ここでは、
custom_greeting_assets
という名前の Canister になります。 -
アセット Canister は、プロジェクトの メイン Canister にデフォルトで依存しています。
-
frontend.entrypoint
は、 Dapp のエントリーポイントとして使用するファイル(ここでは、index.html
ファイル)のパスを指定します。 たとえば、カスタムのfirst-page.html
ファイルのように、別のエントリーポイントがある場合には、この設定を変更します。 -
source
の設定では、src
とdist
のディレクトリのパスを指定します。src
設定は、プロジェクトをビルドするアセット Canister に含まれる静的アセットに使用するディレクトリを指定します。 カスケードスタイルシート (CSS ) や JavaScript のカスタムファイルがある場合は、このパスで指定されたフォルダにインクルードします。 プロジェクトをビルドすると、dist
の設定で指定したディレクトリからプロジェクトのアセットが提供されます。 -
type
の設定は、custom_greeting_assets
が、 認証済みアセット Canister を使用することを指定します。この Canister には、 Internet Computer プラットフォーム 上で静的アセットをホストするために必要なものがすべて付属しています。
このチュートリアルでは、 React の JavaScript を
index.jsx
ファイルに追加しますが、そのためにはdfx.json
ファイルのデフォルト設定を変更する必要はありません。 -
-
続けるには、
dfx.json
ファイルを閉じてください。
デフォルトのフロントエンドファイルの確認
このチュートリアルでは、カスタムフロントエンドを使って、デフォルトの main.mo
Canister を呼び出すことになっています。
しかし、変更を加える前に、プロジェクトのデフォルトのフロントエンドファイルに何があるかを見てみましょう。
デフォルトのデフォルトのフロントエンドファイルを確認するには以下のようにします:
-
テキストエディタで
src/custom_greeting_assets/src/index.html
ファイルを開きます。このテンプレートファイルは、
dfx.json
ファイルのfrontend.entrypoint
設定で指定された Dapp のデフォルトのフロントエンドエントリーポイントとなります。このファイルは標準的な HTML で、
src/custom_greeting_assets/assets
ディレクトリにある CSS ファイルと画像への参照を含んでいます。 デフォルトのindex.html
ファイルには、name
引数の入力フィールドとクリック可能なボタンを表示するための標準的な HTML 構文も含まれています。これは、 デフォルトのフロントエンドを確認する で見たのと同じデフォルトのフロントエンドです。
-
テキストエディターで、
src/custom_greeting_assets/src/index.js
ファイルを開きます。import { custom_greeting } from "../../declarations/custom_greeting"; document.getElementById("clickMeBtn").addEventListener("click", async () => { const name = document.getElementById("name").value.toString(); // custom_greetingアクターを動かしてgreetメソッドを呼び出す const greeting = await custom_greeting.greet(name); document.getElementById("greeting").innerText = greeting; });
-
import
ステートメントは、”../declarations"
からcustom_greeting
Canister への呼び出しを可能にする Actor を指しています。 -
declarations はまだ作成されていませんが、それについてはまた改めて説明します。
-
-
続けるには
index.js
ファイルを閉じてください。
フロントエンドファイルの修正
これで、デフォルトの Dapps に新しいフロントエンドを作成する準備が整いました。
フロントエンドのファイルを準備するために:
-
テキストエディターで、 webpack の設定ファイル (
webpack.config.js
) を開きます。 -
フロントエンドのエントリーを変更して、デフォルトの
index.html
をindex.jsx
に置き換えます。entry: { //frontend.entrypoint は、このビルドの HTML ファイルを指しているので //拡張子を `.js` に変更する必要があります。 index: path.join(__dirname, asset_entry).replace(/\.html$/, ".jsx"), },
-
以下の
module
キーをplugins
セクションの上に追加します:module: { rules: [ { test: /\.(js|ts)x?$/, loader: "ts-loader" } ] },
この設定は、プロジェクトが React JavaScript の
index.jsx
ファイルにts-loader
コンパイラーを使用することを可能にします。 デフォルトのwebpack.config.js
ファイルにはコメントされたセクションがあり、これを修正してmodule
キーを追加することができることに注意してください。 -
プロジェクトのルートディレクトリに、
tsconfig.json
という名前の新規ファイルを作成します。 -
テキストエディターで
tsconfig.json
ファイルを開き、以下をコピーしてファイルに貼り付けます:{ "compilerOptions": { "target": "es2018", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ "lib": ["ES2018", "DOM"], /* Specify library files to be included in the compilation. */ "allowJs": true, /* Allow javascript files to be compiled. */ "jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ }, "include": ["src/**/*"], }
-
変更内容を保存し、
tsconfig.json
ファイルを閉じて次に進みます。 -
デフォルトの
src/custom_greeting_assets/src/index.js
ファイルをテキストエディターで開き、2行目から9行目までを削除します。 -
以下のサンプルコードをコピーして、
index.js
ファイルに貼り付けてください:import * as React from "react"; import { render } from "react-dom"; import { custom_greeting } from "../../declarations/custom_greeting"; const MyHello = () => { const [name, setName] = React.useState(''); const [message, setMessage] = React.useState(''); async function doGreet() { const greeting = await custom_greeting.greet(name); setMessage(greeting); } return ( <div style={{ "fontSize": "30px" }}> <div style={{ "backgroundColor": "yellow" }}> <p>Greetings, from DFINITY!</p> <p> {" "} Type your message in the Name input field, then click{" "} <b> Get Greeting</b> to display the result. </p> </div> <div style={{ margin: "30px" }}> <input id="name" value={name} onChange={(ev) => setName(ev.target.value)} ></input> <button onClick={doGreet}>Get Greeting!</button> </div> <div> Greeting is: " <span style={{ color: "blue" }}>{message}</span>" </div> </div> ); }; render(<MyHello />, document.getElementById("app"));
-
以下のコマンドを実行して、修正した
index.js
ファイルの名前をindex.jsx
に変更します:mv src/custom_greeting_assets/src/index.js src/custom_greeting_assets/src/index.jsx
-
デフォルトの
src/custom_greeting_assets/src/index.html
ファイルをテキストエディタで開き、 body の内容を<div id="app"></div>
で置き換えます。例:
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width"> <title>custom_greeting</title> <base href="/"> <link type="text/css" rel="stylesheet" href="main.css" /> </head> <body> <div id="app"></div> </body> </html>
ローカル Canister 実行環境の起動
custom_greeting
プロジェクトをビルドする前に、ライブの Internet Computer プラットフォーム か、開発環境でローカルに実行されている Canister 実行環境に接続する必要があります。
実行環境をローカルで起動する:
-
ローカルコンピュータで新しいターミナルウィンドウまたはタブを開きます。
-
必要に応じて、プロジェクトのルートディレクトリに移動します。
-
次のコマンドを実行して、ローカルコンピュータ上でローカル Canister 実行環境を起動します:
dfx start --background
ローカル Canister 実行環境の起動操作が完了したら、次のステップに進みます。
Dapp の登録、ビルド、デプロイ
ローカル Canister 実行環境に接続すると、ローカルで Dapp の登録、ビルド、デプロイを行うことができます。
Dapp をローカルにデプロイする:
-
必要に応じて、プロジェクトのルートディレクトリにいることを確認します。
-
以下のコマンドを実行して、 Dapp の登録、ビルド、デプロイを行います:
dfx deploy
dfx deploy
コマンドの出力には、実行した操作に関する情報が表示されます。
新しいフロントエンドを確認する
ブラウザで アセット Canister の Canister 識別子を入力すると、デフォルトの Dapp の新しいフロントエンドにアクセスできるようになりました。
カスタム・フロントエンドを確認する:
-
ターミナルの新しいタブまたはウィンドウを開き、以下を実行します。
npm start
-
ブラウザを開き、 http://localhost:8080 に移動します。
-
greeting を入力するプロンプトが表示されていることを確認します。
例:
-
入力フィールドの Name を表示したいテキストに置き換えて、 Get Greeting をクリックすると、結果が表示されます。
例:
フロントエンドを修正し、変更点をテストする
フロントエンドを見た後に、いくつかの変更を加えたいと思うかもしれません。
フロントエンドを変更するには:
-
テキストエディタで
index.jsx
ファイルを開き,そのスタイル設定を変更します。 例えば、フォントファミリーを変更したり、入力フィールドにプレースホルダーを使用したりするには、以下のように変更します:import * as React from "react"; import { render } from "react-dom"; import { custom_greeting } from "../../declarations/custom_greeting"; const MyHello = () => { const [name, setName] = React.useState(''); const [message, setMessage] = React.useState(''); async function doGreet() { const greeting = await custom_greeting.greet(name); setMessage(greeting); } return ( <div style={{ "fontFamily": "sans-serif" }}> <div style={{ "fontSize": "30px" }}> <p>Greetings, from DFINITY!</p> <p> {" "} Type your message in the Name input field, then click{" "} <b> Get Greeting</b> to display the result. </p> </div> <div style={{ margin: "30px" }}> <input id="name" placeholder="Type text here" value={name} onChange={(ev) => setName(ev.target.value)} ></input> <button onClick={doGreet}>Get Greeting!</button> </div> <div> Greeting is: " <span style={{ color: "green" }}>{message}</span>" </div> </div> ); }; render(<MyHello />, document.getElementById("app"));
-
ファイルを保存し、更新されたページをブラウザで表示してください。
例:
-
新しいメッセージを入力すると、新しい greeting 表示されます。例: