博客
技术

最适合初学者的 Web App 开发技术栈

TBD.

在 generative AI 时代,因为有 GPT、Claude、Deepseek 这样的大语言模型,Cursor、Trae 这样的开发工具,无论是编写代码时使用 LLM,还是将 LLM 集成在 app 中,构建一个 app 的门槛被大大降低。而网页是一个极佳的 app 分发渠道,可以在几分钟内让全世界的用户用上自己的产品,因此,如何优雅地开发、部署一个网页 app,同时具备最低认知负荷 + 最佳实践,就变得很重要。

但真的,直到如今,还有独立开发者不知道 Vercel 和 Railway,在使用 EC2 这样的服务器部署,还有人没有用上 Tailwind + shadcn/ui 这样编写更流畅、灵活度非常高的组件库,还有很多初学者不明白后端是什么,没有发现或尝试 FastAPI 这样的框架,以为后端非常复杂非常难。

但显然事实不是这样,这些都只是信息差罢了,因此我想写一篇短短的文章为初学者提供一些参考。

路径选择与介绍

在千万种组合中,我想这样推荐:

  • 网页开发:Next.js
  • 网页部署:Vercel
  • 后端开发:FastAPI
  • 后端部署:Railway

首先简短的介绍一下,Next.js 是如今最主流的前端框架之一,ChatGPT 和一众 AI web app 都是 Next.js 开发的,他提供了一个非常集成的开发框架和相应生态,可以开箱即用的启动一个完整的网页服务,出厂便自带了服务端渲染、SEO(搜索引擎优化)、路由系统等。Next.js 的背后是 React.js,使用 React 和 Vue 这样的前端 UI 引擎好处是他们极大简化了网页 UI 的开发模式,且生态非常丰富。

在有了 Next.js 的网页工程后,Vercel 只需要几次点击就可以帮你搞定剩下的一切,它会通过 git 仓库自动更新,搞定域名、CDN、SSL 证书、负载均衡、日志等,帮你把网页部署到全球各地的服务器上,让你的网页全球可见,且永不掉线。

后端和前端一样,也是一个萝卜青菜各有所爱的领域。Next.js 内置了一个 API 服务端,可以与服务端渲染非常好地结合在一起,我也有许多项目直接使用 Next.js 中的后端,但是 Next.js 中的后端对于初学者来说略微有些绕,不明白原理反而有点难上手。因此,这里更推荐使用 Python 中的 FastAPI 开始上手后端开发,这同样是一个设计得非常好的库,也是我入门了无数个不同语言的后端库后最喜欢的一个。FastAPI 可以以最简洁的方式,帮助初学者快速了解后端开发的基本原理。

后端的部署同样是一个难题,传统的解决方案,比如租服务器运维,用云函数等,都需要花费大量的开发主要业务逻辑意外的时间精力,而 Railway 恰是后端界的 Vercel,同样提供了一个非常简单易用的部署方式,同样可以持续集成 / 持续部署,将后端部署至全球。

教程

以下是步骤与逐步解析。

前端部分

  1. 安装 Node.js / npm
  2. 安装 yarn / pnpm / bun
  3. 创建 Next.js 项目
  4. 将 Next.js 项目上传至 GitHub
  5. 在 Vercel 中部署 Next.js 项目

后端部分

  1. 安装 Python / uv
  2. 创建项目并安装 FastAPI
  3. 使用浏览器与 Apifox 测试 API
  4. 将 FastAPI 项目上传至 GitHub
  5. 在 Railway 中部署 FastAPI 项目
  6. 在 Next.js 中使用后端数据并渲染

前端部分

1. 安装 Node.js / npm

  • Node.js: JavaScript 运行时环境,支持服务端和本地应用开发
  • npm: Node.js 默认包管理工具,全球最大开源库生态系统
  • 官方下载nodejs.org
Node.js 官网
Node.js 官网

安装包下载完成后,运行安装包

Node.js 安装包
Node.js 安装包

安装结束后在终端运行以下命令检查是否成功

# 验证安装结果
node -v  # 应返回 v20.x.x 格式版本
npm -v   # 应返回 9.x.x 以上版本

出现对应版本号说明 Node.js 已经成功安装

Node.js 安装验证
Node.js 安装验证

2. 安装 yarn / pnpm / bun

由于 npm 的依赖安装速度慢、进度现实不好等原因,市面上出现了 yarn / pnpm / bun 三个替代品,他们可能拥有更好的性能、有依赖安装的本地缓存。下表中更详细的进行了对比,可以根据自身开发需要进行选取

特性npmYarnpnpmBun
安装速度⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
磁盘效率⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
热更新速度⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
生态兼容性原生支持优秀优秀发展中
跨项目缓存全局存储内置缓存

越来越多的开发者选择使用这些第三方包管理工具,下面我们会使用 pnpm 作为样例。在已经成功安装 nodejs 的基础上,可以直接使用 npm 命令安装 pnpm,如图所示,在终端中运行

# 使用 npm 安装
npm install -g pnpm
# 如遇到权限问题,使用
sudo npm install -g pnpm
pnpm 安装命令
pnpm 安装命令

安装结束后在终端运行以下命令检查是否成功

# 验证安装
pnpm -v  # 应返回 8.x.x 以上版本

出现对应版本号说明 pnpm 已经成功安装

pnpm 安装验证
pnpm 安装验证

3. 创建 Next.js 项目

首先,使用 Next.js 官方的脚手架创建一个项目:

# 进入目标目录
cd your-workspace-folder

# 使用官方脚手架创建项目(交互式配置)
npx create-next-app@latest

因为项目是使用 npm 作为包管理器,因此我们需要删除项目中的 package-lock.json 文件,然后使用 pnpm 安装依赖。

# 删除 npm 锁定文件
rm package-lock.json

# 使用 pnpm 重新安装依赖
pnpm install

也可以选择直接使用 pnpm 的脚手架直接创建项目,这将省去删除 package-lock.json 文件并重新安装依赖的步骤。

使用 pnpm 创建项目
使用 pnpm 创建项目
# 进入目标目录
cd your-workspace-folder

# 一步完成项目创建与依赖安装
pnpm create next-app

# 交互式配置流程与 npm 版本完全一致
创建项目成功
创建项目成功

待创建完成后,使用以下命令启动项目。

# 进入项目目录
cd my-app

pnpm dev
启动项目
启动项目

默认将会在 3000 端口处开启一个预览网页,在示例图片中 3000 端口被占用,因此开在 3001 端口处。浏览器访问 http://localhost:3000 (本示例中为 http://localhost:3001 ) 应显示 Next.js 欢迎页

Next.js 欢迎页
Next.js 欢迎页

同时,检查项目结构应包含以下核心文件:

├── app/
│   ├── layout.tsx
│   └── page.tsx
├── public/
├── package.json
└── next.config.js

说明项目创建与运行正常。

4. 将 Next.js 项目上传至 GitHub

首先,如果没有 GitHub 账户,需要在 GitHub 官网 注册一个账户。同时,可以下载 GitHub Desktop 来方便地进行项目的同步和管理。

登录 GitHub Desktop: 在 GitHub Desktop 中,使用你的 GitHub 账户信息进行登录。

创建新仓库: 点击菜单栏中的 File,然后选择 New Repository 来创建一个新的仓库。

创建新仓库
创建新仓库

设置仓库信息: 在弹出的窗口中,填写你的新仓库的相关信息:

  • Name: 你的仓库名称,建议使用项目名称。
  • Description: 一个简短的描述,帮助别人了解你的项目。
  • Local Path: 选择你刚刚创建的 Next.js 项目的文件夹。
  • Initialize this repository with a README: 可以勾选此选项,以便为仓库创建一个初始的 README 文件。
新仓库设置示例
新仓库设置示例

发布项目: 设置完成后,点击 Publish repository 按钮,将你的项目上传至 GitHub。

发布项目
发布项目

你的 Next.js 项目应成功上传至 GitHub 了。其他人可以通过项目链接查看和参与你的项目。

5. 在 Vercel 中部署 Next.js 项目

Vercel 的优势:

  • 自动化部署: 每当你向 GitHub 仓库推送新代码时,Vercel 会自动重新构建并部署最新版,确保你的应用始终是最新的。
  • 全球 CDN: Vercel 会将你的应用内容自动部署到全球的内容分发网络(CDN),确保用户在访问时具有低延迟和快速响应。
  • 无服务器架构: Vercel 支持无服务器功能,允许你轻松构建 API 路由,结合前端和后端逻辑,简化开发流程。

创建新项目: 首先,在 Vercel 官网 注册一个账户,注册后登录你的账户,以便管理和部署项目。 登录后,点击页面中的 New Project 按钮来创建一个新的项目。

创建新的 Vercel 项目
创建新的 Vercel 项目

导入 GitHub 仓库: 在弹出的窗口中,选择 Import Git Repository,然后找到并选择你刚才创建的 GitHub 仓库,点击 Import 将项目导入 Vercel。

导入 Github 仓库中的项目
导入 Github 仓库中的项目

打包前端工程: 导入项目完成后,Vercel 会开始自动打包你的前端工程。在此过程中,系统会构建你的 Next.js 应用并准备部署。Vercel 会自动优化你的项目,包括代码拆分和静态页面生成,以提升加载速度和性能。

前端工程打包中
前端工程打包中

设置域名: 打包完成后,Vercel 会自动为你分配一个域名。你可以在 Settings -> Domains 中修改域名,建议使用一个未被他人使用过的 .vercel.app 域名。

修改项目域名
修改项目域名

完成以上步骤后,你的 Next.js 项目就成功部署到了 Vercel,访问分配的域名即可查看你的应用。

后端部分

1. 安装 Python / uv

我们将使用 Python + FastAPI 编写后端,而 uv 是一个新的高性能 Python 包管理器,它甚至可以帮我们下载并管理 Python 版本,所以我们使用 uv 来安装 Python。

2. 创建项目并安装 FastAPI

根据 FastAPI 官网的指引进行安装。

3. 使用浏览器与 Apifox 测试 API

启动 FastAPI 后,在浏览器中打开 http://localhost:3000,即可看到刚才 Python 文件中出现的 Hello, World!,这是因为浏览器访问域名的本质就是向这个域名发送一个 GET 请求,FastAPI 在接收到请求后,返回了一个 JSON 对象,浏览器接收到 JSON 对象后,将其渲染为 Hello, World!

而为了能调试除了 GET 请求以外的 RESTFUL 请求,我们可以使用 Apifox 来测试 FastAPI 写的 API。

你还可以在 Apifox 里设置自动导入 FastAPI 的 /openapi.json,免去手动创建接口的步骤。

4. 将 FastAPI 项目上传至 GitHub

同理,将 FastAPI 项目上传至 GitHub,以便连接 Railway 部署。

5. 在 Railway 中部署 FastAPI 项目

Railway 提供了 Python + FastAPI 的模版,可以一键点击部署,但因为我们使用了 uv 和自定义的端口,所以还需要修改代码以使 Railway 能够正确部署、运行我们的后端代码。

6. 在 Next.js 中使用后端数据并渲染

有了本地 + 线上部署的后端,我们可以尝试在 Next.js 中调用后端接口,进行服务端数据渲染。

如果是偏向客户端的数据渲染,可以采用 swc 进行开发。

额外参考

使用 shadcn/ui 与 Tailwind CSS 构建 UI

1. shadcn/ui

shadcn/ui 提供了一系列精心设计的 React UI 组件,这些组件可以直接复制到项目中使用,并方便进行二次开发和个性化定制。

2. Tailwind CSS

Tailwind CSS 通过提供大量预定义的原子化类名,简化样式编写,减少代码冗余,提高开发效率。

使用 v0.dev 加速网页设计 / 原型开发

v0.dev 是由 Vercel 推出的 AI 驱动的生成式 UI 工具,可以基于自然语言,截图和figma设计稿快速生成并迭代前端界面代码。 v0.dev 目前主要专注于 react 并基于 shadcn/ui 和 Tailwind CSS 的主流 UI 框架。

1. 自然语言生成代码

用户只需输入描述(例如“生成一个带滑动验证的登录页面”),v0 就能基于这些提示生成相应的 UI 组件代码(目前主要为 React 组件代码)。

2. Figma 设计稿导入与截图生成代码

v0 还支持导入 Figma 设计稿(付费)以及上传界面截图,自动解析设计中的组件、布局和样式信息之后生成高度还原的 React UI 组件代码。

3. 迭代式设计

生成初版后,开发者可以针对不满意的细节提出修改要求,v0 会在原有基础上迭代生成新版本(如 v1、v2 等)。

4. 基于主流 UI 框架

v0 生成的代码结合了 shadcn/ui 和 Tailwind CSS 的优势:前者提供了易用且便于二次开发的 UI 组件,而后者则以原子化 CSS 实现高效样式描述。

使用 Cloudflare 代理 DNS + 提供图床

Cloudflare 不仅可以为你的网站提供 DNS 解析和 CDN 加速,还可以通过 Cloudflare Images 服务提供高性能的图床解决方案。

1. DNS 代理设置

首先在 Cloudflare 注册账号,添加你的域名,按照指引修改域名的 NS 记录。完成后,你可以在 Cloudflare 的控制面板中管理域名的所有 DNS 记录。

对于 Vercel 和 Railway 的项目,只需要:

  1. 在 Cloudflare 中添加 CNAME 记录,指向项目的默认域名
  2. 在项目的部署平台中添加自定义域名
  3. 等待 SSL 证书自动配置完成

2. 图床服务

Cloudflare Images 提供了:

  • 自动图片优化
  • 全球 CDN 加速
  • 防盗链保护
  • 按需调整图片尺寸

你可以通过以下方式使用:

  1. 在 Cloudflare Dashboard 中开启 Images 服务
  2. 使用 API 上传图片
  3. 通过类似 https://imagedelivery.net/<YOUR_ACCOUNT_HASH>/<IMAGE_ID>/<VARIANT_NAME> 的 URL 访问图片

使用 next-intl 实现网页多语言

官方文档提供了通过应用路由器(App Router)(包括是否使用 i8n 路由)和页面路由器(Page Router)进行配置的配置方法。

无论哪种配置方法,过程主要分为以下步骤:

1. 安装 next-intl

# 使用 npm 安装
npm install next-intl

# 或者使用 pnpm
pnpm add next-intl

2. 创建多语言 JSON 文件

public/locales/messages/ 目录下创建不同语言的 JSON 文件。

3. 创建 middleware.ts 以处理默认语言和 URL 解析

实现自动检测用户的语言并进行语言重定向。

4. 调用 useTranslations() 读取翻译

调用 useTranslations() 从 JSON 文件中获取翻译,并返回对应的翻译文本。

使用 @next/mdx 实现 Markdown 支持

在 Next.js 中,通过配置 @next/mdx 插件,可以将 .mdx 文件自动转换为 React 组件。这些组件可直接作为页面路由或通过导入使用,同时保留 Markdown 的简洁语法和 React 的交互能力。

官方文档附有完整的教程:

使用 Next.js 后端进行开发

Next.js 13+ 提供了强大的后端开发能力,通过 App Router 可以直接在前端项目中编写后端 API。这种方式的优势在于:

  • 前后端代码共存,便于维护
  • 自动类型安全
  • 零配置部署
  • 支持 Edge Runtime

1. Route Handlers

app/api 目录下创建路由处理器:

import { NextResponse } from 'next/server'
 
export async function GET() {
  return NextResponse.json({ message: 'Hello, Next.js!' })
}

2. Server Actions

在组件中直接定义服务端函数:

'use server'
 
export async function submitForm(formData: FormData) {
  const name = formData.get('name')
  await saveToDatabase({ name })
}

3. 数据获取

使用 React Server Components 直接在组件中获取数据:

async function getData() {
  const res = await fetch('https://api.example.com/data')
  return res.json()
}
 
export default async function Page() {
  const data = await getData()
  return <main>{/* 使用数据渲染UI */}</main>
}

连接 Vercel 整合的数据库

Vercel 提供了多种数据库集成方案,最推荐的是 Vercel Storage,它提供:

1. Vercel Postgres

基于 Neon 的 Serverless SQL 数据库:

import { sql } from '@vercel/postgres'
 
export async function getData() {
  const { rows } = await sql`SELECT * FROM users`
  return rows
}

2. Vercel KV

基于 Upstash 的 Redis 键值存储:

import { kv } from '@vercel/kv'
 
export async function cacheData(key: string, value: any) {
  await kv.set(key, value)
  await kv.expire(key, 3600) // 1小时后过期
}

3. Vercel Blob

对象存储服务,适合存储用户上传的文件:

import { put } from '@vercel/blob'
 
export async function uploadFile(formData: FormData) {
  const file = formData.get('file') as File
  const blob = await put(file.name, file, {
    access: 'public',
  })
  return blob.url
}

使用 Auth.js / Better Auth 进行登录验证

Auth.js(原 NextAuth.js)是目前最流行的 Next.js 身份验证方案,提供了:

  • 多种认证提供商(GitHub、Google、自定义等)
  • 会话管理
  • JWT 支持
  • 类型安全
  • 中间件集成

1. 基础配置

import NextAuth from 'next-auth'
import GithubProvider from 'next-auth/providers/github'
 
const handler = NextAuth({
  providers: [
    GithubProvider({
      clientId: process.env.GITHUB_ID,
      clientSecret: process.env.GITHUB_SECRET,
    }),
  ],
})
 
export { handler as GET, handler as POST }

2. 使用中间件保护路由

export { default } from 'next-auth/middleware'
 
export const config = {
  matcher: ['/protected/:path*']
}

3. 在组件中使用

'use client'
 
import { useSession } from 'next-auth/react'
 
export default function AuthStatus() {
  const { data: session } = useSession()
  return <div>{session ? '已登录' : '未登录'}</div>
}

使用 Vercel AI SDK

Vercel AI SDK 提供了一套完整的工具,用于在 Next.js 应用中集成 AI 功能:

  • 流式响应
  • 智能缓存
  • 多模型支持
  • 类型安全

1. 安装配置

pnpm add ai openai

2. 创建 AI 接口

import { Configuration, OpenAIApi } from 'openai-edge'
import { OpenAIStream, StreamingTextResponse } from 'ai'
 
const config = new Configuration({
  apiKey: process.env.OPENAI_API_KEY,
})
const openai = new OpenAIApi(config)
 
export async function POST(req: Request) {
  const { messages } = await req.json()
  const response = await openai.createChatCompletion({
    model: 'gpt-3.5-turbo',
    stream: true,
    messages,
  })
  const stream = OpenAIStream(response)
  return new StreamingTextResponse(stream)
}

3. 在前端使用

'use client'
 
import { useChat } from 'ai/react'
 
export default function Chat() {
  const { messages, input, handleInputChange, handleSubmit } = useChat()
 
  return (
    <div>
      {messages.map(m => (
        <div key={m.id}>{m.content}</div>
      ))}
      <form onSubmit={handleSubmit}>
        <input
          value={input}
          onChange={handleInputChange}
          placeholder="说点什么..."
        />
      </form>
    </div>
  )
}
分享