Anvil をローカル実行する

# 概要

[Anvil](https://anvil.works/) は Python でコーディングする、Web ベースの統合開発環境です。
Python さえ知っていればなんとかなる、というのがウリだそうで、以下の特徴があります。

- Web ベースなのでインストール不要
- HTML を書かずにビジュアルエディタで UI 作成
- 作ったらそのまま Web で公開できる

そんな Anvil ですが、作ったアプリをローカルで実行することも可能ということで、試してみました。

# 準備

### Hello World

Hello World をやった前提で説明しますので、まだの方は Hello World をやっておくと良いです。

1. [Anvil のサイト](https://anvil.works/) へ行って "Start building for free" をクリックして、サインアップします。
2. ログインしたら "Things to do" の "2. Build a Hello World app" の "Start the interactive tutorial" をクリックすれば、チュートリアルが始まります。

# ローカル実行

では、作った Hello World をローカル実行できるようにしてみます。

### 情報ソース

ローカル実行の手順は [`anvil-runtime` のリポジトリ](https://github.com/anvil-works/anvil-runtime) で説明されています。
`anvil-runtime` はオープンソースの、Anvil のランタイムエンジンです。

### Java のインストール

説明を読むと OpenJDK の 8 以上をインストールするようにと書かれています。
私の場合、jdk1.8.0 が入っていたのでそれでやってみたら動きました。

### ローカル仮想環境を作る

ここからアプリごとの手順になります。
ローカルにフォルダを用意して仮想環境を作ります (以下は `pipenv` で作った場合)。

```
helloworld
 ├─ .venv
 ├─ Pipfile
 └─ Pipfile.lock
```

### anvil-app-server

仮想環境内に `anvil-app-server` をインストールします。
PyPI からインストールできます。`pipenv` で入れる場合は以下のようにします。

```
> pipenv install anvil-app-server
```

### アプリのクローン

Anvil の Web IDE で作ったアプリは最初から Git 管理されているので、それをクローンすればローカルに持ってこれます。
クローンするには Web IDE でアプリの "Version History" を開いて、"Clone with Git" を押します。
![clone_git.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339253/578f737e-26ab-ccb1-960d-6221902c281c.jpeg)
するとクローンするためのコマンドが表示されるので、クリップボードにコピーして、先ほどの仮想環境のフォルダ (helloworld フォルダ) で実行します。
実行するとサブフォルダ (=ローカルリポジトリ) が出来て、アプリのソースが格納されます。

```
helloworld
 ├─ .venv
 ├─ Hello__World
 │   ├─ .git
 │   ├─ client_code
 │   ├─ theme
 │   ├─ .gitignore
 │   ├─ __init__.py
 │   └─ anvil.yaml
 ├─ Pipfile
 └─ Pipfile.lock
```

### 実行…？

仮想環境内で以下のコマンドを実行するとアプリが起動するらしいのですが…。

```
> anvil-app-server --app Hello__World
```

236MB の jar ファイルをダウンロードしようとして失敗したようです。

```
Downloading Anvil App Server JAR to package directory
  5% of 236.3 MiB |###                                               | Elapsed Time: 0:01:29 ETA:   0:18:25
Failed to download App Server to package directory. Retrying in ~/.anvil
Traceback (most recent call last):
  File "xxx\.venv\lib\site-packages\anvil_app_server\__init__.py", line 167, in find_or_download_app_server
    _urlretrieve(url, package_dir_path, show_progress)
```

もう一度同じコマンドを実行してみたところ、今度は「ファイルが存在する。壊れている」と言われました。
壊れていても再度ダウンロードしようとはしないようです。

```
Found Anvil App Server JAR in package directory
Error: Invalid or corrupt jarfile xxx\.venv\lib\site-packages\anvil_app_server\anvil-app-server.20200515-134353.jar
```

### jar ファイルを手動で取ってくる

上記のエラーメッセージに書かれたパスに、問題の jar ファイルがあれば良いのでしょうから、別途ダウンロードしてやりましょう。
取得元は `anvil_app_server` の `__init__.py` を見ると分かります。

164行目:

```python
    url = "https://anvil-public-assets.s3.eu-west-2.amazonaws.com/app-server/" + server_jar_name
```

これにファイル名をくっつけて、Web ブラウザでアクセスするとダウンロードできました。
![download_jar.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339253/80f29244-9925-6329-d900-b472b781b9b1.jpeg)
これを anvil_app_server フォルダに入れ (て上書きす) れば OK です。

### 実行

```
> anvil-app-server --app Hello__World
Found Anvil App Server JAR in package directory
Found 0 migration(s) for (base runtime) DB.
Executing Anvil migrations...
Database currently at "2019-09-23-B-denormalise-app-sessions"
0 migration(s) to perform.
Migration complete.
[INFO  anvil.core.server] HTTP Server running on port 3030
[INFO  anvil.app-server.run] App URL:  http://localhost:3030
[INFO  anvil.app-server.dispatch] Launching built-in downlink...
[INFO  anvil.app-server.run] SMTP Server running on port 25
Warning: PDF Rendering not supported on Windows. Renderer not initialised
Connecting to ws://localhost:3030/_/downlink
Anvil websocket open
[INFO  anvil.executors.downlink] Downlink client connected with spec {:runtime "python3-full", :session_id "LIEwah7xDUSHG6S4uazw"}
Downlink authenticated OK
```

ローカルで実行しても Web アプリであることに変わりはないので、ブラウザで開きます。
ログに出ている App URL をブラウザに入力します。
![running.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339253/03f563f4-3ff4-bb5c-6141-5f0cf40c2630.jpeg)
動きました！

# 所感

取り急ぎ、ローカルで実行できることを確認しました。
ランタイムエンジンはフリーだし、ローカルなら外部ライブラリも入れ放題です。
ただやはり、これで作ったアプリを人に配布して使ってもらうのは、結構ハードルが高そうです。
どういうものを開発するのに合っているか、見極めが必要かと思います。