首页 / 文章 / Next.js、Tailwind 与 Prisma,结合 Docker 和 PostgreSQL 使用

Next.js、Tailwind 与 Prisma,结合 Docker 和 PostgreSQL 使用

逐步操作:创建一个 Next.js TypeScript 应用,在 Docker 中运行 Postgres,配置 Prisma migrate 及数据初始化,然后从服务器组件中查询用户信息。

1108 词

前置条件

在开始操作之前,请先安装以下工具:

  • Docker(用于本地 Postgres 容器)
  • Node.js(建议使用 v16+ 版本)
  • npm(随 Node 一同提供)

1) 创建 Next.js 项目

使用官方初始化工具并回答提示问题。本教程建议使用 App Router 和 TypeScript。

npx create-next-app@latest notes-taking
# choose your options in the interactive prompt (App Router, TypeScript recommended)
cd note-taking

若想从第一个命令就开始使用 TypeScript:

npx create-next-app@latest note-taking — ts

2) 添加 Tailwind CSS(Next.js 已内置)

最新的 create-next-app 模板在交互式选项中启用 Tailwind 后会自动集成该框架,因此对于已选择该功能的新建项目无需单独安装 Tailwind。

3) 使用 Docker(在本地)运行 Postgres

在容器中启动 Postgres:

docker run — name notes-postgres -e POSTGRES_PASSWORD=password -e POSTGRES_DB=notes_app -p 5432:5432 -d postgres:latest

各参数的含义:

  • docker run — 创建并启动容器
  • --name notes-postgres — 为后续命令提供稳定的名称
  • -e POSTGRES_PASSWORD=... / -e POSTGRES_DB=... — 设置启动凭据及数据库信息
  • -p 5432:5432 — 将端口映射到主机上
  • -d postgres:latest — 以分离模式使用 Postgres 镜像

确认容器正在运行:

docker ps

按镜像过滤:

docker ps — filter “ancestor=postgres”

列出所有容器,包括已停止的:

docker ps -a

按容器名称过滤:

docker ps — filter “name=notes-postgres”

4) 安装 Prisma 及相关包

在 Next.js 项目根目录下:

npm install prisma tsx — save-dev
npm install @prisma/extension-accelerate @prisma/client

初始化 Prisma,并在 app 文件夹下生成客户端代码,以便 App Router 的导入操作仍在本地完成:

npx prisma init — db — output ../app/generated/prisma

这样就会生成一个包含schema.prisma文件的prisma/目录,一个包含DATABASE_URL值的.env文件,以及(使用--output参数时)在app/generated/prisma下生成的客户端代码。

更希望使用默认的客户端存放位置?那就无需指定自定义输出路径直接进行初始化:

npx prisma init — db and remove — output.

5) 配置.env文件(DATABASE_URL)

将DATABASE_URL设置为Docker中的Postgres实例地址:

DATABASE_URL=”postgresql://postgres:password@localhost:5432/notes_app?schema=public”

如果选择了不同的密码和数据库名称,则需相应修改这些值。

6) 编辑prisma/schema.prisma文件

需使用与后续种子脚本相匹配的User/Post模型对:

generator client {
provider = "prisma-client-js"
output = "../app/generated/prisma"
}

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

model User {
id Int @id @default(autoincrement())
name String
email String @unique
posts Post[]
}

model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
authorId Int
author User @relation(fields: [authorId], references: [id])
}

当模型内容正确无误后保存该文件。

7) 运行迁移操作(创建表结构)

执行第一个迁移命令以创建数据库表:

npx prisma migrate dev — name init

Prisma会在prisma/migrations目录下生成用于该变更的SQL语句。

8) 初始化数据库

初始化操作会插入示例数据,这样Prisma Studio和应用程序就能立即拥有数据。

创建prisma/seed.ts文件(如果客户端输出路径不同,请调整导入语句):

// prisma/seed.ts
import { PrismaClient, Prisma } from "../app/generated/prisma";

const prisma = new PrismaClient();

const userData: Prisma.UserCreateInput[] = [
  {
    name: "Alice",
    email: "alice@prisma.io",
    posts: {
      create: [
        {
          title: "Join the Prisma Discord",
          content: "https://pris.ly/discord",
          published: true,
        },
        {
          title: "Prisma on YouTube",
          content: "https://pris.ly/youtube",
        },
      ],
    },
  },
  {
    name: "Bob",
    email: "bob@prisma.io",
    posts: {
      create: [
        {
          title: "Follow Prisma on Twitter",
          content: "https://www.twitter.com/prisma",
          published: true,
        },
      ],
    },
  },
];

export async function main() {
  for (const u of userData) {
    await prisma.user.create({ data: u });
  }
}

main();ty

在package.json中注册该初始化脚本:

"prisma": {
"seed": "tsx prisma/seed.ts"
}

运行该脚本:

npx prisma db seed

这样就会插入Alice、Bob以及他们的帖子。

9) 打开Prisma Studio

可以直观地查看和编辑数据行:

npx prisma studio

浏览器界面会列出模型和记录。

10) 创建Prisma客户端封装文件(lib/prisma.ts)

通过使用全局单例以及accelerate扩展,可以避免在开发过程中创建过多的PrismaClient实例。请创建lib/prisma.ts文件:

// lib/prisma.ts
import { PrismaClient } from "../app/generated/prisma"; // adjust path if needed
import { withAccelerate } from "@prisma/extension-accelerate";

declare global {
// allow global prisma across module reloads in dev
// eslint-disable-next-line no-var
var prisma: PrismaClient | undefined;
}

const prisma =
global.prisma ?? new PrismaClient().$extends(withAccelerate());
if (process.env.NODE_ENV !== "production") global.prisma = prisma;

export default prisma;

将导入路径设置为您生成的客户端路径,如果您省略了--output选项,则使用@prisma/client。

11) 从 Next.js(服务器组件)测试数据库连接

一个在服务器端加载用户的示例app/page.tsx:

import prisma from '@/lib/db'

export default async function Home() {
  const users = await prisma.user.findMany();
  return (
    <div className="min-h-screen bg-gray-50 flex flex-col items-center justify-center -mt-16">
      <h1 className="text-4xl font-bold mb-8 font-[family-name:var(--font-geist-sans)] text-[#333333]">
        Superblog
      </h1>
      <ol className="list-decimal list-inside font-[family-name:var(--font-geist-sans)]">
        {users.map((user) => (
          <li key={user.id} className="mb-2">
            {user.name}
          </li>
        ))}
      </ol>
    </div>
  );
}

启动 Next.js 开发服务器:

npm run dev

打开 http://localhost:3000,确认已生成的测试用户能够正确显示。

完整命令清单

创建项目

npx create-next-app@latest my-app
cd my-app

使用 PostgreSQL Docker

docker run — name notes-postgres -e POSTGRES_PASSWORD=password -e POSTGRES_DB=notes_app -p 5432:5432 -d postgres:latest

执行 docker ps 命令

docker exec -it notes-postgres psql -U postgres

使用 Prisma 工具

npm install prisma tsx — save-dev
npm install @prisma/extension-accelerate @prisma/client
npx prisma init — db — output ../app/generated/prisma

编辑 prisma/schema.prisma 文件

npx prisma migrate dev — name init

创建 prisma/seed.ts 文件

在 package.json 中添加 prisma.seed 条目

npx prisma db seed
npx prisma studio
npm run dev

故障排除与技巧

  • 无法连接到 Postgres:使用 docker ps 确认容器状态,然后检查 DATABASE_URL 中的主机地址和端口。可从主机或其他客户端使用 psql 命令连接该地址。
  • 迁移失败:查看 prisma/migrations 目录下生成的 SQL 文件,确保数据库名称与 .env 文件中的配置一致。
  • 客户端导入错误:修改 output 设置后需重新生成代码,若使用默认路径则应将导入方式改为 @prisma/client。
  • 界面为空:在调试页面组件之前,先重新运行数据初始化脚本,并确认 Prisma Studio 中显示了 Alice/Bob 的信息。