搭建一个 nuxt 项目并使用 cloudflare 的 D1 数据库
解决网络问题
pnpm create nuxt@latest
这个是搭建 nuxt 项目的命令,如果没有独特的网络环境的话,大概率会报错
[ nuxi 09:38:27] ERROR Error: Failed to download template from registry: Failed to download https://raw.githubusercontent.com/nuxt/starter/templates/templates/v3.json: TypeError: fetch failed
有两种解决办法,一种是修改 hosts,另一种是直接从 GitHub 下载模板
修改 hosts
如果是 windows 电脑的话,打开C:\Windows\System32\drivers\etc
,里面有个 hosts,以管理员身份用记事本打开,在里面加上
199.232.28.133 raw.githubusercontent.com
199.232.28.133:443 raw.githubusercontent.com
再次运行pnpm create nuxt@latest
,如果顺利的话那应该可以成功搭建。
直接从 GitHub 克隆
如果不顺利的话就只能这样做了。
打开nuxt 模板仓库,选择自己想要的分支,一般是 v3 分支,然后下载 zip 就可以了。解压后跟使用命令行搭建差不多。
也可以使用 git 来克隆,不过需要手动删除.git
git clone -b v3 git@github.com:nuxt/starter.git target
-b 后面那个 v3 是分支名,target 是你的项目名,不写也行。输入上面这条命令那就会创建 target 文件夹并把对应分支克隆到 target 文件夹里。记得删掉.git 文件
使用 cloudflare
连接 cloudflare 账号
需要先安装wrangler
,在项目中运行
pnpm add -D wrangler
然后登录一下
pnpx wrangler login
这样就连接到你的 cloudflare 账号了。
新建 D1 数据库
运行
pnpx wrangler d1 create 数据库名
这会新建一个 d1 数据库,如果你已经有了的话也可以不新建,使用
pnpx wrangler d1 list
来查看已经建立的 d1 数据库。
新建数据库之后应该会得到关于这个数据库的一些信息,大概像这样
{
"d1_databases": [
{
"binding": "DB",
"database_name": "lll",
"database_id": "13b4b003-373f-4265-9340-10374195d77c"
}
]
}
在项目根目录新建一个 wrangler.jsonc 文件,把上面这个东西复制进去。如果你得到的是 toml,可以新建一个 wrangler.toml,然后复制进去;或者改成 json 也行。
如果你已经有一个数据库了,使用pnpx wrangler d1 list
获取数据库信息,里面有 uuid, name,跟上面一样写就可以了。
在 nuxt 中使用 D1 数据库
在 nuxt 里结合 cloudflare 开发需要一个插件。在 nuxt.config.ts 里的 modules 加上'nitro-cloudflare-dev'
,你的 nuxt.config.ts 应该跟这个类似
export default defineNuxtConfig({
modules: ['nitro-cloudflare-dev'],
compatibilityDate: '2024-11-01',
devtools: { enabled: true },
});
然后执行
pnpm add -D nitro-cloudflare-dev
使用 drizzle
drizzle
是一个轻量级的 ORM 库,可以用 ts 来定义数据库表,与多种数据库结合。
pnpm add drizzle-kit drizzle-orm
安装drizzle
,然后在根目录新建drizzle.config.ts
,加上
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
out: './drizzle', // drizzle的输出目录
schema: './server/db/schema', // 根据实际选择,如果把定义数据库的代码放在其它地方了,这里就要改成实际位置
dialect: 'sqlite', // cloudflare D1基于sqlite
});
在 server 中新建 db 文件夹,在 db 文件夹新建 schema 文件夹,新建一个 user.ts
import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { sql } from 'drizzle-orm';
export const usersTable = sqliteTable('users', {
UserId: int().primaryKey({ autoIncrement: true }),
UserName: text().notNull(),
UserEmail: text().notNull().unique(),
UserPassword: text().notNull(),
CreatedAt: text().default(sql`CURRENT_TIMESTAMP`),
});
根据实际需要修改,也可以继续建表。
运行
npx drizzle-kit generate
这里用 pnpx 按理说应该也可以,但是我这里会报错,用 npx 就不会。
这个命令会生成 sql 语句和其他文件到输出目录中,然后运行
在 wrangler.jsonc 里的数据库配置里加上
"migrations_dir" : "drizzle"
大概是这样子
"d1_databases": [
{
"binding": "DB",
"database_name": "name",
"database_id": "id",
"migrations_dir": "drizzle"
}
]
migrations_dir是drizzle的输出目录,告诉cloudflare我们的sql语句在哪里。
运行
pnpx wrangler d1 migrations apply Test --local
Test改成你的数据库名,这样就会本地初始化一个数据库了。会生成一个.wrangler文件夹,里面应该会找到一个.sqlite文件,可以用sqlite查看器查看里面的数据库。
在代码中访问数据库
配置中间件
在server
文件夹中新建文件夹api
用来存放接口,新建hello.ts
。如果要在api接口里访问数据库,通常会使用一个中间件,把db存在上下文中。
在server
文件夹中新建文件夹middleware
,在里面新建d1.ts
import { drizzle, DrizzleD1Database } from 'drizzle-orm/d1';
import { usersTable } from '~/server/db/schema/user';
import { questionsTable } from '../db/schema/question';
import { answersTable } from '~/server/db/schema/answer';
const schema = {
usersTable,
questionsTable,
answersTable,
};
declare module 'h3' {
interface H3EventContext {
db: DrizzleD1Database<typeof schema>;
}
}
let cloudflare: DrizzleD1Database<typeof schema> | undefined;
export default defineEventHandler(async ({ context }) => {
cloudflare = context.cloudflare || cloudflare;
// 这里之所以是 DB 是因为我们在 `wrangler.toml` 里把 binding 设置为了 "DB"
const { DB } = (context.cloudflare || cloudflare).env;
context.db = drizzle(DB, { schema });
});
这样之后就可以在上下文里拿到db了。
访问!
编辑hello.ts
import { usersTable } from '~/server/db/schema/user';
export default defineEventHandler(async (event) => {
try {
const { db } = event.context;
const user = await db
.select({
id: usersTable.UserId,
name: usersTable.UserName,
email: usersTable.UserEmail,
createdAt: usersTable.CreatedAt,
})
.from(usersTable)
.all();
// 这里我如果不加上这个设置响应头就会报错,虽然数据成功返回,
setResponseHeaders(event, {
Connection: 'close',
'Content-Type': 'application/json',
});
return user;
} catch (error) {
console.error('数据库查询错误:', error);
throw createError({
statusCode: 500,
statusMessage: '服务器内部错误',
message: '获取用户数据时发生错误',
});
}
});