はじめに
Catapultを使ってなにかサービスを作ろうと思ってた。
こんなの「Ogoruken」
↓
でも秘密鍵の管理が大変...めんどい...
↓
そこにplanet箒さんの記事が!!
↓
乗るしかないこのビッグウェーブに!🏄
諸注意
※ 今回こちらのfaucetのテストネット用に作成しました。
MosaicID: "46BE9BC0626F9B1A"
GenHash: "6C0350A10724FC325A1F06CEFC4CA14464BC472F566842D22418AEE0F8746B4C"
エンドポイント: "http://api-harvest-01.ap-northeast-1.nemtech.network:3000"
※ nem2-test-dapps-wallet-tsはがっつり開発中です。試す場合はテスト用にのみご利用ください。
※ 今回作った「nage-xem」は予告なく終了する可能性が濃厚です。ご了承ください。
1. nem2-test-dapps-wallet(以下Dapps Wallet)をTypeScript化
JavaScriptベースをTypeScriptベースに変更。
JavaScriptよりもTypeScriptの方が慣れている & 型がないと不安なので。
UI部分はReactで実装されていたのでそれも合わせてTypeScript化。
時間が足りず、jsのままのところもあります...
クラスコンポーネントをReact Hooksを使った関数コンポーネントに。
勉強のためにも。
2. 「nage-xem」
Dapps Wallet にあるxemを、特定のアドレス(現在はfaucet)に1xemなげるだけのサービスです。
React
create-react-app
こちらは通常通りバンドルファイルの数などを気にしなくてよいのでcliを利用。
楽。
Firebase hosting
とっても楽。
CORSの問題もなくすんなり。
使い方
※ Dapps walletの詳しい使い方はplanet箒さんの記事を御覧ください
※ 開発中Chrome拡張のインストールの仕方は割愛します。TypeScript版のDapps walletのソースコードはこちら
github
1. テストネット用の秘密鍵 & テスト用xemを入手
秘密鍵の作成はplanet箒さんのサイトが便利。
テストネットxemはこちらのfaucetで入手
2. Dapps Walletに、用意した秘密鍵と任意のパスワード(8文字以上)を入力しサインアップ
3. 「nage-xem」を開く。
もし2の前に開いていた場合は再度ページを読み込み直してください。
window.nem2はDapps Walletにサインインした状態でページを読み込むことで有効化されるためです。
適切な場合、「あなたのアドレス」にDapps Walletのアドレスが表示されます。
4. 「1xem投げる」ボタンをクリック!
5. 新規タブで表示されたトランザクション情報を確認後「Confirm」をクリック!
6. これでOK!👌
エクスプローラーでトランザクションを確認してみたり。
※ エンドポイントが同じか注意!
2まで一回やってしまえば、あとはTransactionを送るごとに行うのは「Confirm」を押すだけ!楽!
ハマったところ
Dapps WalletのTypeScript化
グローバルオブジェクトにメソッドを追加しようとすると怒られる。
「windowにそんなメソッドはねえから!!」と怒られる。
型定義用にinterfaceを作り、tsconfigのtypeRootsに追加して解決
例:
"typeRoots": ["node_modules/@types", "src/types"],
グローバルオブジェクトに追加したメソッドが読み込まれない。
gulp&Browserify だとうまくいくけど webpackだと上手く行かず。
webpack.config
でoutput.globalObject
に"this"
設定したら解決。
例:
output: {
path: path.join(__dirname, "dist/js"),
filename: "[name].js",
globalObject: "this" // 👈ポイント!
},
いまいち仕組みがわかっていないので要検証。
「Uncaught ReferenceError: require is not defined」
nem2-sdkを使おうとするとモジュールの解決方法で怒られる。これには大分手間取り、一時はnem2-sdkのimportに絶対パスを指定してやりすごしていました。
最終的にtsconfigとwebpackの設定で解決。
"module": "esnext",
"moduleResolution": "node",
// target: "node", 👈つけない
node: {
fs: "empty",
global: true,
crypto: true,
tls: "empty",
net: "empty",
process: true,
module: false,
clearImmediate: false,
setImmediate: false
},
※webpackのnodeの項目は要検討
「Module not found: Can't resolve 'utf-8-validate' ~」
あわせてこちらも「Module not found: Can't resolve 'bufferutil' in ' ~」
注意だけだったので動いてはいましたが、externals: [/node_modules/, "bufferutil", "utf-8-validate"]
をwebpack.configに追加して解決。
externals: [/node_modules/, "bufferutil", "utf-8-validate"]
オブジェクト自身を指定するはずのthisの補完が効かない
オブジェクトリテラルで、オブジェクトのメンバーであるプロパティやメソッドをthisで取得してもanyになってしまった。
TypeScript化して補完が逆に効かなくなって困りました。
これはtsconfigで"noImplicitThis": true
を追加
"noImplicitThis": true
ReactのTypeScript化
importの書き方
TypeScriptを使ったReactでimportを書く際、import * as React from 'react'
と書いている例が多かったが、Hooksを使おうとすると冗長になってしまう。
import React, { useState } from 'react'
のように書きたい。
tsconfigで"module": "esnext","allowSyntheticDefaultImports": true,
を追加
"module": "esnext",
"allowSyntheticDefaultImports": true
「nage-xem」
同じく「Module not found: Can't resolve 'utf-8-validate' ~」
webpack.configを上書きしようとreact-app-rewiredを使ってみるも上手く行かず。
いまのところほっといても動いてるので放置
Prod buildの際、Transactionの種類がうまく取得できない
window.nem2 を呼び出す際、トランザクションの種類をConstructorの名前で判断している部分でちゃんとトランザクション名を取れず。多分ビルド時の圧縮で名前が変わってしまっているのだと思う。
TransactionTypeで判断すれば実装できる気がするが方法が思いつかなかったので、とりあえずTransferTransaction限定での対応でお茶を濁してます。
今後の課題
- 完全TypeScript化。
- ビルドサイズを小さくする。
- 対応するトランザクションを増やす。
感想
秘密鍵の管理をサービス側で考えなくていいのは本当に楽ですね!これであんなサービスもこんなアプリも気軽に作れるんじゃないでしょうか。
Chrome拡張の作成は前からやりたいと思っていたので良い機会になりました。同じブラウザ内でも、Chrome拡張自身とbackground.js、nage-xemなどのウェブサイト間でのメッセージのやりとりは一人でフロントとバックエンドとを作ってる気分で新鮮でした。
そういう意味では、TypeScriptによってフロント、バックエンドで同じ型を使い回せるのが便利でした。
webpackでのビルドはなかなか大変でした。まず、ビルドが上手く行かない。バンドルできてもうまく動かない。ファイルサイズが大きすぎる、Configファイルがパット見みづらいなどなど。
普段cliは本当によしなにやってくれて便利なんだなと改めて。
こちらの記事は思い出しながら書いているため、各問題の原因と解決方法がごっちゃになってる可能性が…。もし間違えがありましたらコメントいただけると嬉しいです。記録はすぐにやらないとですね!