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 15 | Node.js 22 + NestJS 10 | MongoDB 7.0 |
首先安装nvm
nvm(Node Version Manager) 是一个用于管理 Node.js 版本的命令行工具。它允许开发者在同一台机器上安装和切换多个版本的 Node.js,以便于在不同的项目中使用不同的 Node.js 版本。
怎么安装我就不写了,直接给您推荐一个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 国内镜像加速器(推荐)
-
创建或编辑配置文件:
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"]
}
-
重启 Docker 服务:
sudo systemctl daemon-reexec sudo systemctl restart docker
-
然后重新运行:
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 →
raw→JSON:
{ "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 的服务端渲染阶段运行。
- 例如,
getServerSideProps、getStaticProps、API 路由和直接在服务端运行的fetch请求。
- 典型场景:
- 数据预取(如
getServerSideProps)。 - 静态生成(如
getStaticProps)。 - API 路由(如
pages/api下的代码)。
- 数据预取(如
- 如何识别:
- 如果代码在
getServerSideProps、getStaticProps或 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)。
- 典型场景:
- 如何识别:
- 如果代码在 React 组件中运行,并且依赖于浏览器环境(如 DOM 操作、
window对象),则它是客户端代码。 - 客户端代码可以使用相对路径(如
/api/users),因为浏览器会自动解析为完整的 URL。
- 如果代码在 React 组件中运行,并且依赖于浏览器环境(如 DOM 操作、
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→/userapp/user/[id]/page.tsx→/user/123app/user/create/page.tsx→/user/create/123app/user/edit/page.tsx→/user/edit/123
2. 用户列表页
// 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,推荐使用 TurboRepo 或 Nx。这里以 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-app的npm run dev -
apps/my-nestjs-app的npm 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
- 将代码推送到GitHub仓库
- 登录Vercel官网,导入仓库
- 自动检测Next.js项目,点击部署
- 等待1分钟,获得生产环境链接!
七、进阶学习方向
- 🖼 图片优化:使用
next/image组件自动优化图片 - 🔒 中间件:实现身份验证、重定向等逻辑
- 🌐 国际化:支持多语言切换
- 📱 PWA支持:添加离线访问能力
前端总结
通过本文,你已经掌握了Next.js的核心功能:文件路由、数据获取、API开发和部署。Next.js极大地简化了全栈开发流程,让你能更专注于业务逻辑。现在,尝试用Next.js动手搭建你的第一个项目吧!
前端延伸资源:
前端动手练习:
- 创建一个包含首页、关于页和个人作品集的网站
- 使用SSG生成静态页面
- 添加一个联系表单的API端点
- 部署到Vercel并分享给你的朋友!

934

被折叠的 条评论
为什么被折叠?



