DFINITYで遊んでみる ~動かしてみる~【ICP】

#はじめに
この記事はhttps://qiita.com/YakitoriBoyz/items/ba8fb716cd6bc701139b の続きです。
まだDFINITY Canister SDKが使える状態になっていない方は前回の記事を読んでみてください。

#プロジェクトの作成と実行
##helloの作成とデプロイ
helloという名前のプロジェクトを新規作成します。
なお整理するために以下の作業は`~/ic-projects/`で行っています。

```terminal:terminal
$ dfx new hello
```

実行し、完了すると
<img width="600" alt="DFINITY.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1294172/f217c8de-6245-b3ec-7d07-596c9c6c2799.png">
DFINITYのロゴが表示されます。かっこいい…
作成できたので開発していきます。ここからはシェルを2つ同時に使うようなのでWindows Terminalなどを導入しておくと便利かと思います。
タブを2つ開き、2つ目の方で以下を実行します。

```terminal:terminal
$ cd hello
$ dfx start
```

ローカルでキャニスター実行環境が動き始めます。キャニスターが何なのかは私にはまだ理解できていないです:sweat:
1つ目のタブに戻り、デプロイしていきます。

```terminal:terminal
$ cd hello
$ npm install
$ dfx deploy
```

これでデプロイされます。
ちゃんとできているか確かめるために、以下を実行します。

```terminal:terminal
$ dfx canister call hello greet everyone
("Hello, everyone!")
```

("Hello, everyone!")が出力されていれば大丈夫です。
ちなみにこれは、helloというキャニスターを呼び出し、その中にあるgreetという関数を呼び出し、everyoneという引数を渡し、greetの戻り値を表示しているらしいです。

##Dappのフロントエンドをテスト
先ほどデプロイしたhelloというdappが正常に動いていることが確認できたので、続いてwebブラウザからフロントエンドにアクセスできることを確認します。

```terminal:terminal
$ npm start
```

これでアクセスできるURLが表示されるはず・・・だったのですがエラーが起きました。
（ここからはエラーの日記になっていますので、普通に動いた方は読み飛ばしてください。）

```terminal:terminal
[webpack-cli] Unable to load '@webpack-cli/serve' command
[webpack-cli] TypeError: options.forEach is not a function
    at WebpackCLI.makeCommand (/home/yakitori/ic-projects/hello/node_modules/webpack-cli/lib/webpack-cli.js:108:21)
...
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! hello_assets@0.1.0 start: `webpack serve --mode development --env development`
npm ERR! Exit status 2
npm ERR!
npm ERR! Failed at the hello_assets@0.1.0 start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/yakitori/.npm/_logs/2021-11-03T11_28_33_185Z-debug.log
```

さっぱり分からないのでググったところ、webpack-cliのバージョンによる問題っぽいです。
https://github.com/webpack/webpack-cli/issues/2990
@webpack-cli/serveのバージョンが1.6.0の時はwebpack-cliのバージョンは4.9.0にアップデートしてと書いてあります。
とりあえず今のバージョンを確認します。

```terminal:terminal
├─┬ webpack-cli@4.5.0
│ ├── @webpack-cli/configtest@1.1.0
│ ├─┬ @webpack-cli/info@1.4.0
│ ├── @webpack-cli/serve@1.6.0
```

@webpack-cli/serveのバージョンは1.6.0でwebpack-cliのバージョンは4.5.0でした。なんでこんなに古いんですかね？
まぁwebpack-cliをアップデートすることにします。
npm-check-updatesというパッケージを使えば簡単にアップデートできるみたいなのでインストールします。

```terminal:terminal
$ sudo npm install -g npm-check-updates
```

すると`ncu`というコマンドがつかえるようになります。
実行すると

```terminal:terminal
$ ncu
Checking /home/yakitori/ic-projects/hello/package.json
[====================] 15/15 100%

 html-webpack-plugin      5.3.1  →   5.5.0
 terser-webpack-plugin    5.1.1  →   5.2.4
 util                    0.12.3  →  0.12.4
 webpack-cli              4.5.0  →   4.9.1
 webpack-dev-server     ^3.11.2  →  ^4.4.0
 webpack                 5.24.4  →  5.61.0

Run ncu -u to upgrade package.json
```

アップデート情報を教えてくれます。また、package.jsonもコマンド一つでアップデートしてくれます。

```terminal:terminal
$ ncu -u
Upgrading /home/yakitori/ic-projects/hello/package.json
[====================] 15/15 100%

 html-webpack-plugin      5.3.1  →   5.5.0
 terser-webpack-plugin    5.1.1  →   5.2.4
 util                    0.12.3  →  0.12.4
 webpack-cli              4.5.0  →   4.9.1
 webpack-dev-server     ^3.11.2  →  ^4.4.0
 webpack                 5.24.4  →  5.61.0

Run npm install to install new versions.
```

これでアップデートできたので、もう一度パッケージをインストールします。

```terminal:terminal
$ npm install
$ dfx deploy
```

準備完了して実行！

```terminal:terminal
$ npm start

> hello_assets@0.1.0 prestart /home/yakitori/ic-projects/hello
> npm run copy:types

npm WARN npm npm does not support Node.js v10.19.0
npm WARN npm You should probably upgrade to a newer version of node as we
npm WARN npm can't make any promises that npm will work with this version.
npm WARN npm You can find the latest version at https://nodejs.org/

> hello_assets@0.1.0 copy:types
> rsync -avr .dfx/$(echo ${DFX_NETWORK:-'**'})/canisters/** --exclude='assets/' --exclude='idl/' --exclude='*.wasm' --delete src/declarations

sending incremental file list
hello_assets/

sent 333 bytes  received 17 bytes  700.00 bytes/sec
total size is 19,112  speedup is 54.61

> hello_assets@0.1.0 start /home/yakitori/ic-projects/hello
> webpack serve --mode development --env development

No production canister_ids.json found. Continuing with local
[webpack-cli] Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
 - options has an unknown property 'watchContentBase'. These properties are valid:
   object { allowedHosts?, bonjour?, client?, compress?, devMiddleware?, headers?, historyApiFallback?, host?, hot?, http2?, https?, ipc?, liveReload?, magicHtml?, onAfterSetupMiddleware?, onBeforeSetupMiddleware?, onListening?, open?, port?, proxy?, server?, setupExitSignals?, static?, watchFiles?, webSocketServer? }
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! hello_assets@0.1.0 start: `webpack serve --mode development --env development`
npm ERR! Exit status 2
npm ERR!
npm ERR! Failed at the hello_assets@0.1.0 start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/yakitori/.npm/_logs/2021-11-04T09_05_04_316Z-debug.log
```

何かエラーが出ました:innocent:

watchContentBaseという存在しないオプションを指定していることによるエラーの模様。
v3 -> v4のタイミングでどうやら書き方が変わっているみたいです。
https://github.com/webpack/webpack-dev-server/blob/master/migration-v4.md

私が使っているwebpack-dev-serverのバージョンは4.4.0だったので、修正します。

```javascript:webpack.config.js
  devServer: {
    proxy: {
      "/api": {
        target: "http://localhost:8000",
        changeOrigin: true,
        pathRewrite: {
          "^/api": "/api",
        },
      },
    },
    hot: true,
    
    // ここを変更
    // contentBase: path.resolve(__dirname, "./src/hello_assets"),
    // watchContentBase: true
    static: {
            directory: path.resolve(__dirname, "./src/hello_assets"),
            watch: true,
    },
  },
```

今度こそ動くはず・・・エラーが出ました:fearful:

```terminal:terminal
[webpack-cli] /home/yakitori/ic-projects/hello/node_modules/webpack-dev-server/lib/servers/WebsocketServer.js:10
  static heartbeatInterval = 1000;
                           ^

SyntaxError: Unexpected token =
...
```

エラーを調べると以下の情報を発見しました。
https://github.com/VickScarlet/lifeRestart/issues/176
Node.jsをアップデートすると良いみたいなので、やります。
アップデートの手順は次の記事を参考にしました。
https://symfoware.blog.fc2.com/blog-entry-2535.html
まずはvoltaを入れます。

```terminal:terminal
$ sudo curl https://get.volta.sh | bash
$ source ~/.profile
$ volta
Volta 1.0.5
The JavaScript Launcher ⚡
```

次にNode.jsの安定板をインストールします。

```terminal:terminal
$ volta install node
```

バージョンを確認します。

```terminal:terminal
$ node -v
v16.13.0
$ npm -v
8.1.0
```

できましたね。これでもう一度チャレンジします。

```terminal:terminal
$ npm start

> hello_assets@0.1.0 prestart
> npm run copy:types


> hello_assets@0.1.0 copy:types
> rsync -avr .dfx/$(echo ${DFX_NETWORK:-'**'})/canisters/** --exclude='assets/' --exclude='idl/' --exclude='*.wasm' --delete src/declarations

sending incremental file list
hello_assets/

sent 330 bytes  received 17 bytes  694.00 bytes/sec
total size is 19,112  speedup is 55.08

> hello_assets@0.1.0 start
> webpack serve --mode development --env development

No production canister_ids.json found. Continuing with local
<i> [webpack-dev-server] [HPM] Proxy created: /api  -> http://localhost:8000
<i> [webpack-dev-server] [HPM] Proxy rewrite rule created: "^/api" ~> "/api"
<i> [webpack-dev-server] Project is running at:
<i> [webpack-dev-server] Loopback: http://localhost:8080/
<i> [webpack-dev-server] On Your Network (IPv4): http://172.23.198.213:8080/
<i> [webpack-dev-server] Content not from webpack is served from '/home/yakitori/ic-projects/hello/src/hello_assets' directory
asset index.js 844 KiB [emitted] (name: index) 1 related asset
asset logo.png 24.8 KiB [emitted] [from: src/hello_assets/assets/logo.png] [copied]
asset index.html 573 bytes [emitted]
asset main.css 484 bytes [emitted] [from: src/hello_assets/assets/main.css] [copied]
asset sample-asset.txt 24 bytes [emitted] [from: src/hello_assets/assets/sample-asset.txt] [copied]
runtime modules 27.2 KiB 14 modules
modules by path ./node_modules/ 716 KiB
  modules by path ./node_modules/@dfinity/ 207 KiB 34 modules
  modules by path ./node_modules/webpack-dev-server/client/ 52.7 KiB 12 modules
  modules by path ./node_modules/borc/ 113 KiB 10 modules
  modules by path ./node_modules/webpack/hot/*.js 4.3 KiB 4 modules
  modules by path ./node_modules/html-entities/lib/*.js 81.3 KiB 4 modules
  modules by path ./node_modules/url/ 37.4 KiB 3 modules
  modules by path ./node_modules/querystring/*.js 4.51 KiB 3 modules
  modules by path ./node_modules/simple-cbor/src/*.js 17.5 KiB 3 modules
  modules by path ./node_modules/iso-url/ 4.36 KiB 3 modules
modules by path ./src/ 1.89 KiB
  ./src/hello_assets/src/index.js 360 bytes [built] [code generated]
  ./src/declarations/hello/index.js 1.38 KiB [built] [code generated]
  ./src/declarations/hello/hello.did.js 167 bytes [built] [code generated]
webpack 5.61.0 compiled successfully in 689 ms
```

できました！！！:sob:
ちなみにずっと警告されていたNode.jsとnpmの互換の問題もこれで解決しました。

出力されているURLにアクセスすると、ちゃんと表示されます。
![frontend.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1294172/d7b632b0-0fcb-ebe4-1980-6b1c01fca37d.png)
ここでテキストボックスに文字を入れてクリックすると、
![try.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1294172/02501798-fc38-e05c-ee13-3f012ba75a8f.png)
Hello, (入れた文字)!
が表示され、ターミナル上で行った動作と同じことがブラウザ上でできることが確認できました。

確認ができたらwebpack-dev-serverを`Ctrl-C`で止め、

```terminal:terminal
$ dfx stop
```

を実行しキャニスター実行環境も停止させましょう。

#終わりに
手順通りやるだけだし楽勝でしょ:grin:って思っていたらめちゃくちゃ躓いて大変でした。。。
エラーに対する処置は、私自身webに関する知識がゼロなので間違っているところがあるかもしれませんので、もし気づいた方は教えてくれると嬉しいです。

とりあえずHello, worldができたので満足しています。
もうちょっと勉強して面白いものが作れたらいいなぁ

#参考
https://smartcontracts.org/docs/quickstart/local-quickstart.html
https://smartcontracts.org/docs/quickstart/newcomers.html