最近触ってる Elysia などに触発されて、作ってから11年(厳密には16年)も経った自作のチャートライブラリ ccchart が流石にいろいろ古くて、いじりたくなってきた。
モダンな環境で例えばプラグインのように呼び出したいとか、TailwindCSS の purge のように type lineやbarなどを使うものだけを送信したいとか夢は山ほどあるのだけど、
とりあえず、昨日 Elysia のプラグインを作ったのを良い機会ということで、ccchart を Elysiaプラグインにしてみようと思った。
今回はその作成物語です。
目標
- ccchatのコードをElysia のプラグインとして利用する
- URLをブラウザへ送るのではなく SSRまたはSSGとして生成して渡す
- ブラウザへ送る前にminifyする
- (希望)毎回全コード送るのではなく棒グラフだけ使うなら棒グラフだけにパージしたい。
- (希望)Elysiaのコミュニティプラグインに登録してみたい
- もし、追加したい機能が思いつけば都度追加する
そういえば、レジストリからダウンロードされたすべてのパッケージは、~/.bun/install/cache のグローバル キャッシュに保存されるわけだから、プラグインに登録するとできるのだろうか?今度やってみたい。npmの方だろうか?
Elysia プラグインのドキュメント
Elysia > Plugins
今回の環境
クラウド: Azure VM (これは何でも良い)
OS: Ubuntu 20.04.6 LTS (GNU/Linux 5.15.0-1050-azure x86_64)
Bun: v1.0.18
Elysia: v0.7.30
BunのインストールやElysia プロジェクト作成は、本家や前回 などを参考にしてみてください。
今回はこんなディレクトリを作ります
ざっくりいうと
lib/ にソース(ccchart.js など)
src/ に起動ファイル(index.ts)とプラグイン(ccchart_plugin.ts)
を配置しています。(まぁ、プロジェクトの方針次第ですが)
src/plugins/ccchart_plugin.ts というプラグインファイルは、lib のソースからテキストコードを取り出して minify し、起動ファイル index.ts のHTTPサーバーが lissen している GET メソッドに渡します。
.ccchart/
├─ lib/
│ └─ ccchart.js // ccchart オリジナルファイル
├─ src/
│ ├─ ( ccchart.js // 生成されたminifyファイル )
│ ├─ index.ts // bun dev で起動するファイル
│ └─ plugins
│ └─ ccchart_plugin.ts //プラグインファイル
│
├─ README.md
├─ bun.lockb
├─ node_modules/
├─ package.json
└─ tsconfig.json
この ccchart のデータ は、別の WebSocket サーバーから受信してリアルタイム表示してるのですが、今回はプラグイン作成の話なので省略します。気になる方は、下記やQiita検索を ccchart でしてみてください。
結果
その結果、ブラウザにはこんな動くチャートが表示されます。
今回の動作サンプル
まぁ、今回も作ったものを pm2 start "bun dev" してあげておきます。まぁ期間限定になるとは思いますが、参考までにどうぞ。
起動ファイルの中身
起動ファイルは src/index.ts です。
├─ src/
│ ├─ ( ccchart.js // 生成されたminifyファイル )
│ ├─ index.ts // bun dev で起動するファイル
│ └─ plugins
│ └─ ccchart_plugin.ts //プラグインファイル
pacage.jsonのscriptは以下のようになっていますので、「$ bun dev」で実行できます。パラメータ「--watch 」は ホットリロード です。ファイルが変更された時に、自動的に再起動してくれます。
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "bun run --watch src/index.ts"
},
cssなどは分けていないので、実際に使う時は適当に配置しましょう。
因みに、ccchartは個々のチャートのスタイルをchartDfaultOptions や config
で設定することが多いです。
import { Elysia } from "elysia";
import { html } from '@elysiajs/html';
import { ccchart } from './plugins/ccchart_plugin.ts';
// メインのHTTPサーバー
const app = new Elysia()
.use(html)
.use(ccchart)
//.use(chartDfaultOptions)
.get('/', ({ ccchart }) =>{
return `
<style>
#hoge0{
display: block;
background-color: rgb(255, 255, 255);
border: 1px solid #ccc;
background-color: rgba(120,120,120,0.0);
box-shadow: 12px 12px 12px rgba(100,100,100,0.3), inset 1px 1px 1px 5px rgba(250,250,250,0.5);
border-radius: 12px;
margin: 10px;
}
</style>
<div class="chart"><canvas id="hoge0"></canvas></div>
<script>${ ccchart }</script>
<script>
// 共通スタイル
const chartDfaultOptions = {
"config": {
"title": "",
"subTitle": "",
"type": "line",
"minY": 0,
"maxY": 100,
"width": 560,
"height": 300 ,
"lineWidth": 1,
"xScaleSkip": 5,
"useMarker": "maru", // canvas版の丸で高速化 ツールチップが必要なら >cssハイブリッド版"css-maru"
"markerWidth": 8,
"xLines": [
{"val":66,"color":"rgba(0,0,0,0.7)"}
],
"bg": "#fff",
"textColors": {"title":"#777","subTitle":"#777","x":"#999","y":"#999","hanrei":"#777","unit":"#777","memo":"#666"},
"colorSet":
["#DDA0DD","#3CB000"],
"shadows": {
"hanrei" : ['#aaa', 5, 5, 5],
"xline": ['#555', 7, 7, 5],
"line": ['#666', 5, 5, 5],
"bar": ['#bbb', 5, 5, 5],
"stacked": ['#bbb', 5, -5, 5],
"stackedarea": ['#666', 5, 5, 5],
"bezi": ['#666', 5, 5, 5],
"bezi2": ['#666', 5, 5, 5]
}
}
};
// 共有スタイルに個々のスタイルをマージする
const chartCfg0 = ccchart.util.cnfExtend( chartDfaultOptions, {
// 個々のスタイル
config: {
title : "useRowData: 0",
subTitle : "水平カスタム線に2件目のデータ使用",
xLines: [
{"useRow": 1, "color":"rgba(250,0,0,0.7)"}
]
},
// 受信したデータを入れる配列
"data": [
["時間"],
["1件目"],
["2件目"]
]
});
// ccchart を実行する
ccchart
.init('hoge0', chartCfg0)
.ws('wss://ccchart.com:8016')
.on('message', ccchart.wscase.oneColAtATime);
//oneColAtATimeは、WebSocketの受信パターン関数
// 一度に1列ずつ [["2013"],[435],[600]] と
// いった配列で届く場合用
</script>
`})
.listen(9010);
プラグインの中身
では、プラグイン関連のコード( src/plugins/ccchart_plugin.ts )を見ていきましょう
import { Elysia } from "elysia";
// ファイル名
const fileName = '/ccchart.js';
// ソースファイルのあるディレクトリ
const fromDir = './lib';
// ミニファイファイルを出力するディレクトリ
const toDir = './src';
// minify する
await Bun.build({
entrypoints: [fromDir + fileName],
outdir: toDir,
minify: true, // default false
})
// plugin を作る
const ccchart_str = Bun.file(toDir + fileName)
export const ccchart= new Elysia()
.decorate('ccchart', await ccchart_str.text())
まぁ、難しいことはやってません。
Elysia のプラグイン化し、minify したソースをccchartという名前で export しているだけです。
minifyの方法については、 Bun の Build のところにいろいろな方法が載っています。
Bun > Build
あと目標でできてないのは、分割選択送信とプラグイン登録だけど、たぶん分割はものすごく時間っがかかりそう。。できるかなぁ。
まぁ、とりま今日はここまで。
最近 Qiita に書いた Bun 関連の記事10選