为什么生成了 dist,项目还是可能跑不起来?从一个 React + Express + MySQL 项目看部署闭环

为什么生成了 dist,项目还是可能跑不起来?从一个 React + Express + MySQL 项目看部署闭环

全栈项目部署时,最容易出现的误判是:前端、后端都生成了 dist,就等于上线完成。这个判断少了几项关键条件:前端请求地址、后端运行时环境、MySQL 授权和服务器进程必须彼此匹配。本文通过 Future Capsule 的实际代码结构,串起页面、API、数据库和生产部署之间的关系。命令与云服务器步骤来自源码配置,运行未验证。

先建立一个正确的心智模型

部署不是把整个项目目录搬到服务器,而是把不同类型的产物交给不同的运行环境:

text 复制代码
前端 src --Vite--> client/dist --静态服务器--> 浏览器
后端 src --tsc--> server/dist --Node.js--> Express API
                                               ↓
                                             MySQL

所以:

  • client/dist 是浏览器资源;
  • server/dist 是 Node.js 代码;
  • node_modules 是运行依赖;
  • .env 是运行时配置;
  • MySQL 和网络权限属于项目之外,但决定项目能否启动。

先看后端:为什么数据库失败会让服务看起来没启动

后端入口做了一个明确选择:先验证数据库,再开放 HTTP 服务。

ts 复制代码
const startServer = async () => {
  try {
    await testConnection();
    app.listen(PORT, () => {
      console.log(`Server running on http://localhost:${PORT}`);
    });
  } catch (error: any) {
    console.error('Failed to start server:');
    console.error(error.message);
    process.exit(1);
  }
};

这个顺序意味着,只要 testConnection() 失败,app.listen 就不会执行。于是下面这类错误本质上是数据库访问问题,而不是端口监听问题:

text 复制代码
Host '某个来源 IP' is not allowed to connect to this MySQL server

需要检查的是:

  1. 数据库地址和端口是否正确;
  2. MySQL 是否监听了远程地址;
  3. 云安全组和系统防火墙是否允许访问;
  4. 数据库用户是否授权了当前来源主机;
  5. 目标数据库和表是否存在。

编译成功并不能证明这些条件成立。

再看前端:localhost 为什么是部署陷阱

项目 API 服务中的默认配置是:

js 复制代码
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:3001';

这段代码在本地开发很方便,但在生产环境容易造成误解。在通常的浏览器访问场景中,localhost 指向当前浏览器所在的设备:

text 复制代码
用户浏览器 --localhost:3001--> 用户电脑

而不是:

text 复制代码
用户浏览器 --localhost:3001--> 云服务器

因此,生产打包前应把 client/.env 设置为后端真实地址:

env 复制代码
VITE_API_URL=http://你的后端域名或公网IP:3001

然后重新执行 npm run build。这是因为 Vite 环境变量会在构建阶段进入前端静态资源;只在服务器上修改一个前端运行时 .env,不会自动改变已经生成的 JavaScript。

这套业务是怎样流转的?

项目的两个主要接口都挂载在 /api/capsules:

text 复制代码
首页加载
  → useInfiniteScroll
  → GET /api/capsules?page=1&limit=20
  → 分页查询 MySQL
  → 返回 data、hasMore、total

提交胶囊
  → CapsuleForm
  → POST /api/capsules
  → 校验内容和未来时间
  → INSERT capsules

GET 接口使用页码和条数计算偏移量,并按照创建时间倒序排列。前端瀑布流根据窗口宽度切换为 1、2 或 3 列;未解锁卡片每秒计算倒计时,到点后刷新列表。

真正重要的是解锁判断发生在服务端:

ts 复制代码
const isUnlocked = new Date(capsule.unlock_time) <= now;

content: isUnlocked ? capsule.content : null

这比只在前端隐藏内容可靠,因为未解锁正文根本不会出现在接口响应中。

dist 里应该有什么?

后端执行 npm run build 后,TypeScript 按 tsconfig.json 将 src 输出到 dist。后端生产上传可以采用:

text 复制代码
server/
├─ dist/
├─ package.json
├─ package-lock.json
└─ .env

本地 Windows 的 node_modules 不建议直接上传到 Linux 服务器。服务器上进入后端目录重新安装生产依赖:

bash 复制代码
npm install --omit=dev
npm run start

但如果服务器要重新执行 npm run build,就需要安装包含 TypeScript 的开发依赖。

前端只上传 client/dist 中的内容,并让网站根目录直接看到:

text 复制代码
index.html
assets/

如果访问公网 IP 看到的是宝塔默认页面,通常说明网站根目录仍指向默认目录,或者上传时多套了一层 dist。

一张排错表,比重复打包更有用

问题 说明 处理方向
找不到 tsc 编译器依赖没有安装 server 中执行 npm install
MySQL 不允许来源主机 账号来源权限不足 授权、白名单、安全组、防火墙
前端请求 localhost 构建时 API 地址错误 修改 VITE_API_URL 后重新构建
显示宝塔默认页 网站根目录或上传层级错误 让根目录直接包含 index.html
找不到 dist/app.js 后端构建产物缺失 检查 build 输出和上传位置

一套可执行的部署顺序

本地构建

bash 复制代码
cd server
npm install
npm run build

cd ../client
npm install
npm run build

上传

  • 后端:dist、package.json、锁文件和 .env;
  • 前端:client/dist 的内容;
  • 不上传本地 node_modules。

服务器启动

bash 复制代码
cd server
npm install --omit=dev
npm run start

生产环境可使用 PM2 管理 Node.js 进程:

bash 复制代码
pm2 start dist/app.js --name future-capsule-server
pm2 save

上线验收

text 复制代码
浏览器能打开正确 index.html
        ↓
前端请求的不是错误的 localhost
        ↓
后端端口可访问
        ↓
后端启动日志显示数据库连接成功
        ↓
GET/POST /api/capsules 正常

最后一个判断:不要把构建问题和运行问题混在一起

npm run build 失败,优先看 TypeScript、Vite 和依赖安装;npm run start 失败,优先看 dist/app.js、.env、Node.js 依赖和数据库;网页显示默认页,优先看 Nginx/宝塔网站根目录;网页能打开但接口失败,优先看 VITE_API_URL、后端端口和 CORS。

这个项目的经验可以迁移到很多全栈应用:dist 只回答"代码产物在哪里",并不回答"服务能否连接外部依赖"。只有构建、配置、网络、权限和进程全部闭环,部署才算真正完成。

运行未验证:本文示例命令、数据库授权和云服务器配置需在目标环境逐项确认。

标签: 前端部署、Node.js、MySQL、Vite、TypeScript

相关推荐
小天源5 小时前
智叟云集系统架构解析:从品牌 AI 可见度监测到前后端协同
人工智能·react.js·系统架构·node.js·react·ai监测·ai品牌监测
Coisinier8 小时前
docker命令管理镜像及容器
linux·运维·nginx·docker·容器·操作系统
2301_32241428048 小时前
基于web的校园失物招领管理系统59695-计算机毕设 原创(免费领源码+部署教程+开发环境)
mysql·nginx·php·apache·thinkphp·phpstudy·wampserver
donk13149 小时前
React Native for OpenHarmony 实战:三方库 react-native-step-indicator 的鸿蒙化适配指南
分布式·react native·react.js·wpf·harmonyos
donk131410 小时前
React Native for OpenHarmony 实战:三方库 react-native-segmented-control-tab 的鸿蒙化适配指南
javascript·react native·react.js·华为·harmonyos
flytalei12 小时前
从YAML到Nginx服务访问:动手理解 Kubernetes Pod、Deployment 与 Service
运维·nginx·kubernetes
donk131413 小时前
React Native for OpenHarmony 实战:三方库 react-native-toast-message 的鸿蒙化适配指南
react native·react.js·音视频·harmonyos
看浪的路人1 天前
第2讲:ReAct 模式从零实现——不用框架,手写一个 Agent 内核
前端·react.js·前端框架
健康活着就好1 天前
# Nginx负载均衡四种策略,从原理到配置
nginx