WebAssembly製CLIをWAPMに公開する

# TL; DR

- [WAPM](https://wapm.io/) のアカウント作成
- `wapm init` でリポジトリに `wapm.toml` を作成
- 公式の [GitHubActon](https://github.com/wasmerio/wapm-publish) をタグ打ち時に流す
- アップロード完了！

https://wapm.io/Syuparn

# はじめに

前回の記事で、WebAssemblyとWASIを使って `yes` コマンドを実装しました。

https://qiita.com/Syuparn/items/35fd5e19f50a0a1f7c4e

今回は、これを手軽にインストールできるように [WAPM](https://wapm.io/) (WebAssembly Package Manager) に公開してみます。

# WAPMとは？

https://wapm.io/about

WAPMはWebAssembly製ツール/ライブラリのパッケージマネージャーです。 `wapm` コマンドで依存パッケージのバージョン管理ができます。（ざっくり言うとnpmのWebAssembly版）
登録したパッケージは上記 wapm.io で公開されます。

作成例 [^1]

https://wapm.io/Syuparn

![wapm.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239887/5db60063-4df2-43b2-fd2d-0b3a85ec3bfe.png)

「Open In Shell」をクリックすると、ダウンロードしなくてもコマンドを試してみることができます[^2]。

![open_in_shell.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239887/65d25c57-62c1-70d2-6b02-7fdba5d7c7e1.png)

localhostへのインストールも1コマンドで行えます。

```bash
$ wapm install Syuparn/yes
[INFO] Installing Syuparn/yes@0.2.2
Package installed successfully to wapm_packages!

# wapm run で実行
$ wapm run yes | head -n 3
y
y
y
```

それでは、本題のパッケージ公開方法について紹介します。

# 公開の手順
## WAPMのアカウント作成

GitHub連携でアカウント作成可能です。ただしプロフィール（アイコン等）は連携されないので右上「Edit Profile」から手動入力が必要です。

## wapm.tomlの生成

続いて、リポジトリにパッケージ情報 `wapm.toml` を用意します。
リポジトリのルートフォルダで `wapm init` を実行すると対話的シェルが起動するので、質問に答えると `wapm.toml` が生成されます。

```bash
$ wapm init
This utility will walk you through creating a wapm.toml file.
It only covers the most common items, and tries to guess sensible defaults.

Use `wapm add <pkg>` afterwards to add a package and
save it as a dependency in the wapm.toml file.

Press ^C at any time to quit.
Package name: Syuparn/yes
Version: 0.1.0
Description: yes command implemented in WebAssembly and WASI
Repository: https://github.com/Syuparn/wasm-yes
License: MIT
Enter the data for the Module (1)
 - Source (path): yes.wasm
 - Name: yes
 - ABI: WASI
 - Commmands (space separated): yes
Enter the data for the Module (2)
 - Source (path): none

About to write to /home/syuparn/work/wasm-yes/wapm.toml:

[package]
name = "Syuparn/yes"
version = "0.1.0"
description = "yes command implemented in WebAssembly and WASI"
license = "MIT"
repository = "https://github.com/Syuparn/wasm-yes"

[[module]]
name = "yes"
source = "yes.wasm"
abi = "wasi"

[module.interfaces]
wasi = "0.0.0-unstable"

[[command]]
name = "yes"
module = "yes"


Is this OK? (yes) yes
```

## 注意点
### パッケージ名は `アカウント/xxx` の形式にする必要がある

パッケージ名は自分のアカウントの配下に作る必要があります。そうでない場合、この後の `wapm publish` で失敗します。

```bash:パッケージ名を"Syuparn/yes"ではなく"yes"にした場合
/home/runner/.wasmer/bin/wapm config set registry.url https://registry.wapm.io
/home/runner/.wasmer/bin/wapm config set registry.token ***
Logged in to WAPM.
/home/runner/.wasmer/bin/wapm publish
Error: Global use for aliases is disabled for now. Try renaming your package to: '***/yes' or use a different namespace
...
```

### READMEファイルのパス指定が必要

wapm.io では、デフォルトではリポジトリの `readme.md` を表示します。GitHubのデフォルトは `README.md` なので、パスを指定しなおす必要があります。

```toml:wapm.toml
[package]
# ...
readme = "README.md"
```

## GitHub Action設定

最後に、WAPMへのリリースをGitHub Actionで設定します。公式のActionがあるのでこちらをそのまま使用しました。

https://github.com/wasmerio/wapm-publish

タグ打ち時にジョブが流れるようにすれば、自動でWAPMに新バージョンをリリースできます（[workflow](https://github.com/Syuparn/wasm-yes/blob/main/.github/workflows/deploy.yml)）。

`WAPM_USERNAME` には先ほど作ったWAPMのアカウント名を指定します。
 `WAPM_PASSWORD` にはWAPMの 「Settings → Security」で作成したパスワードを指定します。

![pass_wapm.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239887/6dabe3c9-31c6-07f4-23c7-eaf5bb2c69fc.png)


シークレットはリポジトリの「Settings → Secrets」から登録できます。

![secret.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239887/3182d2c7-36cd-a023-7e2b-fdb01b275268.png)

### 注意！

デプロイされるバージョンは、打ったタグではなく **`wapm.toml` の設定値で決まります**。タグ打ち前に `wapm.toml` の更新をお忘れなく！
（タグ打ち時にコミット追加する等、うまく自動化したいところ...）

```bash:wapm.toml更新を忘れた場合
$ wapm publish
Error: The version 0.1.0 already exists for package yes
```

# おわりに

以上、WebAssemblyをWAPMで公開する方法でした。皆さんもツールを公開して布教してみてはいかがでしょうか？

[^1]: コマンドのページのURLに直接飛ぶとなぜかInternal Server Errorが発生するので、ユーザーページを貼っています
[^2]: なぜか `head` のSIGPIPEが効かず固まってしまいますが、ローカルで試した際にはちゃんと終了します。