Nuxt EdgeDB
輕鬆將 Nuxt 3 與 EdgeDB 整合,以最少的配置為您的應用程式新增強大的資料庫層。
功能
- 🍱 輕鬆整合:只需一行配置即可設定資料庫。
- 🎩 即時模式更新:透過對 schema、queries 和 migrations 的監聽器體驗 HMR 般的開發體驗。
- 🛟 型別化查詢生成:使用 @edgedb/generate 自動生成型別化查詢客戶端。
- 🍩 整合資料庫管理:透過 Nuxt DevTools 管理您的資料庫。
- 🔐 靈活的身份驗證:透過 1 行程式碼切換 電子郵件 或 OAuth 身份驗證,並支援自定義身份驗證提供商。
- 🧙 初步指導:引導您完成 EdgeDB CLI 設定和 專案初始化。
快速設定
- 將
nuxt-edgedb-module
依賴新增到您的專案中
npx nuxi@latest module add edgedb
- 將
nuxt-edgedb-module
新增到nuxt.config.ts
的modules
部分
export default defineNuxtConfig({
modules: [
'nuxt-edgedb-module'
]
})
- 在您的專案根目錄執行
npx nuxt-edgedb-module
以執行 CLI 設定嚮導。
npx nuxt-edgedb-module
就是這樣!您的 Nuxt 專案現在擁有一個數據庫。✨
如果您尚未在計算機上安裝 EdgeDB,安裝嚮導將幫助您安裝它。
示例專案
如果您想執行示例專案,您必須克隆此儲存庫並執行 playground。
因為 EdgeDB 無法在 Stackblitz 或 CodeSandbox 等 Web 容器環境中執行。
git clone [email protected]:Tahul/nuxt-edgedb.git
cd nuxt-edgedb
pnpm install
pnpm stub
cd playground
edgedb project init
npx nuxt-edgedb-module
pnpm run dev
模組選項
您可以從 nuxt.config.ts
檔案配置模組的任何行為
export default defineNuxtConfig({
modules: ['nuxt-edgedb-module'],
edgeDb: {
// Devtools integrations
devtools: true,
// Completely toggle watchers feature
watch: true,
// Enable or disable prompts on watch events
watchPrompt: true,
// Generate target for your queries and query builder
generateTarget: 'ts',
// dbschema/ dir
dbschemaDir: 'dbschema',
// Individual queries dir (useEdgeDbQueries composable)
queriesDir: 'queries',
// Toggle CLI install wizard
installCli: true,
// Toggles composables
composables: true,
// Toggles auto-injection on auth credentials
injectDbCredentials: true,
// Enables authentication integration
auth: false,
// Enables oauth integration
oauth: false,
}
})
伺服器端使用
該模組會自動匯入 Nuxt 應用程式 server/
上下文中所有可用的可組合函式。
useEdgeDb
useEdgeDb
使用您的 Nuxt 環境配置公開從 edgedb
匯入的原始客戶端。
// server/api/blogpost/[id].ts
import { defineEventHandler, getRouterParams } from 'h3'
export default defineEventHandler(async (req) => {
const params = getRouterParams(req)
const id = params.id
const client = useEdgeDb()
const blogpost = await client.querySingle(`
select BlogPost {
title,
description
} filter .id = <uuid>$id
`, {
id: id
});
return blogpost
})
useEdgeDbQueries
useEdgeDbQueries
公開您的 dbschema/queries.ts
中的所有查詢。
您不必向它們傳遞客戶端。它們將使用由 useEdgeDb
生成的、作用域為當前請求的客戶端。
// queries/getBlogPost.edgeql
select BlogPost {
title,
description
} filter .id = <uuid>$blogpost_id
// server/api/blogpost/[id].ts
import { defineEventHandler, getRouterParams } from 'h3'
export default defineEventHandler(async (req) => {
const params = getRouterParams(req)
const id = params.id
const { getBlogpPost } = useEdgeDbQueries()
const blogPost = await getBlogpost({ blogpost_id: id })
return blogpost
})
您仍然可以直接從 #edgedb/queries
匯入 查詢,並向它們傳遞來自 useEdgeDb()
的客戶端。
// server/api/blogpost/[id].ts
import { getBlogPost } from '#edgedb/queries'
import { defineEventHandler, getRouterParams } from 'h3'
export default defineEventHandler(async (req) => {
const params = getRouterParams(req)
const id = params.id
const client = useEdgeDb()
const blogPost = await getBlogpost(client, { blogpost_id: id })
return blogpost
})
useEdgeDbQueryBuilder
useEdgeDbQueryBuilder
將生成的 查詢構建器 直接暴露給您的 server/
上下文。
// server/api/blogpost/[id].ts
import { defineEventHandler, getRouterParams } from 'h3'
export default defineEventHandler(async (req) => {
const params = getRouterParams(req)
const id = params.id
const client = useEdgeDb()
const e = useEdgeDbQueryBuilder()
const blogPostQuery = e.select(
e.BlogPost,
(blogPost) => ({
id: true,
title: true,
description: true,
filter_single: { id }
})
)
const blogPost = await blogPostQuery.run(client)
return blogpost
})
型別定義
EdgeDB 生成的所有介面都可透過 #edgedb/interfaces
匯入。
<script setup lang="ts">
import type { BlogPost } from '#edgedb/interfaces'
defineProps<{ blogPost: BlogPost }>()
</script>
身份驗證
您可以將 EdgeDB 用作僅限伺服器的資料庫,透過 server/api
端點和客戶端上的 $fetch
公開,從而避免需要身份驗證。
但在某些專案中,您可能希望使用者登入,以便他們在伺服器上也有身份。幸運的是,該模組為您解決了這個問題。
在執行這些身份驗證安裝步驟之前,我們強烈建議您閱讀 EdgeDB 身份驗證 文件。
auth
選項 在 Nuxt 配置中啟用
export default defineNuxtConfig({
modules: ['nuxt-edgedb-module'],
edgedb: {
auth: true
}
})
在您的模式中設定 EdgeDB 身份驗證
在此示例中,您可以注意到
global current_user
定義了一個與客戶端令牌身份關聯的 全域性屬性。type User
是您的使用者模型,您可以隨意更改它,這可以在以後透過遷移來完成。access policy author_has_full_access
&using (.author ?= global current_user);
定義了使用者只能訪問其自己的BlogPost
的策略。
// dbschema/default.esdl
using extension auth;
module default {
global current_user := (
assert_single((
select User { id, name }
filter .identity = global ext::auth::ClientTokenIdentity
))
);
type User {
required name: str;
required identity: ext::auth::Identity;
}
type BlogPost {
property content: str {
default := 'My blog post content.';
};
property title: str {
default := 'My blog post';
};
required author: User;
access policy author_has_full_access
allow all
using (.author ?= global current_user);
access policy others_read_only
allow select;
}
}
您可以在伺服器執行時編輯此模式,並接受提示訊息以自動遷移。
如果您在伺服器關閉時進行這些編輯,可以執行 edgedb migration create
和 edgedb migrate
。
在您的伺服器中設定 EdgeDB 身份驗證
您需要在 EdgeDB 伺服器上啟用身份驗證提供商。
這可以透過您的 DevTools 中的 EdgeDB
選項卡完成。
瀏覽您的資料庫到 Auth Admin
並指定
auth_signing_key
allowed_redirect_urls
您還必須啟用一些提供商。例如,您可以從 Email + Password
開始。
如果您啟用 required_verification
,則需要為您的 EdgeDB 例項配置 SMTP 伺服器。
您可以在此處找到有關如何在本地使用 Mailtrap 嘗試此功能的進一步說明。
請記住,這些步驟也必須在您的生產環境中執行。
在客戶端使用身份驗證元件
由於您在配置中啟用了身份驗證,該模組已將這些元件注入到您的專案中
EdgeDbAuthEmailLogin
EdgeDbAuthEmailVerify
EdgeDbAuthLogout
EdgeDbAuthResetPassword
EdgeDbAuthSendPasswordReset
EdgeDbAuthSignup
EdgeDbAuthProviders
您可以檢視這些元件的原始碼以瞭解更多關於它們的 props。
它們都是無樣式的元件,只公開必要的邏輯以實現流暢的身份驗證流程。
<template>
<EdgeDbAuthEmailLogin
v-slot="{ email, updateEmail, password, updatePassword, submit, loading }"
redirect-to="/"
>
<div>
<input
type="email"
:value="email"
placeholder="[email protected]"
@change="(e) => updateEmail(e.target.value)"
>
<input
type="password"
:value="password"
placeholder="password"
@change="(e) => updatePassword(e.target.value)"
>
<button
type="button"
@click="(e) => !loading && submit()"
>
{{ loading ? 'Loading' : 'Login' }}
</button>
</div>
</EdgeDbAuthEmailLogin>
</template>
當然,您可以完全在本地重寫這些元件中的任何一個,以實現您自己的身份驗證流程。
OAuth
如果您想使用 OAuth,您必須在您的 nuxt.config
中啟用它
export default defineNuxtConfig({
edgeDb: {
oauth: true
}
})
這會將兩個新元件注入到您的應用程式中
EdgeDB 目前支援以下提供商的 OAuth
- Apple
- Azure (Microsoft)
- GitHub
為了使 OAuth 正常工作,您需要透過 Nuxt DevTools 訪問您的 EdgeDB 例項 UI。
瀏覽到您的資料庫並訪問“Auth Admin”選項卡。
在提供商列表中,您可以新增任何您想要的提供商並配置必要的金鑰(通常是客戶端 appid
和 secret
)。
不要忘記將您的提供商的回撥 URL 設定為 EdgeDB Auth Admin 頂部列出的 URL。
然後,您可以在您的應用程式中建立一個簡單的 OAuth 按鈕,如下所示
<template>
<!-- Gives access to all available auth providers -->
<EdgeDbAuthProviders v-slot="{ oAuthProviders: providers }">
<!-- Create a OAuth button behavior from a provider name -->
<EdgeDbOAuthButton
v-for="provider of providers"
:key="provider.name"
v-slot="{ redirect }"
:provider="provider.name"
>
<!-- Call `redirect` from the OAuthButton -->
<button @click="() => redirect()">
{{ provider.display_name }}
</button>
</EdgeDbOAuthButton>
</EdgeDbAuthProviders>
</template>
您還需要一個回撥頁面,可以使用 EdgeDbAuthCallback
。
<template>
<EdgeDbOAuthCallback
v-slot="{ loading }"
redirect-to="/"
>
<div>
<h2>OAuth callback</h2>
<p v-if="loading">
Loading...
</p>
</UCard>
</div>
</EdgeDbOAuthCallback>
</template>
太棒了,不是嗎?!只需幾行程式碼,我們就為我們的應用程式添加了基本的身份驗證。
客戶端使用
現在身份驗證已實現,您還可以在 Nuxt 應用程式中使用 useEdgeDbIdentity
可組合函式。
<script setup lang="ts">
const { isLoggedIn } = useEdgeDbIdentity()
</script>
<template>
<div>
<LoginButton v-if="isLoggedIn" />
<LogoutButton v-else />
</div>
</template>
您可以檢視 useEdgeDbIdentity
獲取更多詳細資訊。
伺服器端使用
身份驗證過程確實使用一個名為 edgedb-auth-token
的 cookie。
在伺服器上,如果您想為當前使用者向資料庫進行身份驗證請求,您只需將當前請求物件傳遞給可組合函式即可
export default defineEventHandler(async (req) => {
// Will throw an error, as you cannot delete a BlogPost without being the author
const { deleteBlogPost } = useEdgeDbQueries()
await deleteBlogPost({ blogpost_id: id })
// Success
const { deleteBlogPost: deleteBlogPostAuthenticated } = useEdgeDbQueries(req)
await deleteBlogPostAuthenticated({ blogpost_id: id })
return { id }
})
其他身份驗證解決方案
EdgeDDB Auth 是一個很棒的解決方案,但您的應用程式以後可能需要更多功能。
不要忘記 EdgeDB 也可以用作資料庫。您可以構建自己的身份驗證或使用現有解決方案,例如
您也可以 同時 使用並從您自己的身份驗證提供商建立身份物件,並使用 edgedb-auth-token
作為您的 cookie。
我建議檢視 https://github.com/edgedb/edgedb-examples,其中充滿了基於 EdgeDB 構建的自定義身份驗證的精彩示例。
身份驗證環境變數
# Your EdgeDB instance auth extension base URL
NUXT_EDGEDB_AUTH_BASE_URL=https://:10702/db/edgedb/ext/auth/
# Your EdgeDB instance OAuth callback URL
NUXT_EDGEDB_OAUTH_CALLBACK=https://:10702/db/edgedb/ext/auth/callback
# Your app callback page
NUXT_EDGEDB_OAUTH_REDIRECT_URL=https://:3000/auth/callback
# Your app app reset password URL (receiving the token from the forgot password email)
NUXT_EDGEDB_AUTH_RESET_PASSWORD_URL=https://:3000/auth/reset-password
# Your app email verify url (receiving the token from email verify feature)
NUXT_EDGEDB_AUTH_VERIFY_REDIRECT_URL=https://:3000/auth/verify
深入瞭解身份驗證
EdgeDB Auth 僅提供身份驗證所需的最基本身份功能。
在提供的身份驗證設定程式碼示例中,User
型別與 Identity
介面一起出現。
如果您想在註冊時用其他屬性填充 User
,您將不得不自己實現此行為。
如果您想從 OAuth 提供商解析資料,您可以從 Nitro 外掛使用名為 edgedb:auth:callback
的 Nitro 鉤子。
// server/plugins/auth.ts
export default defineNitroPlugin((app) => {
app.hooks.hook('edgedb:auth:callback', (data) => {
const {
code,
verifier,
codeExchangeUrl,
codeExchangeResponseData,
} = data
// codeExchangeResponseData contains the OAuth token from the provider.
// ... implement your own authentication logic.
})
})
生產環境
如果您想脫離開發環境並將資料庫部署到生產環境,您必須遵循 EdgeDB 指南。
EdgeDB 是一個開源資料庫,旨在自託管。
然而,他們還提供了一個 雲服務,由於環境變數的緣故,它與此模組完全相容。
如果您想自定義可組合函式使用的 DSN,您可以使用模組提供的環境變數
NUXT_EDGEDB_HOST=
NUXT_EDGEDB_PORT=
NUXT_EDGEDB_USER=
NUXT_EDGEDB_PASS=
NUXT_EDGEDB_DATABASE=
如果您想使用環境變數,您必須指定 所有 變數,否則客戶端將回退到預設值。
問答
我的資料庫客戶端會暴露給使用者嗎?
不會,useEdgeDb
和 useEdgeDbQueries
僅在 Nuxt 的 server/ 上下文可用。
作為 可選功能,您可以在客戶端從 @dbschema/queries
匯入查詢。
您需要為這些查詢提供一個來自 createClient()
的客戶端。
<script setup lang="ts">
import { createClient } from 'edgedb'
import { getUser } from '@dbschema/queries'
const client = createClient()
const user = await getUser(client, 42)
</script>
您還可以,同樣作為 可選功能,將查詢構建器匯入到客戶端。
我猜這對於超級管理員/內部儀表板可能很有用,但在安全訪問方面請自行承擔風險。
<script setup lang="ts">
import e, { type $infer } from '#edgedb/builder'
const query = e.select(e.Movie, () => ({ id: true, title: true }))
type result = $infer<typeof query>
// ^ { id: string; title: string }[]
</script>
請注意這些匯入,因為如果您匯入錯誤的查詢,可能會導致客戶端擁有寫入操作,從而可能損害您的資料庫。
如何在生產環境中執行我的遷移?
- 在您的生產環境克隆您的 Nuxt 專案
- 確保您已在伺服器上安裝 EdgeDB CLI
- 將
edgedb migrate --quiet
新增到您的 CLI 指令碼中
我應該版本化生成的檔案嗎?
不,因為它們是使用 Nuxt 客戶端生成的,您應該將它們新增到您的 .gitignore
中
**/*.edgeql.ts
dbschema/queries.*
dbschema/query-builder
dbschema/interfaces.ts
queries/*.query.ts
如果更改 **Dir
選項,您必須相應地更改這些路徑。
我的資料庫模式的 HMR 真的安全嗎?
嗯,這取決於您何時使用它。
我建議在您隨意開發專案時保持 watchPrompt
啟用。
這將防止執行任何不需要的遷移,並且只會在您向模式新增新內容時提示。
如果您想快速且知道自己在做什麼,可以將 watchPrompt
設定為 false,並受益於對模式的任何更改的自動遷移建立和應用。
如果您不希望使用這些功能,只需將 watch
設定為 false,並放心地更改您的開發資料庫。
您的資料庫上的 HMR 在生產環境中顯然 沒有 效果。
nuxt-edgedb
為什麼名字不是
因為這個控制代碼已經在 NPM 上被佔用了。
它似乎被 ohmree
佔用,但該包似乎不活躍。
如果有人認識他,我很樂意與他取得聯絡!
貢獻
此整合仍有許多很棒的功能待構建。
我很樂意接收和審查任何拉取請求。
開發
# Install dependencies
npm install
# Generate type stubs
npm run dev:prepare
# Develop with the playground
npm run dev
# Build the playground
npm run dev:build
# Run ESLint
npm run lint
# Run Vitest
npm run test
npm run test:watch
# Release new version
npm run release