nuxt3 の ServerAPI で Cloudflare Workers KV を扱うためのメモ。
shell
# nuxt3プロジェクトをセットアップ
$ npx nuxi init example-cloudflare-kv
$ cd example-cloudflare-kv
$ npm i
# パッケージを追加
$ npm i -D @cloudflare/workers-types wrangler
# Cloudflareにログインする
$ npx wrangler login
依存関係
package.json
{
< 省略 >
"devDependencies": {
"@cloudflare/workers-types": "^4.20231121.0",
"@nuxt/devtools": "latest",
"nuxt": "^3.8.2",
"vue": "^3.3.10",
"vue-router": "^4.2.5",
"wrangler": "^3.19.0"
}
}
Cloudflare の Workers と KV の設定
wrangler.toml
name = "example-cloudflare-kv"
compatibility_date = "2023-12-07"
account_id = "<Cloudflare アカウントID>"
type = "javascript"
main = "./.output/server/index.mjs"
workers_dev = true
[site]
bucket = ".output/public"
[vars]
CLOUDFLARE_ENV = "production"
[build]
command = ""
upload.format = "service-worker"
[[kv_namespaces]]
binding = "STORAGE"
id = "<名前空間ID>"
preview_id = "<名前空間 ID>"
nuxt3のビルド先設定とStorage設定
nuxt.config.ts
export default defineNuxtConfig({
nitro: {
preset: `cloudflare`,
// storage: Production
storage: {
db: {
driver: `cloudflare-kv-binding`,
binding: `STORAGE`,
},
},
// storage: Development
devStorage: {
db: {
driver: `memory`,
},
},
},
});
アプリケーション部分
app.vue
<template>
<p>{{ countRef.clicks }}</p>
<button id="app-count-button" class="btn btn-border" @click="onClick">
POST
</button>
</template>
<script setup lang="ts">
import { Count } from "./server/api/count.patch";
const countRef = ref<Count>();
onMounted(async () => {
// api: count取得
const { data } = await useFetch<Count>("/api/count");
countRef.value = {
clicks: data.value?.clicks || 0,
};
});
async function onClick() {
// api: countのインクリメント
const { data: count } = await useFetch<Count>("/api/count", {
method: `PATCH`,
body: { field: "CLICKS", operator: "INCREMENT" },
});
if (countRef.value && count.value) {
countRef.value.clicks = count.value.clicks;
}
}
</script>
/api/count API の GET メソッド
server/api/count.get.ts
export default defineEventHandler(async (event) => {
// storage: データを取得
const count = await useStorage().getItem(`db:count`);
// api: countを返す
return count;
});
/api/count API の PATCH メソッド
server/api/count.patch.ts
export interface Count {
clicks: number;
}
export interface CountUp {
field: "CLICKS";
operator: "INCREMENT";
}
export default defineEventHandler(async (event) => {
// api: パラメータを取得
const body: CountUp = JSON.parse((await readRawBody(event)) as string);
// storage: データを取得
const count: Count = (await useStorage().getItem(`db:count`)) ?? {
clicks: 0,
};
// インクリメント指示の判定
if (body.field === `CLICKS` && body.operator === `INCREMENT`) {
// クリック数をカウントアップ
count.clicks++;
// storage: データを保存
await useStorage().setItem(`db:count`, JSON.stringify(count));
}
// api: countを返す
return count;
});
nuxt3のビルドとデプロイ
shell
# nuxt3のビルド
$ nuxt build
# cloudflare worksにdeploy
$ wrangler publish