ESM(JavaScript Module)とブラウザでsymbol-sdk@3を使う

# はじめに

今回は、ESMでsymbol-sdkを使うというテーマでやっていきます。

まず、ESMとは、ECMAScript Modulesのことです。JavaScript Moduleともいいます。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Modules

これは何かというと、ブラウザのscriptタグで以下のようにimport/exportが使えるようになります。（あとTop Level awaitが使えたりします）

```html
<script type="module">
	import Hoge from "/path/to/hoge.js";
	new Hoge().say(); // Hello, World!
</script>

<script type="module" src="/path/to/file.js"></script>
```

```jsx
export default class Hoge {
  say() {
    console.log('Hello, World!');
  }
}
```

それと、symbol-sdkのバージョン3系で、このESMが使えるようになりました。

https://www.npmjs.com/package/symbol-sdk

なので、ESMを使ったsymbol-sdkの書き方を少しやってみたいと思います。

ちなみに、symbol-sdkは3.0.7です。

# インポート

## もしNode.jsがPCにインストールされていれば

以下のコマンドによりsymbol-sdkをダウンロードして、

```bash
npm i symbol-sdk@3.0.7
```

index.jsファイルに、

```jsx
import symbolSdk from './node_modules/symbol-sdk/dist/bundle.web.js';
```

index.htmlファイルに

```html
<script type="module" src="./index.js"></script>
```

とすれば、インポート完了です。

もしくは、index.htmlファイルに直接書いてもよいですね。

```html
<script type="module">
	import symbolSdk from './node_modules/symbol-sdk/dist/bundle.web.js';
</script>
```

それで、じゃぁホスティングするときどうするんだっていう話になるんですが、

`./node_modules/symbol-sdk/dist/` 配下の以下のファイルをあげておけばいいんじゃないかと思います。

- bundle.web.js
- bundle.web.js.map
- 5fcc69fd3573ae76acd8.module.wasm

これらをindex.htmlと同じディレクトリに配置するとき、パスは以下のようになると思います。

```html
<script type="module">
	import symbolSdk from './bundle.web.js';
</script>
```

## Node.jsがPCにインストールされてないよ

という場合でも、以下のワザが使えるかもしれません。

```html
<script type="module">
	import symbolSdk from 'https://www.unpkg.com/symbol-sdk@3.0.7/dist/bundle.web.js';
</script>
```

インターネット上にある他のどこかのsdkをインポートすることができます。

ちょっと確認や小ネタなんかには良いかもしれませんね。

# サンプルコード

それではSymbolブロックチェーンにトランザクションを送信してみます。

以下のコードはすべて `<script>` タグの内部に書いていきます。

まずはインポートとかいろいろ。 `window.localStorage` にて、 `privateKey` には秘密鍵が、 `nodeUrl` にはノードのエンドポイントが事前にセットされているとします。

```jsx
import symbolSdk from 'https://www.unpkg.com/symbol-sdk@3.0.7/dist/bundle.web.js'

const facade = new symbolSdk.facade.SymbolFacade('testnet');

const privateKey = new symbolSdk.PrivateKey(localStorage.getItem('privateKey'));
const keyPair = new facade.constructor.KeyPair(privateKey);

const network = symbolSdk.symbol.Network.TESTNET;
const deadline = network.fromDatetime(new Date(Date.now() + 7200000)).timestamp;

const nodeUrl = localStorage.getItem('nodeUrl');
```

トランザクションを作ります。受取人はフォーセットです。

```jsx
const transaction = facade.transactionFactory.create({
  type: 'transfer_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  recipientAddress: 'TARDV42KTAIZEF64EQT4NXT7K55DHWBEFIXVJQY',
  mosaics: [
    { mosaicId: 0x72C0212E67A08BCEn, amount: 1000000n }
  ]
});
```

署名してハッシュ

```jsx
const signature = facade.signTransaction(keyPair, transaction);
const jsonPayload = facade.transactionFactory.constructor.attachSignature(transaction, signature);
const hash = facade.hashTransaction(transaction).toString();

console.log(hash);
```

送信します。ブラウザなので `fetch` が使えます。

```jsx
const response = await fetch(
  new URL('/transactions', nodeUrl),
  {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json' },
    body: jsonPayload
  })
  .then((res) => res.json());

console.log(JSON.stringify(response));
```

以上です。

これをそのまま書いてブラウザで実行すると、リロードするたびに送金されるので、そのあたりはよしなに。

# おわりに

symbol-sdkがESMに対応したことで、ブラウザで使うのがより簡単になりましたね。従来のNode.jsライブラリも、いくつかESM対応しているものがあるので探してみるのもいいかもしれません。