前端圈子有个挺有意思的现象:写了三四年页面,组件库玩得飞起,状态管理信手拈来,可一旦项目要求自己搭个后端、配个数据库、把服务部署上线,很多人立刻就卡住了。不是能力不够,而是这块知识从来没被系统串起来过——网上的教程要么是零散的"三步搞定部署",要么是后端视角的完整成长路线,中间那段"前端开发者到底该补哪些、补到什么程度"的空白,几乎没人认真讲过。
这篇内容就是来填这个空白的。我会从一名前端开发者的实际处境出发,把"后端选型"和"部署选型"这两件事拆开揉碎,讲清楚每个决策背后的取舍逻辑,给出可以直接抄作业的方案组合,也会把我在真实项目里踩过的坑原原本本摆出来。不管你是想独立接私活、做自己的产品,还是在团队里需要承担全栈职责,这篇都能帮你少走至少半年的弯路。
1. 先搞清楚前端开发者补后端的真实边界
1.1 你不需要成为后端工程师
这是我最想先说清楚的一件事。很多前端同学一想到"补后端",脑子里浮现的就是Java完整成长路线、分布式事务、高并发架构那一整套东西,然后直接被吓退。但实际上,前端开发者需要掌握的后端能力,和后端工程师的岗位要求,是两个完全不同的集合。
后端工程师的核心竞争力在于:复杂业务建模、高并发场景下的性能优化、分布式系统的稳定性保障、数据库调优、中间件选型。这些东西需要多年积累,而且大部分场景下前端根本用不到。你做一个SaaS工具、一个内容站、一个内部管理系统,日活可能就几千,QPS峰值撑死几百,这个量级下谈分布式纯属过度设计。
前端开发者真正需要补的后端能力,我总结成三个层次:
- 第一层:能读写数据。理解HTTP请求的完整生命周期,会用至少一种方式操作数据库(增删改查),能设计出合理的表结构。这一层是刚需,绕不过去。
- 第二层:能组织业务逻辑。知道什么是路由、中间件、鉴权、参数校验,能把前端传来的请求正确处理并返回。这一层决定了你能不能独立完成一个完整功能。
- 第三层:能保证服务稳定运行。会部署、会看日志、会做基本的错误处理和监控。这一层是从"能跑"到"能用"的分水岭。
超过这三层的东西,比如消息队列、缓存集群、微服务拆分,等你真的遇到性能瓶颈了再学也不迟。过早引入这些,只会让项目复杂度爆炸,维护成本飙升。
1.2 前后端分离项目里,前端到底该管到哪
前后端分离架构下,职责边界其实比很多人想象的更模糊。我见过太多项目,前端只管调接口,接口挂了就找后端;也见过前端把BFF层(Backend for Frontend)全包了,后端只提供原子接口。这两种极端都不太健康。
我的建议是:前端应该负责到"数据聚合与适配"这一层,但不应该负责核心业务规则的实现。
举个具体例子。一个电商详情页,需要展示商品信息、库存、用户是否收藏、优惠券可用状态。后端提供四个独立接口,前端在BFF层聚合这四个接口的数据,组装成页面需要的结构,这是合理的。但如果"优惠券是否可用"这个判断逻辑涉及复杂的规则计算,那这个逻辑就应该在后端实现,前端只负责展示结果。
判断标准很简单:这个逻辑如果被另一个客户端(比如小程序、App)复用,它应该放在后端;如果只服务于当前这个前端,放在BFF层没问题。
1.3 一个容易被忽略的能力:接口设计
前端开发者补后端,最容易忽略的其实是接口设计能力。因为平时都是别人设计好接口你来调,你很少有机会从零设计一套接口。但当你自己写后端时,接口设计的好坏直接决定了前端调用体验。
我踩过的一个典型坑:早期做项目时,我把所有接口都设计成POST,参数全塞在body里,觉得这样统一。结果后来要做缓存、要做RESTful风格的资源管理时,发现根本没法优雅地处理。GET请求可以被浏览器缓存、可以被CDN缓存,POST不行;GET请求的语义是"获取资源",天然幂等,POST不是。
接口设计的几个基本原则,前端同学一定要建立起来:
| 原则 | 说明 | 反例 |
|---|---|---|
| 用对HTTP方法 | GET查、POST增、PUT改、DELETE删 | 所有操作都用POST |
| 资源导向命名 | URL表示资源,动词放方法里 | /getUserById |
| 状态码语义化 | 200成功、400参数错、401未登录、403无权限、404不存在、500服务错 | 所有错误都返回200 |
| 分页统一 | 列表接口统一用page/pageSize或cursor | 每个接口分页参数都不一样 |
| 错误结构统一 | 错误响应格式一致,便于前端统一处理 | 有的返回字符串,有的返回对象 |
这套东西看起来简单,但真正落地时能坚持下来的项目不多。而一旦坚持下来,前端调用接口的体验会有质的提升——你可以写一个统一的请求拦截器处理所有错误,可以基于状态码做统一的登录态跳转,可以基于HTTP方法做统一的缓存策略。
2. 后端技术栈选型:别被"主流"绑架
2.1 Node.js系:前端最顺滑的过渡路径
对前端开发者来说,Node.js系是学习成本最低的选择,没有之一。你不需要学新语言,JavaScript/TypeScript直接上手,异步模型、模块系统、包管理这些概念你本来就熟。Express、Koa、Fastify、NestJS这几个框架,我按推荐度排个序。
Fastify是我目前最推荐的。性能比Express好一大截,插件体系设计得很干净,TypeScript支持一流,内置了JSON Schema校验。它的学习曲线比NestJS平缓,但比Express更有结构。一个典型的Fastify路由长这样:
fastify.get('/api/users/:id', { schema: { params: { type: 'object', properties: { id: { type: 'integer' } } }, response: { 200: { type: 'object', properties: { id: { type: 'integer' }, name: { type: 'string' } } } } } }, async (request, reply) => { const user = await db.getUser(request.params.id) return user })Schema定义既是校验也是文档,还能自动生成OpenAPI规范,一举三得。这个设计我很喜欢。
NestJS适合中大型项目。它借鉴了Angular的架构思想,模块、控制器、服务、依赖注入一应俱全。如果你团队里前端用的是Angular,或者你习惯了强类型和装饰器,NestJS会很舒服。但它的样板代码比较多,小项目用起来会觉得重。
Express是经典,生态最全,但它的中间件模型和错误处理机制在现代视角下有些过时。新项目我不太推荐,除非你要用某个只有Express版本的中间件。
Koa是Express原班人马做的,async/await支持更优雅,但生态比Express小,而且它的洋葱模型对新手来说需要适应。
Node.js系的短板也很明显:CPU密集型任务性能差(比如图像处理、复杂计算),类型系统不如静态语言严格,依赖管理容易出问题(node_modules黑洞)。但对于绝大多数Web应用场景,这些都不是问题。
2.2 Python系:数据与AI场景的最优解
如果你的项目涉及数据处理、爬虫、AI模型调用,Python系几乎是唯一选择。FastAPI是我强烈推荐的框架,它的设计理念和Fastify很像——基于类型注解做校验和文档生成,性能在Python框架里属于第一梯队。
FastAPI最大的优势是Pydantic带来的类型安全。你定义好数据模型,请求校验、响应序列化、文档生成全部自动完成:
from fastapi import FastAPI from pydantic import BaseModel class UserCreate(BaseModel): name: str email: str age: int | None = None app = FastAPI() @app.post("/api/users") async def create_user(user: UserCreate): # user已经是校验过的对象,直接用 return await db.create_user(user)如果你要接大模型能力,比如本地部署的模型服务,Python生态的库支持是最全的。这块后面部署章节会细讲。
Python系的短板是性能。虽然FastAPI用了异步,但Python的GIL限制决定了它在高并发场景下不如Node.js和Go。不过对于中小项目,这个差距可以忽略。
2.3 Go系:性能与部署体验的平衡点
Go是我认为前端开发者值得认真考虑的第三个选项。它的语法简洁,学习曲线比Java平缓得多,编译型语言带来的部署体验极佳——编译成一个二进制文件,扔到服务器上就能跑,不需要装运行时。
Gin是Go生态里最流行的Web框架,API风格和Express很像,前端同学上手很快:
func main() { r := gin.Default() r.GET("/api/users/:id", func(c *gin.Context) { id := c.Param("id") user, err := db.GetUser(id) if err != nil { c.JSON(404, gin.H{"error": "user not found"}) return } c.JSON(200, user) }) r.Run(":8080") }Go的短板是生态相对年轻,某些领域的库不如Node.js和Python丰富,而且它的错误处理方式(到处if err != nil)需要适应。但如果你追求性能和部署简单,Go是很值得投入的。
2.4 选型决策表:按场景对号入座
说了这么多,直接给一张决策表,按你的实际场景对号入座:
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 个人项目、快速原型 | Node.js + Fastify | 学习成本最低,开发速度快 |
| 中大型团队项目 | Node.js + NestJS 或 Go + Gin | 结构清晰,便于协作 |
| 数据/AI相关 | Python + FastAPI | 生态最全,库支持最好 |
| 高并发API服务 | Go + Gin | 性能强,资源占用低 |
| 需要快速接大模型 | Python + FastAPI | 模型调用库最丰富 |
| 已有Java团队 | Java + Spring Boot | 团队技术栈统一优先 |
选型这件事,我的核心观点是:不要为了用新技术而选型,要为了解决问题而选型。你团队最熟什么、项目最需要什么、维护成本最低的是什么,这三个问题的答案才是选型的依据。
3. 数据库与存储:从"能存"到"存得好"
3.1 关系型数据库:PostgreSQL还是MySQL
前端开发者第一次选数据库,大概率会在PostgreSQL和MySQL之间纠结。我的建议很明确:新项目无脑选PostgreSQL。
原因有几个。第一,PostgreSQL对JSON的支持远超MySQL,你可以直接在关系表里存JSON字段并对其建索引、做查询,这在处理半结构化数据时非常方便。第二,PostgreSQL的类型系统更丰富,数组、范围、枚举、UUID都是原生支持。第三,PostgreSQL的扩展生态强大,需要全文搜索、地理查询、向量检索时,都有成熟的扩展可用。
MySQL的优势在于生态成熟、运维资料多、云厂商支持广。如果你的团队已经有MySQL运维经验,或者要部署到某些只支持MySQL的环境,那选MySQL也没问题。但如果是全新项目,PostgreSQL是更面向未来的选择。
表设计这块,前端同学最容易犯的错是"把前端数据结构直接映射成表结构"。比如前端有个嵌套的地址对象,就直接建一个地址表关联。但很多时候,地址只是一个值对象,不需要独立成表,直接存JSON字段反而更合适。判断标准是:这个数据是否需要被独立查询、更新、关联?是则独立成表,否则内嵌。
3.2 ORM选型:Prisma、Drizzle还是TypeORM
Node.js生态的ORM,我按推荐度排:Prisma > Drizzle > TypeORM。
Prisma的最大优势是类型安全和开发体验。你定义好schema,它会自动生成完全类型化的客户端,写查询时IDE能给你完整的补全和类型检查:
model User { id Int @id @default(autoincrement()) email String @unique name String? posts Post[] } model Post { id Int @id @default(autoincrement()) title String author User @relation(fields: [authorId], references: [id]) authorId Int }const userWithPosts = await prisma.user.findUnique({ where: { id: 1 }, include: { posts: true } }) // userWithPosts的类型完全推导出来,posts字段自动补全Prisma的短板是它的查询引擎是独立的二进制,部署时需要额外处理,而且某些复杂查询它生成的SQL不够优化。
Drizzle是后起之秀,它更接近SQL,生成的查询更可控,而且它是纯TypeScript实现,没有额外的二进制依赖。如果你对SQL比较熟,Drizzle会让你觉得很自然。
TypeORM是老牌ORM,装饰器风格,但它的类型推导不如Prisma,而且历史包袱比较重。新项目我不太推荐。
3.3 什么时候该引入NoSQL
很多前端同学一上来就想用MongoDB,觉得JSON文档模型和前端数据结构天然契合。但我的建议是:除非有明确理由,否则优先用关系型数据库。
关系型数据库经过几十年发展,在数据一致性、事务、查询优化方面都非常成熟。而NoSQL的"灵活"往往意味着"约束少",约束少意味着数据容易变脏,后期维护成本高。
真正需要NoSQL的场景其实不多:
- 文档型数据为主,且结构变化频繁:比如CMS系统,内容模型经常调整,MongoDB的灵活schema有优势。
- 海量日志、时序数据:这类数据写入量大、查询模式固定,用专门的时序数据库或列式存储更合适。
- 缓存场景:Redis是标配,用来做会话、热点数据缓存、分布式锁。
- 全文搜索:Elasticsearch或Meilisearch,比关系型数据库的LIKE查询强太多。
向量数据库这块单独说一下。如果你要做语义搜索、RAG应用,需要存向量并做相似度检索。Milvus、Chroma、Qdrant这几个是常见选择。Chroma最轻量,适合本地开发和小项目;Qdrant性能和功能平衡得好;Milvus适合大规模场景但部署复杂。我的建议是先用Chroma跑通流程,真有性能需求了再换。
4. 部署方案:从"本地能跑"到"线上能用"
4.1 部署方式的三个层次
部署这件事,我把它分成三个层次,对应不同的项目阶段和团队规模。
第一层:平台托管(PaaS)。Vercel、Netlify、Railway、Render这类平台,你只需要把代码推上去,它自动构建、部署、分配域名、配HTTPS。前端项目用Vercel/Netlify是标配,后端用Railway/Render也很省心。这一层的优势是零运维,劣势是成本随规模上升快,且定制能力有限。
第二层:容器化部署。用Docker把应用打包成镜像,部署到云服务器或容器编排平台。这一层需要你懂Dockerfile怎么写、镜像怎么优化、容器怎么编排。但一旦掌握,部署的一致性和可移植性会大幅提升。
第三层:自建基础设施。自己买服务器、配负载均衡、搭CI/CD、做监控告警。这一层灵活度最高,但运维成本也最高。除非团队有专职运维,否则不建议前端开发者深入这一层。
我的建议是:个人项目和小团队从第一层起步,业务稳定后逐步过渡到第二层,第三层交给专业的人。
4.2 Docker部署的实操细节
Docker是绕不过去的一环,我重点讲几个前端同学容易踩坑的地方。
多阶段构建是必须掌握的技巧。前端项目构建产物和运行环境是分离的,用多阶段构建可以把镜像体积从几百MB压到几十MB:
# 构建阶段 FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build # 运行阶段 FROM node:20-alpine WORKDIR /app COPY --from=builder /app/dist ./dist COPY --from=builder /app/node_modules ./node_modules COPY package*.json ./ EXPOSE 3000 CMD ["node", "dist/server.js"]这个Dockerfile的关键点:构建阶段装了所有依赖并编译,运行阶段只拷贝编译产物和运行时依赖。npm ci比npm install更适合CI环境,因为它严格按lock文件安装,保证一致性。
镜像体积优化的几个技巧:用alpine基础镜像、合并RUN指令减少层数、清理缓存文件、用.dockerignore排除不需要的文件。我见过一个项目镜像1.2GB,优化后压到80MB,部署速度提升十几倍。
环境变量管理是另一个重点。不要把数据库密码、API密钥硬编码在代码里,用环境变量注入。Docker Compose里可以这样写:
services: app: build: . environment: - DATABASE_URL=postgresql://user:pass@db:5432/mydb - NODE_ENV=production depends_on: - db db: image: postgres:16-alpine environment: - POSTGRES_PASSWORD=pass volumes: - pgdata:/var/lib/postgresql/data volumes: pgdata:注意depends_on只保证启动顺序,不保证db已经ready。生产环境需要在应用里做重试逻辑,或者用healthcheck配合。
4.3 本地部署AI模型的配置要点
现在很多项目需要接大模型能力,本地部署模型是常见需求。这块我讲几个实操要点。
Ollama是目前本地跑模型最省心的方案。安装后一条命令就能拉取并运行模型:
ollama pull llama3.1 ollama run llama3.1它会自动处理模型下载、量化、推理服务启动。默认监听11434端口,提供兼容OpenAI的API接口,前端可以直接调用。
硬件配置是本地部署的核心约束。模型参数量和显存需求大致对应关系:
| 模型参数量 | 量化后显存需求 | 推荐硬件 |
|---|---|---|
| 7B | 4-6GB | 消费级显卡即可 |
| 13B | 8-10GB | RTX 3060 12G以上 |
| 34B | 20-24GB | RTX 4090或双卡 |
| 70B | 40GB+ | 专业卡或多卡 |
如果显存不够,可以用CPU推理,但速度会慢很多。也可以用更激进的量化(比如Q4、Q3),代价是精度下降。
部署架构上,我建议把模型服务独立部署,应用通过HTTP调用。这样模型服务可以独立扩缩容,应用不需要关心模型细节。用Docker Compose编排:
services: ollama: image: ollama/ollama ports: - "11434:11434" volumes: - ollama_data:/root/.ollama deploy: resources: reservations: devices: - driver: nvidia count: 1 capabilities: [gpu] volumes: ollama_data:这个配置把模型数据持久化到volume,容器重启不会丢失已下载的模型。GPU预留配置让容器能访问宿主机的NVIDIA显卡。
4.4 CI/CD:让部署自动化
手动部署的时代已经过去了,CI/CD是标配。GitHub Actions是最容易上手的方案,一个典型的部署workflow:
name: Deploy on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - run: npm ci - run: npm run build - run: npm test - name: Deploy to server uses: appleboy/ssh-action@v1 with: host: ${{ secrets.HOST }} username: ${{ secrets.USER }} key: ${{ secrets.SSH_KEY }} script: | cd /app git pull docker compose up -d --build这个workflow做了几件事:检出代码、装依赖、构建、跑测试、SSH到服务器拉代码并重建容器。关键点是secrets管理敏感信息,不要把服务器地址、密钥写死在workflow里。
CI/CD的价值不只是省事,更重要的是保证部署的一致性。手动部署容易漏步骤、容易出错,自动化部署每次都是同样的流程,出问题也容易回溯。
5. 那些没人告诉你但一定会踩的坑
5.1 环境变量在构建时和运行时的区别
这是前端同学最容易踩的坑,没有之一。前端项目里,process.env.XXX在构建时就被替换成字面量了,运行时改环境变量没用。而后端项目里,process.env.XXX是运行时读取的,改了立即生效。
这个差异导致的问题:你在Docker里给前端容器注入环境变量,发现根本不生效,因为构建时就已经固化了。解决方案是前端用运行时配置——把配置写在一个单独的config.js里,容器启动时用脚本生成这个文件,或者通过window对象注入。
后端则要注意:环境变量在进程启动时读取,改了要重启进程。用PM2或Docker的话,重启是自动的,但如果你在代码里缓存了环境变量,就要小心。
5.2 数据库连接池配置不当导致的连接耗尽
默认的连接池配置往往不适合生产环境。Node.js的pg库默认池大小是10,Prisma默认是num_cpus * 2 + 1。如果你的应用并发高,或者有慢查询,连接池很快会被占满,新请求就会排队甚至超时。
我的经验值:连接池大小设置为数据库最大连接数的70%左右,同时设置合理的连接超时和空闲回收。PostgreSQL默认最大连接数是100,那应用侧连接池设70左右比较合适。如果有多实例部署,每个实例的池大小要除以实例数。
const pool = new Pool({ max: 20, idleTimeoutMillis: 30000, connectionTimeoutMillis: 2000, })connectionTimeoutMillis很关键,它决定了获取连接的最长等待时间。设太短,高峰期容易报错;设太长,请求会堆积。2000ms是个比较平衡的值。
5.3 日志没打好,出问题两眼一抹黑
前端开发者写后端,最容易忽略日志。本地开发时console.log够用,但线上出问题时,没有结构化日志你根本不知道发生了什么。
我的建议是:从项目第一天就用结构化日志。Node.js用pino,Python用structlog,Go用zap。结构化日志输出JSON格式,便于检索和分析:
const logger = pino({ level: process.env.LOG_LEVEL || 'info', formatters: { level: (label) => ({ level: label }) } }) logger.info({ userId: 123, action: 'login' }, 'user logged in')关键是要记录上下文信息:请求ID、用户ID、耗时、错误堆栈。有了这些,排查问题时可以按请求ID串起整个调用链。
日志级别也要合理使用:debug用于开发调试,info用于正常业务事件,warn用于可恢复的异常,error用于需要关注的错误。生产环境一般开info级别,出问题时临时调到debug。
5.4 健康检查不是可选项
很多人部署服务时不做健康检查,结果容器挂了编排系统不知道,流量还在往上面打。健康检查分两种:liveness(存活检查)和readiness(就绪检查)。
liveness检查进程是否还活着,失败则重启容器。readiness检查服务是否准备好接收流量,失败则从负载均衡摘除。两个检查的端点应该分开:
app.get('/health/live', (req, res) => { res.status(200).send('ok') }) app.get('/health/ready', async (req, res) => { try { await db.query('SELECT 1') res.status(200).send('ok') } catch (err) { res.status(503).send('not ready') } })liveness不要检查外部依赖,否则数据库抖动会导致容器被误杀。readiness可以检查关键依赖,依赖不可用时暂时不接流量。
5.5 上传功能的正则限制与服务器配置
文件上传是前端转后端时的高频需求,也是坑最多的地方。常见问题:前端上传脚本文件被后端拒绝,因为后端正则限制了后缀。但有时候你确实需要上传某些特殊后缀的文件,这时候要检查两个地方。
第一是应用层的校验规则。很多框架默认有文件类型白名单,需要显式配置。第二是Web服务器层的限制。比如Apache的配置里可能有<FilesMatch>规则限制某些后缀,Nginx可能有location规则拦截。排查时要一层层看:应用框架的校验、Web服务器的配置、操作系统的权限。
我的建议是:上传校验用白名单而非黑名单。黑名单永远列不全,白名单只允许明确需要的类型,更安全。同时要校验文件内容(magic number),不能只看后缀,因为后缀可以伪造。
6. 一套可以直接抄作业的技术栈组合
6.1 个人项目/快速原型组合
如果你要快速做一个个人项目,我推荐这套:
- 前端:Vue 3 + Vite + TypeScript
- 后端:Node.js + Fastify + Prisma
- 数据库:PostgreSQL(用Supabase或Neon的免费层)
- 部署:前端Vercel,后端Railway
- AI能力:需要时接OpenAI API或本地Ollama
这套组合的优势是学习成本低、开发速度快、部署零运维。Supabase和Neon提供免费的PostgreSQL,Railway提供免费额度的后端托管,Vercel的前端托管基本免费。整个项目跑起来,前期成本几乎为零。
6.2 中小团队生产组合
如果是团队项目,需要更稳的架构:
- 前端:React/Vue + TypeScript + Vite
- 后端:Node.js + NestJS 或 Go + Gin
- 数据库:PostgreSQL + Redis
- ORM:Prisma(Node)或 GORM(Go)
- 部署:Docker + Docker Compose,部署到云服务器
- CI/CD:GitHub Actions
- 监控:Sentry(错误)+ Prometheus + Grafana(指标)
这套组合的关键是容器化和自动化。Docker保证环境一致,GitHub Actions保证部署流程一致,Sentry和Prometheus保证出问题能及时发现。
6.3 数据/AI项目组合
涉及数据处理和AI的项目:
- 前端:React + TypeScript
- 后端:Python + FastAPI
- 数据库:PostgreSQL + Chroma/Qdrant(向量)
- AI服务:Ollama本地部署 或 云API
- 任务队列:Celery + Redis(处理耗时任务)
- 部署:Docker Compose,GPU服务器
这套组合的重点是Python生态的完整性。FastAPI处理API,Celery处理异步任务,向量数据库处理语义检索,Ollama或云API提供模型能力。
6.4 选型时的几个反直觉建议
最后分享几个我在选型上踩坑后总结的反直觉建议。
不要追求最新版本。新版本往往有未发现的bug,生态适配也需要时间。生产环境用稳定版,等新版本发布几个月、社区反馈稳定了再升级。
不要过早优化。我见过太多项目一开始就上微服务、上消息队列、上缓存集群,结果业务量根本撑不起来,维护成本却高得吓人。先用最简单的方案跑通业务,遇到瓶颈再优化。
不要忽视运维成本。选型时不仅要考虑开发效率,还要考虑运维成本。一个需要专职运维的方案,即使开发效率高,总体成本也可能更高。对前端开发者来说,托管服务往往比自建更划算。
不要盲目跟风。技术圈每年都有新热点,但大部分热点和你项目无关。选型时问自己:这个技术解决了我什么具体问题?如果答不上来,就不用。
技术选型这件事,没有标准答案,只有适合和不适合。我上面给的所有建议,都是基于"前端开发者补后端"这个特定视角的,换一个视角结论可能完全不同。你在实际项目中,还是要结合自己的团队、业务、资源来综合判断。但有一点是确定的:先把一个完整项目从零到一跑通,比看一百篇选型文章都有用。跑通之后,你对每个技术点的理解会完全不一样,那时候再回头看这些选型建议,会有更深的体会。