petite-vue を試す環境として packup を試してみたらすごく良かった

petite-vue というライブラリがあります。
Vue.js の代替ディストリビューションという説明がリポジトリの README にあります。

これを動作確認する環境として、packupを採用したら快適だったのでメモです。

参考

導入

docker 環境準備

packup は、deno で動作するアプリケーションパッケージャーなので、deno 用の docker 環境を用意します。

dockerfile
1
2
3
4
5
6
7
FROM denoland/deno:centos

RUN mkdir /usr/src/app
WORKDIR /usr/src/app

EXPOSE 8080
EXPOSE 35729
docker-compose.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
version: "3"
services:
app:
build:
context: .
dockerfile: Dockerfile
privileged: true
entrypoint:
- /sbin/init
ports:
- "8080:8080"
- "35729:35729"
volumes:
- .:/usr/src/app:cached
tty: true

ポート 35729 を公開しておくのが、packup を実行する上ではポイントです。
自動リロード関連の為に空いているポートの様です。
Docker 環境でディレクトリをマウントしていると、ファイル監視が効かないです。
(これは回避策がわからないのでどうにかしたい。)
が、ブラウザから通信先になっており他のロードに影響してしまうので、開けておきましょう。

packup を導入

README 通りの導入を進めます。

1
2
3
4
5
6
$ deno run -A https://deno.land/x/packup@v0.1.12/install.ts
$ which packup
/usr/local/bin/packup

# 動作に支障はないが、実行時に No static dir "static" と表示されるので作っておいた
$ mkdir static

index.html を作成。

index.html
1
2
3
4
5
6
<html>
<body>
<script src="./main.ts"></script>
<h1>Hi from packup!</h1>
</body>
</html>

main.ts を作成。

main.ts
1
console.log("hello world");

次のコマンドで起動。

1
$ packup -p 8080 index.html

ブラウザで、localhost:8080 にアクセスするとページを取得できます。

次のコマンドでビルドをできました。

1
$ packup build index.html

dist ディレクトリが作成され index.fccc32343a257ba23b7683a823b9c262.js が作成されていました。

index.fccc32343a257ba23b7683a823b9c262.js
1
2
3
4
(() => {
// deno:file:///usr/src/app/page/main.ts
console.log("hello world");
})();

petite-vue を導入

petite-vue の README に従い導入してみます。

index.html[書き換え1]
1
2
3
4
5
6
7
8
9
10
11
<html>
<body>
<script src="https://unpkg.com/petite-vue" defer init></script>

<!-- anywhere on the page -->
<div v-scope="{ count: 0 }">
{{ count }}
<button @click="count++">inc</button>
</div>
</body>
</html>

ボタンを押すと数字のカウントアップされるものが動きます。

少し書き換えてカウンターを2つ用意します。

index.html[書き換え2]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>

<body>
<script type="module">
import { createApp } from "https://unpkg.com/petite-vue?module";

function counter() {
return {
count: 0,
clickCount: 0,
// getters
get getClickCount() {
// head で文字コードを指定しないと
// return `${this.clickCount}回`; は、SyntaxError: Unexpected end of input になる
return `${this.clickCount}回`;
},
// methods
increment() {
this.count++;
this.clickCount++;
},
decrement() {
this.count--;
this.clickCount++;
},
};
}

createApp({
counter,
}).mount("#app1");

createApp({
counter,
}).mount("#app2");
</script>

<div v-scope="counter()" id="app1">
<p>{{ count }}({{ getClickCount }})</p>
<button @click="increment">increment</button>
<button @click="decrement">decrement</button>
</div>

<div v-scope="counter()" id="app2">
<p>{{ count }}({{ getClickCount }})</p>
<button @click="increment">increment</button>
<button @click="decrement">decrement</button>
</div>
</body>
</html>

動作させると、独立して動作するカウンターと総クリック数が2つ表示できています。

これよりも高度な使い方は README に記載が有るので、そちらを参照。
テンプレートも使えるのが面白そうです。

petite-vue を packup でバンドル

本題の petite-vue を packup でバンドル をやってみます。
せっかくバンドルするので、color-hashも使ってみます。
クリックするたびに色が変わるという具合ですね。

main.ts[書き換え1]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import ColorHash from "https://deno.land/x/color_hash@v2.0.0/mod.ts";
import { createApp } from "https://cdn.skypack.dev/petite-vue";

const colorHash = new ColorHash();

function counter() {
return {
count: 0,
clickCount: 0,
get getClickCount() {
return `${this.clickCount}回`;
},
get getColor() {
return colorHash.hex(`${this.clickCount}`);
},
increment() {
this.count++;
this.clickCount++;
},
decrement() {
this.count--;
this.clickCount++;
},
};
}

createApp({
counter,
}).mount("#app1");

createApp({
counter,
}).mount("#app2");

petite-vue のロード先を unpkg から skypack に切り替えています。
切り替えないと次のエラーになります。

1
2
deno:file:///usr/src/app/page/main.ts:27:26: error: [plugin: deno] Unreachable.
27 │ import { createApp } from 'https://unpkg.com/petite-vue?module'

続けて HTML は次の用意なります。script がスッキリしました。

index.html[書き換え3]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>

<body>
<script type="module" src="./main.ts"></script>

<div v-scope="counter()" id="app1">
<p v-bind:style="{color: getColor}">{{ count }}({{ getClickCount }})</p>
<button @click="increment">increment</button>
<button @click="decrement">decrement</button>
</div>

<div v-scope="counter()" id="app2">
<p v-bind:style="{color: getColor}">{{ count }}({{ getClickCount }})</p>
<button @click="increment">increment</button>
<button @click="decrement">decrement</button>
</div>
</body>
</html>

動かしてみると次のようになります。

petite-vue を packup でバンドルして使うことができました。


今回は、petite-vue のバンドルを試すにあたって vite でやろうかとも考えたものの、packup を
試してみてよかったです。
aleph や Ultra などのガチっとした react のフレームワークではなく、Deno での軽いページの開発に適したものが無かったので、とてもフィットしていました。

petite-vue は、READMEに「少しのインタラクションを振りかける」といったような表現が出てきます。
stimulus に思想が近いなぁと感じていましたが、同じような言説や、そもそもそこが意識されているという記述も見かけます。

WEBの開発も軽重有るのでこういったものもありがたいものです。
既存のVueの知識も生かせるので。(jQuery の知識が薄すぎるので、あれなだけですけれども。)

ではでは。