OSSとなったAnvilのHackに取り掛かってみた

Pythonのみでアプリが作れるサービスanvilがOSS化というニュースをみて、ビルドを試した結果をまとめました。
2020.07.02

はじめに

PythonだけでWebアプリが作れるanvilがOSSになったという記事を見て、PythonだけでWebアプリが作れるという事がどういうことなのかも含めて実際に試してみました。

セットアップ

以下のリポジトリにて行います。

READMEにビルド済Jarファイルを用いたスタンドアロンのサーバ設定手順が記載されており、まずはそれをなぞってみます。

pipenvを用いての手続きとしては以下の通り。

pipenv install --python 3.8
pipenv install anvil-app-server
pipenv shell
create-anvil-app todo-list MyTodoList
anvil-app-server --app MyTodoList

インストールログ

% mkdir anvil
% cd anvil
% export PIPENV_VENV_IN_PROJECT=1
% pipenv install --python 3.8
Creating a virtualenv for this project…
Pipfile: /path/to/anvil/Pipfile
Using ~/.anyenv/envs/pyenv/versions/3.8.0/bin/python3 (3.8.0) to create virtualenv…
⠇ Creating virtual environment...created virtual environment CPython3.8.0.final.0-64 in 458ms
  creator CPython3Posix(dest=/path/to/anvil/.venv, clear=False, global=False)
  seeder FromAppData(download=False, pip=latest, setuptools=latest, wheel=latest, via=copy, app_data_dir=/path/to/seed-app-data/v1)
  activators BashActivator,CShellActivator,FishActivator,PowerShellActivator,PythonActivator,XonshActivator</p>
✔ Successfully created virtual environment!
Virtualenv location: /path/to/anvil/.venv
Creating a Pipfile for this project…
Pipfile.lock not found, creating…
Locking [dev-packages] dependencies…
Locking [packages] dependencies…
Updated Pipfile.lock (db4242)!
Installing dependencies from Pipfile.lock (db4242)…
  ?   ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 0/0 — 00:00:00
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.

% pipenv install anvil-app-server
Installing anvil-app-server…
Adding anvil-app-server to Pipfile's [packages]…
✔ Installation Succeeded
Pipfile.lock (3ca2ea) out of date, updating to (db4242)…
Locking [dev-packages] dependencies…
Locking [packages] dependencies…
✔ Success!
Updated Pipfile.lock (3ca2ea)!
Installing dependencies from Pipfile.lock (3ca2ea)…
  ?   ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 17/17 — 00:00:02
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.
% pipenv shell
% create-anvil-app todo-list MyTodoList
Congratulations! Your new Anvil app is created, using the 'todo-list'
template. To serve this app, run:

anvil-app-server --app MyTodoList
% anvil-app-server --app MyTodoList
Downloading Anvil App Server JAR to package directory
100% of 236.3 MiB |##########################################################################################| Elapsed Time: 0:05:10 Time:  0:05:10
Downloaded Anvil App Server JAR to 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
Connecting to ws://localhost:3030/_/downlink
Anvil websocket open
[INFO  anvil.executors.downlink] Downlink client connected with spec {:runtime "python3-full", :session_id "xxxxxxxxxxxxxxxxxxxxxx"}
Downlink authenticated OK

http://localhost:3030にアクセスすると以下の画面が開きます。

この手続で生成されるプロジェクトのコードは、Anvilのプロジェクトとして作成して動作するものと同一です。

ソースコードを見てみる

pypiからAnvil App Server JARをダウンロードしてのローカルでの動作をやってみましたが、これはOSSになったソースコードへ触れているわけではありません。

doc/HACKING.mdに沿ってビルドしていきますが、色々と細部が違っているため修正が必要です。

ビルド環境設定

clojureを使う上でメジャーなビルド用ライブラリも入れておきます。

brew install leiningen
git clone git@github.com:anvil-works/anvil-runtime.git

以下、clientとserver夫々の詳細な手続きです。

client

環境に依存する部分があります。

cd anvil-runtime/client
npm install
npm run build

npm run buildの実行時にWARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).と警告がでて正常に完了しない場合は、以下のように修正をいれます。

% vim js/webpack.config.js
   devtool: "source-map",
+  performance: { hints: false },
 };

% npm run build

> anvil-runtime-core@1.0.0 build /path/to/anvil-runtime/client
> webpack --mode production --config js/webpack.config.js

Hash: a8458e152fb974be294a
Version: webpack 4.42.0
Time: 5727ms
Built at: 2020-07-02 12:43:52
               Asset      Size  Chunks                          Chunk Names
    runner.bundle.js   657 KiB       0  [emitted]        [big]  runner
runner.bundle.js.map  1.92 MiB       0  [emitted] [dev]         runner
        sw.bundle.js   120 KiB       1  [emitted]               sw
    sw.bundle.js.map   543 KiB       1  [emitted] [dev]         sw
Entrypoint runner [big] = runner.bundle.js runner.bundle.js.map
Entrypoint sw = sw.bundle.js sw.bundle.js.map
  [9] ./PyDefUtils.js 63.9 KiB {0} [built]
[429] multi babel-polyfill ./runner.js 40 bytes {0} [built]
[430] ./runner.js 62.4 KiB {0} [built]
[451] ./messages.js 1.56 KiB {0} [built]
[452] ./extra-python-modules.js 214 KiB {0} [built]
[453] ./components.js 28.1 KiB {0} [built]
[508] ./modules/anvil.js 46.7 KiB {0} [built]
[509] ./modules/json.js 1.63 KiB {0} [built]
[510] ./modules/base64.js 1.19 KiB {0} [built]
[511] ./modules/xml.js 2.37 KiB {0} [built]
[512] ./modules/regex.js 508 bytes {0} [built]
[513] ./modules/tz.js 3.63 KiB {0} [built]
[514] ./modules/shapes.js 5.27 KiB {0} [built]
[524] multi babel-polyfill ./sw.js 40 bytes {1} [built]
[525] ./sw.js 7.06 KiB {1} [built]
    + 511 hidden modules

変更を監視しておきます。

% cd client/
% npm run watch

> anvil-runtime-core@1.0.0 watch /path/to/anvil-works/anvil-runtime/client
> webpack --mode development --watch --config js/webpack.config.js

webpack is watching the files…
Hash: 74a8058c7e12991d59eb
Version: webpack 4.42.0
Time: 4639ms
Built at: 2020-07-02 12:48:20
               Asset      Size  Chunks                          Chunk Names
    runner.bundle.js  1.63 MiB  runner  [emitted]        [big]  runner
runner.bundle.js.map  2.04 MiB  runner  [emitted] [dev]         runner
        sw.bundle.js   559 KiB      sw  [emitted]        [big]  sw
    sw.bundle.js.map   447 KiB      sw  [emitted] [dev]         sw
Entrypoint runner [big] = runner.bundle.js runner.bundle.js.map
Entrypoint sw [big] = sw.bundle.js sw.bundle.js.map
[0] multi babel-polyfill ./runner.js 40 bytes {runner} [built]
[1] multi babel-polyfill ./sw.js 40 bytes {sw} [built]
[./PyDefUtils.js] 63.9 KiB {runner} [built]
[./components.js] 28.1 KiB {runner} [built]
[./extra-python-modules.js] 214 KiB {runner} [built]
[./messages.js] 1.56 KiB {runner} [built]
[./modules/anvil.js] 46.7 KiB {runner} [built]
[./modules/base64.js] 1.19 KiB {runner} [built]
[./modules/http.js] 10.7 KiB {runner} [built]
[./modules/image.js] 10 KiB {runner} [built]
[./modules/js.js] 491 bytes {runner} [built]
[./modules/json.js] 1.63 KiB {runner} [built]
[./modules/media.js] 3.21 KiB {runner} [built]
[./runner.js] 62.4 KiB {runner} [built]
[./sw.js] 7.06 KiB {sw} [built]
    + 511 hidden modules

server

色々とドキュメントと食い違っているだけでなく、途中でエラーにより中断してしまうため、修正をいれます。

% vim packaging/app-server/build-all
- rm ./build-tmp -rf
+ rm -rf ./build-tmp
% cd packaging/app-server
% ./build-all
*** Building core runtime *********************************
Created /path/to/anvil-runtime/server/core/target/anvil-runtime-latest.jar
Wrote /path/to/anvil-runtime/server/core/pom.xml
Installed jar and pom into local repo.
*** Building database migration ***************************
Compiling migrator.core
Compiling migrator.migrations
Compiling migrator.pg-json-handler
Created /path/to/anvil-runtime/database/migrator-core/target/anvil-migrator-core-latest.jar
Wrote /path/to/anvil-runtime/database/migrator-core/pom.xml
Installed jar and pom into local repo.
*** Building app server ***********************************
Compiling anvil.app-server.conf
Compiling anvil.app-server.dispatch
Compiling anvil.app-server.postgres
Compiling anvil.app-server.run
Compiling anvil.app-server.secrets
Compiling anvil.app-server.tables
Created /path/to/anvil-runtime/server/app-server/target/anvil-app-server-latest.jar
Created /path/to/anvil-runtime/server/app-server/target/anvil-app-server.jar
*** Building Python package *******************************
  adding: anvil-app-server-source.tgz (stored 0%)
*** Build complete.

ビルドされたPythonのパッケージをローカルにインストールします。

% cd /path/to/anvil-runtime/
% pipenv install -e packaging/app-server/python-package-build/
Installing -e packaging/app-server/python-package-build/…
Adding anvil-app-server to Pipfile's [packages]…
✔ Installation Succeeded
Pipfile.lock (08c9cf) out of date, updating to (db4242)…
Locking [dev-packages] dependencies…
Locking [packages] dependencies…
✔ Success!
Updated Pipfile.lock (08c9cf)!
Installing dependencies from Pipfile.lock (08c9cf)…
  ?   ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 17/17 — 00:00:04
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.

サーバを動かします。が、ドキュメントではAnvilのアプリコードが一式揃っている前提となっています。そこで、最初に作成したMyTodoListをまるっとコピーしてきます。

% cd anvil-runtime/server/app-server
% pipenv shell
% mkdir -p test-files/data
% mkdir test-files/apps
% cp -r /path/to/MyTodoList test-files/apps/MyTodoList
% lein run --app test-files/apps/MyTodoList
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
[INFO  anvil.executors.downlink] Downlink client connected with spec {:runtime "python3-full", :session_id "gaRDHwZ3lO9SHKnWbkot"}

http://localhost:3030にアクセスすると、アプリの動作が確認できます。

ダウンリンクの設定

Anvilの1機能であるDownlinkの設定については、環境変数経由での設定で動作を確認できなかったため、ロジックを確認中です。

cd anvil-runtime/downlink/python
pipenv shell
export DOWNLINK_SERVER=ws://localhost:3030/_/downlink
export DOWNLINK_KEY=123456789
python -m anvil_downlink_host.run

Connecting to ws://localhost:3030/_/downlink
Anvil websocket open
Fatal error from Anvil server: Incorrect downlink key

あとがき

Anvilの動作については3通りです。それぞれ目的毎に応じた状態となっています。

環境 用途
Anvilのサービス上での動作 ソースコードの管理割愛
pypi経由でダウンロードしたjarファイル上での動作 Pythonコードのみでローカル管理
jarファイルのソースコード上での直接動作 全てのコードの管理

現状、OSSにて全てを把握出来るようになった状態です。全てのコードを管理したい場合の動作検証コストは高い状態ですが、頑張りたい人、及び要件を満たすことができる等の必要な人にはおすすめです。

参考リンク