【Node.js】Node全栈NestJS和NextJS从环境搭建到MongoDB数据库连接与CRUD操作

Nest (NestJS) 是一个用于构建高效、可扩展的 Node.js 服务器端应用的框架。它使用渐进式 JavaScript,构建并完全支持 TypeScript(但仍然允许开发者使用纯 JavaScript 进行编码)并结合了 OOP(面向对象编程)、FP(函数式编程)和 FRP(函数式反应式编程)的元素。
在幕后,Nest 使用强大的 HTTP 服务器框架,如 Express(默认),也可以选择配置为使用 Fastify!
Nest 在这些常见的 Node.js 框架(Express/Fastify)之上提供了一个抽象级别,但也直接向开发者公开了它们的 API。这使开发者可以自由使用可用于底层平台的无数第三方模块

最近开发完一个小项目,使用了NestJS和NextJS。目前Web3 项目(超 40% 的区块链节点服务采用)在国外(尤其是欧美地区)对 NestJS 的采用率较高,记录一下使用NestJS与MongoDB进行集成,并实现简单的CRUD操作。

技术栈如下:

前端后端数据库
React 19 + Next.js 15Node.js 22 + NestJS 10MongoDB 7.0

首先安装nvm 

nvm(Node Version Manager) 是一个用于管理 Node.js 版本的命令行工具。它允许开发者在同一台机器上安装和切换多个版本的 Node.js,以便于在不同的项目中使用不同的 Node.js 版本。

怎么安装我就不写了,直接给您推荐一个csdn链接

NVM介绍、安装、使用教程-CSDN博客

然后安装node.js 22

nvm install 22.15.0

查看现有的node.js版本

nvm list 

选择使用刚刚的node.js22.15.0版本

nvm use 22.15.0

一、后端环境准备与项目搭建


1.1 安装NestJS CLI


NestJS CLI是官方提供的命令行工具,快速创建和管理NestJS项目。确保开发环境已经安装了Node.js(推荐v16或更高版本),然后全局安装NestJS CLI:

npm i -g @nestjs/cli


1.2 创建新项目
进入项目目录中,再使用命令创建项目。使用CLI创建新项目:

D:\Code\WEB3\nest
nest new my-nestjs-app
cd my-nestjs-app

选择包管理器(npm/yarn/pnpm)后,CLI会自动创建项目结构并安装依赖。

1.3 安装MongoDB相关依赖

安装NestJS的MongoDB模块和Mongoose:

npm install @nestjs/mongoose mongoose

二、配置MongoDB连接

安装mongodb

如果你虚拟机的linux安装了 Docker,可以用这个命令直接拉取并运行 MongoDB 容器:

docker run -d -p 27017:27017 --name mongo-dev mongo:7

可能会遇到docker镜像拉不了情况,应该是被墙了。

方案一:无法拉取镜像解决办法,配置 Docker 国内镜像加速器(推荐)

  1. 创建或编辑配置文件:

 

sudo mkdir -p /etc/docker

touch daemon.json

vim /etc/docker/daemon.json

写入如下内容。

{
 "registry-mirrors": ["https://docker.registry.cyou",
"https://docker-cf.registry.cyou",
"https://dockercf.jsdelivr.fyi",
"https://docker.jsdelivr.fyi",
"https://dockertest.jsdelivr.fyi",
"https://mirror.aliyuncs.com",
"https://dockerproxy.com",
"https://mirror.baidubce.com",
"https://docker.m.daocloud.io",
"https://docker.nju.edu.cn",
"https://docker.mirrors.sjtug.sjtu.edu.cn",
"https://docker.mirrors.ustc.edu.cn",
"https://mirror.iscas.ac.cn",
"https://docker.rainbond.cc"]
}

  1. 重启 Docker 服务:

sudo systemctl daemon-reexec sudo systemctl restart docker

  1. 然后重新运行:

docker run -d -p 27017:27017 --name mongo-dev mongo:7

用数据库连接软件连接数据库,这里连接不需要账号密码。连接成功创建一个数据库nestjs-mongodb

2.1 配置MongoDB连接

在app.module.ts中配置MongoDB连接,这里的ip要写你提供数据库服务的ip:

import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { UsersModule } from './users/users.module';

@Module({
  imports: [
    MongooseModule.forRoot('mongodb://192.168.32.135:27017/nestjs-mongodb'),
    UsersModule,
  ],
})
export class AppModule {}

三、创建用户模块

3.1 创建用户模块

使用CLI创建一个新的模块:

nest g module users

3.2 创建用户Schema

在users目录下创建一个新的Schema文件user.schema.ts:

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type UserDocument = User & Document;

@Schema()
export class User {
  @Prop({ required: true })
  name: string;

  @Prop({ required: true })
  email: string;

  @Prop({ default: Date.now })
  createdAt: Date;
}

export const UserSchema = SchemaFactory.createForClass(User);

3.3 注册Schema到模块

在users.module.ts中注册Schema:

import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { User, UserSchema } from './schemas/user.schema';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

@Module({
  imports: [MongooseModule.forFeature([{ name: User.name, schema: UserSchema }])],
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}

四、实现CRUD操作

关于SQL语句

如果你用的是 MongoDB,不需要 SQL 建表:

MongoDB 是非关系型数据库,不需要手动建表,插入数据时自动创建集合。

4.1 创建用户服务

在users.service.ts中实现CRUD逻辑:

import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User, UserDocument } from './schemas/user.schema';

@Injectable()
export class UsersService {
  constructor(@InjectModel(User.name) private readonly userModel: Model<UserDocument>) {}

  async findAll(): Promise<User[]> {
    return this.userModel.find().exec();
  }

  async findOne(id: string): Promise<User> {
    const user = await this.userModel.findById(id).exec();
    if (!user) {
      throw new NotFoundException('User not found');
    }
    return user;
  }

  async create(user: Partial<User>): Promise<User> {
    const newUser = new this.userModel(user);
    return newUser.save();
  }

  async update(id: string, user: Partial<User>): Promise<User> {
    const updatedUser = await this.userModel.findByIdAndUpdate(id, user, { new: true }).exec();
    if (!updatedUser) {
      throw new NotFoundException('User not found');
    }
    return updatedUser;
  }

  async delete(id: string): Promise<void> {
    const result = await this.userModel.findByIdAndDelete(id).exec();
    if (!result) {
      throw new NotFoundException('User not found');
    }
  }
}

4.2 创建用户控制器

在users.controller.ts中定义路由:

import { Controller, Get, Post, Put, Delete, Body, Param } from '@nestjs/common';
import { UsersService } from './users.service';
import { User } from './schemas/user.schema';

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Get()
  async findAll(): Promise<User[]> {
    return this.usersService.findAll();
  }

  @Get(':id')
  async findOne(@Param('id') id: string): Promise<User> {
    return this.usersService.findOne(id);
  }

  @Post()
  async create(@Body() user: Partial<User>): Promise<User> {
    return this.usersService.create(user);
  }

  @Put(':id')
  async update(@Param('id') id: string, @Body() user: Partial<User>): Promise<User> {
    return this.usersService.update(id, user);
  }

  @Delete(':id')
  async delete(@Param('id') id: string): Promise<void> {
    return this.usersService.delete(id);
  }
}

五、运行和测试

5.1 启动应用

运行应用:

npm run start:dev

5.1.1vscode第一次启动项目可能会报错。

1.在Vscode报错是这样显示的
npm : 无法加载文件 D:\ProgramFiles\nodejs\npm.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?Link
ID=135170 中的 about_Execution_Policies。
所在位置 行:1 字符: 1
+ npm i
+ ~~~
    + CategoryInfo          : SecurityError: (:) [],PSSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess
2.原因
        Windows 系统的执行策略禁止运行脚本所导致的。执行策略是 Windows PowerShell 的安全机制,它决定了能否加载配置文件或运行脚本。

3.解决方法
        1.在Vscode终端输入 查看执行策略/权限;
get-ExecutionPolicy
                结果是Restricted(受限制的),说明会会禁止所有脚本的运行
        2.终端输入Set-ExecutionPolicy -Scope CurrentUser命令给用户赋予权限;
Set-ExecutionPolicy -Scope CurrentUser

               我们一般用的都是 RemoteSigned;所以值就写这个
        3.最后终端输入get-ExecutionPolicy查看一下权限,显示RemoteSigned就ok


4.扩展
        在 Windows PowerShell 里,ExecutionPolicy 有多种可选的值,每种值都代表着不同的脚本执行限制级别,以下为你详细介绍:

Restricted:这是默认策略,它会禁止所有脚本的运行。即使是本地创建的脚本也无法执行。
AllSigned:只有经过数字签名的脚本才能运行,不管这些脚本是本地的还是从网络下载的。
RemoteSigned:本地脚本无需数字签名就能运行,但从网络下载的脚本必须要有数字签名才行。
Unrestricted:允许所有脚本运行,不过从网络下载的脚本在运行前会给出安全提示。
Bypass:不做任何限制,所有脚本都能直接运行,不会给出安全提示。
Undefined:意味着没有为当前范围设置执行策略,它会继承父范围的策略。

5.2 测试API


使用Postman或curl测试API:

GET /users:获取所有用户。
GET /users/:id:获取单个用户。
POST /users:创建新用户。
PUT /users/:id:更新用户信息。
DELETE /users/:id:删除用户。

使用 Postman 调试(推荐)

示例 1:创建用户

  • 方法:POST

  • URL:http://localhost:3000/users

  • Body → rawJSON

{ "name": "Tom", "email": "tom@example.com" }


示例 2:获取所有用户

  • 方法:GET

  • URL:http://localhost:3000/users


示例 3:根据 ID 查询用户

  • 方法:GET

  • URL:http://localhost:3000/users/<用户ID>


示例 4:更新用户

  • 方法:PUT

  • URL:http://localhost:3000/users/<用户ID>

  • Body → JSON:

{ "name": "Updated Tom", "email": "tom@update.com" }


示例 5:删除用户

  • 方法:DELETE

  • URL:http://localhost:3000/users/<用户ID>


六、后端总结


介绍了NestJS的核心概念和基础用法,包括模块、控制器、服务和依赖注入等。还包括了如何使用MongoDB连接NestJS,并实现了简单的CRUD操作,构建高效、可扩展的后端应用。

前端为什么选择Next.js?


如果你正在学习前端开发,一定听过React的大名。但React只是一个库,要搭建完整的应用,你还需要路由、数据获取、SEO优化等能力——这时候Next.js就登场了!作为React的“超集框架”,Next.js提供了:

🚀 开箱即用的服务端渲染(SSR)和静态生成(SSG)
🔗 零配置路由系统
🔧 API路由支持全栈开发
📦 自动代码分割与优化
🌍 无缝部署到Vercel等平台
无论你是想开发博客、电商网站,还是企业级应用,Next.js都能让开发效率翻倍。下面我们从零开始,手把手带你掌握Next.js核心技能!

一、前端环境搭建与项目创建


1. 创建Next项目

Next.js 不需要 CLI 安装,它推荐用 npx 一次性创建项目
进入项目目录中,再使用命令创建项目

cd D:\Code\WEB3\next
npx create-next-app@latest my-next-app
cd my-next-app

创建后会有提示,一直按回车就行。

前言:在NextJS前端框架中。什么是服务端代码?什么是客户端代码?使用前端代理解决跨域访问后的请求url区别。
0.1变量配置

0.2前端代理配置(解决前端的客户端代码跨域访问问题)

 项目根目录的next.config.ts里,写入如下的内容设置前端代理解决跨域问题。

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  /* config options here */
  reactStrictMode: true,
  async rewrites() {
    return [
      {
        source: '/api/:path*',
        destination: 'http://localhost:3000/:path*', // 后端服务地址
      },
    ];
  },
};

export default nextConfig;

以上配置会让请求 url代理成如下内容

关于跨域访问客户端代码

请求url写代理的url路径。/api/users/${id}

/api/替换成后端你的ip和端口http://localhost:3000/

例如:/api/users/${id}会被替换成http://localhost:3000/users/${id}

async function fetchUser() {
      const res = await fetch(`/api/users/${id}`);
      const data = await res.json();
      setUser(data);
    }
关于跨域访问服务端代码

Next前端的服务端代码不受跨域访问影响,请求url直接写真实后端地址。

1. 服务端代码

不受跨域请求访问的影响,直接写真实的后端请求url。

  • 运行环境:Node.js(服务端)。
  • 特性
    • 服务端代码在 Next.js 的服务端渲染阶段运行。
    • 例如,getServerSidePropsgetStaticPropsAPI 路由 和直接在服务端运行的 fetch 请求。
  • 典型场景
    • 数据预取(如 getServerSideProps)。
    • 静态生成(如 getStaticProps)。
    • API 路由(如 pages/api 下的代码)。
  • 如何识别
    • 如果代码在 getServerSidePropsgetStaticProps 或 API 路由中运行,则它是服务端代码。
    • 服务端代码需要完整的绝对 URL(如 http://localhost:3001/api/users),因为它无法解析相对路径。
2.1前端 服务端代码 不受跨域请求访问问题,浏览器请求url分析

前端的 服务端代码 不受跨域请求访问问题,请求url要写真实的后端接口地址

http://localhost:3000/users

NEXT_PUBLIC_API_BASE_URL=http://localhost:3000

async function getUsers(): Promise<User[]> {

    const res = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/users`, { cache: 'no-store' });

    if (!res.ok) throw new Error('Failed to fetch users');

    return res.json();

  }

其他人看不到后端的真实的ip和端口。只显示前端的ip和端口。


2. 客户端代码

受到跨域访问请求的影响。如果受到跨域影响要通过前端代理url来访问后端接口。

  • 运行环境:浏览器(客户端)。
  • 特性
    • 客户端代码在用户的浏览器中运行。
    • 例如,React 组件中的 useEffect、事件处理程序(如 onClick)。
  • 典型场景
    • 用户交互(如按钮点击、表单提交)。
    • 动态数据加载(如 useEffect 中的 fetch 请求)。
  • 如何识别
    • 如果代码在 React 组件中运行,并且依赖于浏览器环境(如 DOM 操作、window 对象),则它是客户端代码。
    • 客户端代码可以使用相对路径(如 /api/users),因为浏览器会自动解析为完整的 URL。
 2.1前端 客户端代码 代理解决跨域问题后,浏览器请求url分析

其他人看不到后端的真实的ip和端口。只显示前端的ip和端口。

请求url写代理的url路径。/api/users/${id}

/api/替换成后端你的ip和端口http://localhost:3000/

例如:/api/users/${id}会被替换成http://localhost:3000/users/${id}

useEffect(() => {
    if (!id) return;

    async function fetchUser() {
      const res = await fetch(`/api/users/${id}`);
      const data = await res.json();
      setUser(data);
    }
    fetchUser();
  }, [id]);

结合我的代码分析

1. 服务端代码

以下是典型的服务端代码场景:

// 服务端代码示例

async function getUsers(): Promise<User[]> {

  const res = await fetch('http://localhost:3000/users'); // 需要后端api的绝对路径

  if (!res.ok) throw new Error('Failed to fetch users');

  return res.json();

}

  • 运行环境:Node.js。
  • 原因fetch 在服务端运行时无法解析相对路径 /api/users,需要完整的绝对 URL。

2. 客户端代码

以下是典型的客户端代码场景:

useEffect(() => {

  async function fetchUser() {

    const res = await fetch(`/api/users/${id}`); // 可以使用相对路径

    const data = await res.json();

    setUser(data);

  }

  fetchUser();

}, [id]);

  • 运行环境:浏览器。
  • 原因useEffect 是 React 的 Hook,只会在客户端运行。浏览器会自动将相对路径 /api/users/${id} 解析为完整的 URL(如 http://localhost:3000/api/users/${id})。

您的项目结构分析

1. 前端项目(Next.js)

  • 运行端口:假设是 3001。
  • 代码类型
    • pages 文件夹中的代码可能包含服务端和客户端代码。
    • useEffect 和事件处理程序运行在客户端。
    • getServerSideProps 和 getStaticProps 运行在服务端。

2. 后端项目(Nest.js)

  • 运行端口:3000。
  • 职责:提供 API 服务,供前端通过 fetch 或其他 HTTP 客户端调用。

1.1修改前端端口号

修改前端的端口号为3001,避免和后端的3000端口冲突。两者默认端口号都是3000.

1.2启动前端项目

常规方式启动,执行下面两行命令。

npm install
npm run dev

访问http://localhost:3001,看到欢迎页面即成功!

二、核心概念与项目结构

1. 项目目录解析

my-next-app/
├── app/          # 页面和布局(App Router模式)
├── pages/        # 页面路由(传统模式)
├── public/       # 静态资源(图片、字体)
├── styles/       # CSS文件
├── components/   # 可复用组件
└── package.json  # 依赖管理

 注意:Next.js 13+推荐使用app目录(App Router),但传统pages目录依然兼容,本文以app目录为例。

三、文件系统路由:零配置实现页面跳转

1. 创建页面

app目录下新建文件夹,文件夹名即路由路径。例如:

文件路径 ->前端请求地址

  • app/user/page.tsx → /user
  • app/user/[id]/page.tsx → /user/123
  • app/user/create/page.tsx → /user/create/123
  • app/user/edit/page.tsx → /user/edit/123

2. 用户列表页

http://localhost:3001/users

// app/users/page.tsx

interface User {
    _id: string;
    name: string;
    email: string;
    createdAt: string;
  }
  
  async function getUsers(): Promise<User[]> {
    const res = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/users`, { cache: 'no-store' });
    if (!res.ok) throw new Error('Failed to fetch users');
    return res.json();
  }
  
  export default async function UsersPage() {
    const users = await getUsers();
  
    return (
      <div>
        <h1>用户列表</h1>
        <ul>
          {users.map((user) => (
            <li key={user._id}>
              <a href={`/users/${user._id}`}>{user.name} - {user.email}</a>
            </li>
          ))}
        </ul>
        <a href="/users/create">➕ 添加用户</a>
      </div>
    );
  }
  

3. 用户详情页(动态路由)

http://localhost:3001/users/681e33cbb8bdeb06f9f3c99e

使用方括号[param]定义动态参数:

// app/users/[id]/page.tsx
'use client';

import { useRouter } from 'next/navigation';
import { useEffect, useState } from 'react';

interface User {
  _id: string;
  name: string;
  email: string;
  createdAt: string;
}

interface Props {
  params: Promise<{ id: string }>; // 将 params 定义为 Promise
}

export default function UserDetailPage({ params }: Props) {
  const [user, setUser] = useState<User | null>(null);
  const [id, setId] = useState<string | null>(null);
  const router = useRouter();

  useEffect(() => {
    // 异步解包 params
    async function resolveParams() {
      const resolvedParams = await params; // 解包 Promise
      setId(resolvedParams.id);
    }
    resolveParams();
  }, [params]);

  useEffect(() => {
    if (!id) return;

    async function fetchUser() {
      const res = await fetch(`/api/users/${id}`);
      const data = await res.json();
      setUser(data);
    }
    fetchUser();
  }, [id]);

  const handleDelete = async () => {
    const confirmed = confirm('确定要删除这个用户吗?');
    if (!confirmed) return;

    await fetch(`/api/users/${id}`, {
      method: 'DELETE',
    });
    router.push('/users');
  };

  if (!user) return <p>加载中...</p>;

  return (
    <div>
      <h1>{user.name}</h1>
      <p>邮箱:{user.email}</p>
      <p>注册时间:{new Date(user.createdAt).toLocaleString()}</p>
      <a href={`/users/${user._id}/edit`}>✏️ 编辑</a>
      <button onClick={handleDelete} style={{ marginLeft: '1rem', color: 'red' }}>
        🗑 删除
      </button>
      <br />
      <a href="/users">返回列表</a>
    </div>
  );
}

访问/users/42将显示“博客ID: 42”。

 4. 创建用户页

http://localhost:3001/users/create

// app/users/create/page.tsx
'use client';

import { useState, FormEvent } from 'react';
import { useRouter } from 'next/navigation';

export default function CreateUserPage() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const router = useRouter();

  const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
    e.preventDefault();

    const res = await fetch('/api/users', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name, email }),
    });

    if (res.ok) {
      router.push('/users');
    } else {
      alert('提交失败');
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <h1>添加用户</h1>
      <input
        placeholder="姓名"
        value={name}
        onChange={(e) => setName(e.target.value)}
        required
      />
      <input
        placeholder="邮箱"
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        required
      />
      <button type="submit">提交</button>
    </form>
  );
}

 5. 编辑用户页面

http://localhost:3001/users/edit

// app/users/edit/page.tsx
'use client';

import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';

interface User {
  _id: string;
  name: string;
  email: string;
}

interface Props {
  params: { id: string };
}

export default function EditUserPage({ params }: Props) {
  const [user, setUser] = useState<User | null>(null);
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const router = useRouter();

  useEffect(() => {
    async function fetchUser() {
      const res = await fetch(`/api/users/${params.id}`);
      const data = await res.json();
      setUser(data);
      setName(data.name);
      setEmail(data.email);
    }
    fetchUser();
  }, [params.id]);

  const handleUpdate = async (e: React.FormEvent) => {
    e.preventDefault();
    await fetch(`/api/users/${params.id}`, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name, email }),
    });
    router.push('/users');
  };

  if (!user) return <p>加载中...</p>;

  return (
    <form onSubmit={handleUpdate}>
      <h1>编辑用户</h1>
      <input value={name} onChange={(e) => setName(e.target.value)} required />
      <input value={email} onChange={(e) => setEmail(e.target.value)} required />
      <button type="submit">更新</button>
    </form>
  );
}

 6. 删除功能(在用户详情页添加删除按钮)

前面用户详情页代码直接替换成下面这个代码就行。多了删除按钮功能

// app/users/[id]/page.tsx
'use client';

import { useRouter } from 'next/navigation';
import { useEffect, useState } from 'react';

interface User {
  _id: string;
  name: string;
  email: string;
  createdAt: string;
}

interface Props {
  params: Promise<{ id: string }>; // 将 params 定义为 Promise
}

export default function UserDetailPage({ params }: Props) {
  const [user, setUser] = useState<User | null>(null);
  const [id, setId] = useState<string | null>(null);
  const router = useRouter();

  useEffect(() => {
    // 异步解包 params
    async function resolveParams() {
      const resolvedParams = await params; // 解包 Promise
      setId(resolvedParams.id);
    }
    resolveParams();
  }, [params]);

  useEffect(() => {
    if (!id) return;

    async function fetchUser() {
      const res = await fetch(`/api/users/${id}`);
      const data = await res.json();
      setUser(data);
    }
    fetchUser();
  }, [id]);

  const handleDelete = async () => {
    const confirmed = confirm('确定要删除这个用户吗?');
    if (!confirmed) return;

    await fetch(`/api/users/${id}`, {
      method: 'DELETE',
    });
    router.push('/users');
  };

  if (!user) return <p>加载中...</p>;

  return (
    <div>
      <h1>{user.name}</h1>
      <p>邮箱:{user.email}</p>
      <p>注册时间:{new Date(user.createdAt).toLocaleString()}</p>
      <a href={`/users/${user._id}/edit`}>✏️ 编辑</a>
      <button onClick={handleDelete} style={{ marginLeft: '1rem', color: 'red' }}>
        🗑 删除
      </button>
      <br />
      <a href="/users">返回列表</a>
    </div>
  );
}


四、API路由:快速搭建Next前端框架的后端接口

Next前端框架支持创建后端api提供访问 响应数据。

app/frontApi/hello目录下创建API端点:

// app/frontApi/hello/route.tsx
export async function GET() {
  return Response.json({ message: 'Hello Next.js!' });
}

访问http://localhost:3001/frontApi/hello

请求方式GET

将返回JSON数据:

{ "message": "Hello Next.js!" }

五、使用Monorepo管理前后端项目,使它们放在一起

要将你的两个已有项目 my-next-app(Next.js)和 my-nestjs-app(NestJS)统一为一个 monorepo,推荐使用 TurboRepoNx。这里以 TurboRepo 为例,它对前后端组合项目支持非常好。


✅ 步骤概览(TurboRepo 方案)

1. 创建一个新的根目录作为 monorepo 根

你可以直接在 D:\Code\WEB3\first 作为 monorepo 根目录使用。

D:\Code\WEB3\first\
├── turbo.json           👈 TurboRepo 配置
├── package.json         👈 顶层依赖管理
├── apps\
│   ├── my-next-app\     👈 原来的前端
│   └── my-nestjs-app\   👈 原来的后端
└── node_modules\

2. 安装 TurboRepo

进入根目录并初始化:

cd D:\Code\WEB3\first
npm init -y
npm install turbo --save-dev

创建 turbo.json 文件:

{
  "pipeline": {
    "dev": {
      "cache": false,
      "dependsOn": ["^dev"]
    },
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "dist/**"]
    },
    "lint": {},
    "test": {}
  }
}

3. 移动项目到 apps/ 目录下

将已有项目放入 apps/ 文件夹:

mkdir apps
mv next/my-next-app apps/my-next-app
mv nest/my-nestjs-app apps/my-nestjs-app

Windows 用户可手动拖动到 apps/ 中,或使用 Git Bash/PowerShell。


4. 修改两个项目的 package.json

apps/my-next-app/package.json 示例:
{
  "name": "my-next-app",
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "next": "^13.x",
    "react": "^18.x",
    "react-dom": "^18.x"
  }
}
apps/my-nestjs-app/package.json 示例:
{
  "name": "my-nestjs-app",
  "scripts": {
    "dev": "nest start --watch",
    "build": "nest build",
    "start": "node dist/main.js"
  },
  "dependencies": {
    "@nestjs/core": "^9.x",
    "reflect-metadata": "^0.1.13"
  }
}

5. 顶层运行方式

D:\Code\WEB3\first 执行:

npx turbo run dev

Turbo 会自动并行运行:

  • apps/my-next-appnpm run dev

  • apps/my-nestjs-appnpm run dev


6. 可选:统一依赖到顶层(如 React、TypeScript 等)

你可以把一些公共依赖移到根的 package.json,使用 workspace 管理:

顶层 package.json 示例:
{
  "name": "web3-monorepo",
  "private": true,
  "workspaces": ["apps/*"],
  "scripts": {
    "dev": "turbo run dev",
    "build": "turbo run build"
  },
  "devDependencies": {
    "turbo": "^1.10.0"
  }
}

✅ 最终结构如下:

D:\Code\WEB3\first\
├── turbo.json
├── package.json
├── apps\
│   ├── my-next-app\
│   │   └── package.json
│   └── my-nestjs-app\
│       └── package.json
└── node_modules\

需要我用 Nx 或其他 monorepo 工具也写一份方案对比吗?需要就在评论区留言!

六、部署到Vercel

  1. 将代码推送到GitHub仓库
  2. 登录Vercel官网,导入仓库
  3. 自动检测Next.js项目,点击部署
  4. 等待1分钟,获得生产环境链接!

七、进阶学习方向

  • 🖼 图片优化:使用next/image组件自动优化图片
  • 🔒 中间件:实现身份验证、重定向等逻辑
  • 🌐 国际化:支持多语言切换
  • 📱 PWA支持:添加离线访问能力

前端总结

通过本文,你已经掌握了Next.js的核心功能:文件路由、数据获取、API开发和部署。Next.js极大地简化了全栈开发流程,让你能更专注于业务逻辑。现在,尝试用Next.js动手搭建你的第一个项目吧!

前端延伸资源

前端动手练习

  1. 创建一个包含首页、关于页和个人作品集的网站
  2. 使用SSG生成静态页面
  3. 添加一个联系表单的API端点
  4. 部署到Vercel并分享给你的朋友!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

穗余

家庭条件困难,望有打赏援助生活

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值