こんにちは|こんばんは。カエルのアイコンで活動しております @kyamaz です。
はじめに
本稿は、グラフデータベースである kuzudb を Vue3 で扱うための手順を取り上げます。
前半の Vue3 環境の構築については拙稿『p5.jsをVue3のコンポーネントにする』に習っており、後半もほかの複数の手順を参考にしながら本稿にまとめております。
KuzuDB とは
高性能なクエリ処理と拡張性を重視したオープンソースのグラフデータベースです。MITライセンスで提供されており、商用利用も可能です。グラフデータベースは他に Neo4j が有名ですが、KuzuDB は Cypherライクなクエリ言語をサポートしており、Neo4jと同様の使い方ができるのも特徴の一つです。高速なストレージ管理や並列クエリ実行による高スループットの実現などもされており、Neo4jの代替として大規模なグラフデータを効率的に扱いたいユースケースに向いているようです。
このあとは、Vue3 の環境を整えたのちに、KuzuDB をブラウザ上で扱うWebassembly 実装である kuzu-wasm
を使えるように整えていきます。
Vue3 + TypeScript + Vite の環境を整える
まず、プロジェクト名をkuzuvue
(お好きな名前でよいです)としてVue 3 + TypeScript + Vite + Jestの環境をまず整えます。
% npm init vite@latest kuzuvue -- --template vue-ts
Scaffolding project in /hoge/fuga/kuzuvue...
Done. Now run:
cd kuzuvue
npm install
npm run dev
出力された通りにnpm
を実行しておきましょう。npm run dev
の後に次のように出力されますので、手元のブラウザでhttp://localhost:5173/
にアクセスしてみます。
VITE v5.0.XX ready in XXX ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ press h + enter to show help
動作が確認できればCtrl-C
でプロセスを終わらせて、次の手順に進みます。ついでに、プロジェクトルートで次のモジュールもインストールしておきましょう。
npm install vue-router
npm install -D vitest
次に、vue-router で動作するように整えていきます。src
フォルダにrouter.ts
を新規で作成します。
// router.ts
import { createRouter,createWebHistory } from 'vue-router';
import Home from "./pages/Home.vue";
const routes = [
{ path: '/', name: 'home', component: Home },
]
const router = createRouter({
history: createWebHistory(), // HTML5 History モード
routes,
})
export default router;
また、main.ts
を次のように書き換えます。
// main.ts
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'; // router.tsをインポート
const app = createApp(App)
app.use(router) // Vue Routerを使用する
app.mount('#app')
そして、src
フォルダの構成を変更して、必要なファイルを編集していきます。
-
src
フォルダの下にpages
を作成し、そこにApp.vue
をHome.vue
いうファイル名でコピーしておきます。 -
components
,assets
フォルダをpages
の下に移動します。(mv src/components src/assets src/pages/
) -
App.vue
を次のように変更します。
<template>
<router-link to="/"></router-link>
<router-view/>
</template>
<script lang="ts">
export default {
}
</script>
<style scoped>
</style>
ここまでは、一般的な Vite+Vue3+VueRouter の開発テンプレートの構築手順です。
次から、このテンプレートの状態から kuzudb を使えるようにしていきましょう。
kuzudb をインストールする
kuzudb 関連のモジュールを使用できるようにインストールします。
※本来はTypeScriptで型チェックができるようにする必要がありますが、型定義が簡単にインストールできなく、 がうまく環境を整えられなかったため、ここでは割愛させて頂き、Javascriptとしてのみ動作させる方向で進めます。型チェックができるようにするには、Reactの例になりますが、@hibohiboo さんの以下の記事をご参考ください。
% npm install kuzu
% npm install @kuzu/kuzu-wasm
ここからは、HelloWorld.vue
に kuzu を実装していきます。
その前に、トップページをシンプルになるように編集しておきましょう。Home.vue
を次のように、コンポーネントHelloWorld
を使うように変更します。
<script lang="ts">
import HelloWorld from './components/HelloWorld.vue'
export default {
components: {
HelloWorld
}
}
</script>
<template>
<div>
<HelloWorld />
</div>
</template>
<style scoped>
</style>
HelloWorld.vue に kuzu-wasm を利用する部分を次のように書きます。
<script setup>
import { ref, onMounted } from 'vue';
import kuzu_wasm from "@kuzu/kuzu-wasm";
const users = ref([]);
const do_mounted = async () => {
const kuzu = await kuzu_wasm();
const db = await kuzu.Database();
const conn = await kuzu.Connection(db);
// テーブルの作成
conn.execute(`CREATE NODE TABLE User(name STRING, age INT64, PRIMARY KEY(name))`);
conn.execute(`CREATE REL TABLE Follows(FROM User TO User, since INT64)`);
// データの挿入
conn.execute(`CREATE (u:User {name: 'Alice', age: 31});`);
conn.execute(`CREATE (u:User {name: 'Bob', age: 40});`);
// データの取得
const res = conn.execute(`MATCH (a:User) RETURN a.name AS name, a.age AS age;`);
console.log(res);
};
onMounted(do_mounted);
</script>
<template>
<div>
<h1>Kuzu-WASM with Vue</h1>
<ul>
<li v-for="user in users" :key="user.name">
{{ user.name }} - {{ user.age }}歳
</li>
</ul>
</div>
</template>
(動作不備)users に KuzuDB の値を入れてサイト上に表示したいのですが、うまく動作できておりません。対応できましたら改めて修正します。ご容赦ください。
WASM を試す際に、SharedArrayBuffer の対応が必要
このままnpm run dev
で試してみると、ブラウザのコンソールに SharedArrayBuffer is not defined
のエラーが出ます。調べてみると以下の記事が参考になりました。
そこで vite.config.ts
を次のように書き換えてから、npm run dev
を行い、ブラウザで試してみたところ、エラーが解消しました。
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vite.dev/config/
export default defineConfig({
plugins: [vue()],
build: { target: 'esnext' },
optimizeDeps: {
exclude: ['@kuzu/kuzu-wasm'],
esbuildOptions: {
target: 'es2022',
},
},
server: {
headers: {
'Cross-Origin-Embedder-Policy': 'require-corp',
'Cross-Origin-Opener-Policy': 'same-origin',
},
},
})
最後に
初稿の公開では、完全に動作ができていないままですが、ご見識の高い方からのご助言もあると助かります。
ご一読いただきまして有り難うございます。
最後に、本稿を記載するために検証したNodeJSとブラウザ環境を記しておきます。お手元の環境で検証する際に動作が異なる場合などは、参考になるかもしれません。
本稿の環境
本稿のために使用した環境は以下となります。
macOS: Sequoia 15.3.1 (chip: Apple M1)
node: v18.19.0
npm: 10.9.2
Google Chrome 133.0.6943.127 (Official Build) (arm64)
(●)(●) Happy Hacking!
/"" __""\