从零开始:将 Vite + React 项目部署到 GitHub Pages 完全指南
从零开始:将 Vite + React 项目部署到 GitHub Pages 完全指南
本教程基于实际操作经验编写,从"为什么"到"怎么做",带你彻底理解整个部署流程。
写在前面
你写了一个网页应用,想让朋友也能访问。最简单的方式就是部署到 GitHub Pages —— 免费、稳定、还自带 HTTPS。
但当你真正动手时,可能会遇到一堆问题:
- 什么是 Git?什么是 GitHub?它们有什么区别?
- GitHub Pages 和 GitHub Actions 又是什么关系?
- 为什么我的 React 项目不能直接部署,还要配置一堆东西?
这篇教程会回答所有这些问题。读完后,你不仅能成功部署项目,还能理解每一步背后的原理。
第一章:理解基本概念
在开始之前,我们先搞清楚几个核心概念。这些概念相互关联,理解它们之间的关系非常重要。
1.1 Git:你的代码时光机
想象一下,你在写一篇重要的文章。你可能会这样保存:
论文_v1.doc
论文_v2.doc
论文_v2_修改.doc
论文_最终版.doc
论文_最终版_真的最终.doc这种方式有很多问题:文件越来越多、不知道每个版本改了什么、想回到某个状态很困难。
Git 就是为了解决这个问题而生的。它是一个版本控制系统,能够:
- 记录每一次修改的内容
- 随时回到任何一个历史版本
- 查看"谁在什么时候改了什么"
使用 Git 后,你只需要一个文件夹,所有历史版本都被 Git 默默记录在 .git 隐藏目录里。
1.2 GitHub:Git 的云端管家
Git 把版本历史存在你自己电脑上,但如果:
- 电脑坏了怎么办?
- 想和别人协作怎么办?
- 想在另一台电脑上继续工作怎么办?
GitHub 就是一个云端平台,专门用来存放 Git 仓库。你可以把本地的代码"推送"到 GitHub,它就安全地保存在云端了。
💡 简单记忆:Git 是工具,GitHub 是平台。就像 "视频" 和 "YouTube" 的关系。
1.3 GitHub Pages:免费的网站托管
GitHub 除了存代码,还提供了一个福利:GitHub Pages。
它能把你仓库里的静态文件(HTML、CSS、JS)变成一个真正可访问的网站。而且完全免费,自带 https://用户名.github.io/仓库名 的域名。
1.4 GitHub Actions:自动化机器人
这是一个稍微高级的概念,但对于现代前端项目来说必不可少。
问题来了:你写的是 React + TypeScript 代码,但浏览器只认识 HTML、CSS、JavaScript。
你写的代码 浏览器需要的
─────────── ────────────
App.tsx → index.js
styles.scss → styles.css
组件化代码 → 打包后的单文件中间这个转换过程叫做构建(Build)。在本地,你运行 npm run build,Vite 就会帮你完成构建,生成 dist 文件夹。
但 GitHub Pages 只是一个静态文件托管服务,它不会帮你运行 npm run build。
这就是 GitHub Actions 的作用:它是一个自动化服务,可以在 GitHub 的服务器上执行命令。每当你推送代码,它就自动:
- 下载你的代码
- 安装依赖 (
npm install) - 执行构建 (
npm run build) - 把构建结果部署到 Pages
相当于你有了一个 24 小时在线的机器人,帮你做重复性工作。
1.5 概念关系图
让我们用一张图来总结这些概念的关系:
┌─────────────────────────────────────────────────────────────────┐
│ 你的电脑 │
│ ┌─────────────┐ │
│ │ 项目文件 │ ──── git add/commit ────→ 本地 Git 仓库 │
│ │ (源代码) │ (.git 目录) │
│ └─────────────┘ │
└──────────────────────────────┬──────────────────────────────────┘
│ git push
▼
┌─────────────────────────────────────────────────────────────────┐
│ GitHub │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 远程仓库 │ ───→ │ Actions │ ───→ │ Pages │ │
│ │ (存储代码) │ │ (自动构建) │ │ (托管网站) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼
用户访问的网站
https://xxx.github.io/项目名/第二章:Git 操作详解
现在概念清楚了,让我们开始实际操作。
2.1 初始化仓库
git init这条命令在当前目录创建一个 .git 隐藏文件夹。从此刻起,Git 开始追踪这个目录。
执行前:普通文件夹
执行后:Git 仓库
你可以用 ls -la(Mac/Linux)或 dir /a(Windows)查看这个隐藏目录。
2.2 Git 的三个区域
在理解后续命令前,必须先理解 Git 的三个区域:
┌─────────────┐ git add ┌─────────────┐ git commit ┌─────────────┐
│ 工作区 │ ───────────→ │ 暂存区 │ ─────────────→ │ 版本库 │
│ Working Dir │ │ Stage │ │ Repository │
│ │ │ │ │ │
│ 你编辑的 │ │ 准备提交的 │ │ 已保存的 │
│ 实际文件 │ │ 文件快照 │ │ 历史版本 │
└─────────────┘ └─────────────┘ └─────────────┘为什么要有"暂存区"这个中间层?
想象你改了 10 个文件,但只想提交其中 3 个。暂存区让你可以精确控制"这次提交包含哪些改动"。
2.3 添加文件到暂存区
git add .这里的 . 表示"当前目录的所有文件"。执行后,所有改动的文件都进入暂存区,等待被提交。
你也可以只添加特定文件:
git add src/App.tsx
git add package.json2.4 提交到版本库
git commit -m "这里写提交信息"这条命令把暂存区的内容永久保存到版本库。每次提交都会生成一个唯一的 ID(如 c7d1fef),你可以通过这个 ID 回到这个版本。
提交信息很重要:好的提交信息能让你(和同事)知道这次改动是干什么的。
# ❌ 不好的提交信息
git commit -m "update"
git commit -m "fix"
# ✅ 好的提交信息
git commit -m "修复登录页面样式错位问题"
git commit -m "添加用户头像上传功能"2.5 .gitignore:告诉 Git 忽略什么
有些文件不应该提交到仓库:
node_modules/:几万个文件,又大又能重新安装dist/:构建产物,每次构建都会重新生成.env:包含密钥等敏感信息
在项目根目录创建 .gitignore 文件:
node_modules/
dist/
.env
.env.localGit 会自动忽略这些文件,不会追踪它们的变化。
第三章:连接 GitHub
本地仓库准备好了,接下来要把它推送到 GitHub。
3.1 GitHub CLI:命令行操作 GitHub
传统方式需要在网页上操作,但 GitHub CLI(命令行工具)让一切变得简单。
首先检查是否安装:
gh --version如果没安装,去 https://cli.github.com/ 下载。
3.2 登录认证
gh auth login按提示操作:
- 选择
GitHub.com - 选择
HTTPS - 选择
Login with a web browser - 复制终端显示的一次性代码
- 浏览器会打开,粘贴代码完成授权
授权成功后,GitHub CLI 就能代表你执行操作了。
3.3 创建远程仓库并推送
gh repo create 仓库名 --private --source=. --push这一条命令做了四件事:
- 在 GitHub 上创建名为"仓库名"的私有仓库
- 把当前目录(
--source=.)设为源代码 - 自动配置远程连接
- 推送代码(
--push)
参数说明:
--private:私有仓库(只有你能看到)--public:公开仓库(所有人能看到)
第四章:配置 GitHub Actions
现在代码在 GitHub 了,我们来配置自动部署。
4.1 创建工作流文件
在项目根目录创建 .github/workflows/deploy.yml:
项目目录/
├── .github/
│ └── workflows/
│ └── deploy.yml ← 创建这个文件
├── src/
├── package.json
└── ...💡 目录名必须是 .github/workflows,这是 GitHub 约定的位置。4.2 工作流文件详解
下面是完整的配置文件,我会逐段解释每一部分:
name: Deploy to GitHub Pages这只是给工作流起个名字,会显示在 GitHub Actions 页面。
on:
push:
branches: ['master']
workflow_dispatch:触发条件:
push+branches: ['master']:当有代码推送到 master 分支时触发workflow_dispatch:允许在 GitHub 网页上手动触发
permissions:
contents: read
pages: write
id-token: write权限设置:
contents: read:允许读取仓库内容pages: write:允许写入 GitHub Pagesid-token: write:用于身份验证
concurrency:
group: 'pages'
cancel-in-progress: true并发控制:如果新的部署开始,取消正在进行的旧部署。避免冲突。
jobs:
build:
runs-on: ubuntu-latest定义任务:创建一个名为 build 的任务,运行在最新版 Ubuntu 虚拟机上。
💡 GitHub 会为每次运行临时创建一个全新的虚拟机,运行完就销毁。
steps:
- name: Checkout
uses: actions/checkout@v4第一步:检出代码。虚拟机是空的,需要把你的代码从仓库"下载"进去。actions/checkout@v4 是 GitHub 官方提供的动作(Action)。
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'第二步:安装 Node.js。虚拟机虽然有基础环境,但不一定有你需要的 Node 版本。这一步安装 Node 20,并启用 npm 缓存加速后续安装。
- name: Install dependencies
run: npm install第三步:安装项目依赖。读取 package.json,下载所有依赖包。
- name: Build
run: npm run build第四步:构建项目。执行 Vite 的构建命令,把源代码编译成静态文件,输出到 dist 目录。
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: './dist'第五、六步:准备部署。配置 Pages 并上传 dist 目录作为"产物"。
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4第二个任务:部署。needs: build 表示必须等 build 任务完成才能开始。这个任务把上一步上传的产物发布到 GitHub Pages。
4.3 关于 package-lock.json
你可能注意到了 cache: 'npm' 这个配置。它需要读取 package-lock.json 来确定缓存键。
什么是 package-lock.json?
当你运行 npm install 时,npm 会:
- 读取
package.json里的依赖列表 - 下载依赖,并记录每个包的精确版本号到
package-lock.json
这个文件确保了"任何人在任何时候安装,都得到完全相同的依赖版本"。
如果没有这个文件,Actions 会报错:
Dependencies lock file is not found解决方法:
npm install # 这会自动生成 package-lock.json
git add package-lock.json
git commit -m "添加 package-lock.json"
git push4.4 启用 GitHub Pages
工作流文件创建好了,还需要在 GitHub 上启用 Pages:
gh api repos/你的用户名/仓库名/pages -X POST -f build_type=workflow这条命令告诉 GitHub:"我要用 Actions 工作流来部署 Pages"。
第五章:自定义域名
默认的 xxx.github.io/项目名 地址太长?你可以配置自己的域名。
5.1 DNS 是什么?
当你在浏览器输入 google.com,电脑需要知道这个域名对应哪个服务器(IP 地址)。DNS(域名系统)就像一本电话簿,负责把域名"翻译"成 IP 地址。
你输入: journal.hongrui-fu.online
│
▼ DNS 查询
│
得到: 185.199.108.153 (GitHub 服务器)
│
▼ 发送请求
│
显示: 你的网站5.2 常见 DNS 记录类型
| 记录类型 | 作用 | 值的格式 | 例子 |
|---|---|---|---|
| A | 域名 → IP 地址 | IP 地址 | 185.199.108.153 |
| CNAME | 域名 → 另一个域名 | 域名 | xunxun2001.github.io |
| TXT | 存储文本(常用于验证) | 任意文本 | github-pages-verify=xxx |
5.3 域名验证 vs 域名指向
这是很多人混淆的地方:
TXT 记录(验证):
- 作用:证明"这个域名是我的"
- 给谁看:GitHub
- 不设置会怎样:GitHub 可能不让你用这个域名
A/CNAME 记录(指向):
- 作用:告诉访客"这个域名的服务器在哪"
- 给谁看:全世界的 DNS 系统
- 不设置会怎样:访客无法访问你的网站
两者都需要设置!
5.4 A 记录还是 CNAME?
| 域名类型 | 推荐记录 | 原因 |
|---|---|---|
顶级域名 (example.com) | A 记录 | 技术限制:根域名不能用 CNAME |
子域名 (www.example.com) | CNAME | 更灵活,如果 GitHub IP 变了会自动跟随 |
子域名 (journal.example.com) | CNAME | 同上 |
GitHub Pages 的官方 IP 地址(如果用 A 记录):
185.199.108.153
185.199.109.153
185.199.110.153
185.199.111.153这些 IP 非常稳定,GitHub 保证不会轻易变更。
5.5 配置步骤(以子域名为例)
假设你想用 journal.hongrui-fu.online:
步骤 1:GitHub 端设置
gh api repos/你的用户名/仓库名/pages -X PUT -f cname="journal.hongrui-fu.online"步骤 2:DNS 端设置(在你的域名服务商控制台)
添加一条 CNAME 记录:
| 类型 | 名称 | 值 |
|---|---|---|
| CNAME | journal | xunxun2001.github.io |
⚠️ Cloudflare 用户注意:把代理状态设为"仅 DNS"(灰色云朵),否则 HTTPS 可能有问题。
步骤 3:修改 Vite 配置
// vite.config.ts
export default defineConfig({
base: '/', // 使用自定义域名时,base 应该是 '/'
// ...
})为什么要改 base?
base 决定了 HTML 中资源的路径前缀:
<!-- base: '/fufu-zhizhi-journal/' -->
<script src="/fufu-zhizhi-journal/assets/index.js"></script>
<!-- base: '/' -->
<script src="/assets/index.js"></script>- 使用
github.io/仓库名/访问时,需要加仓库名前缀 - 使用自定义域名访问时,不需要前缀
配置错误会导致资源 404,页面空白。
第六章:常见问题排查
6.1 推送被拒绝:邮箱隐私保护
错误信息:
error: GH007: Your push would publish a private email address原因:你的 Git 配置使用了真实邮箱,GitHub 默认会阻止暴露私人邮箱。
解决方案:
# 使用 GitHub 提供的匿名邮箱
git config user.email "用户名@users.noreply.github.com"
# 重新签署最近的提交
git commit --amend --reset-author --no-edit
# 再次推送
git push6.2 Actions 失败:找不到 lock 文件
错误信息:
Dependencies lock file is not found解决方案:
npm install # 生成 package-lock.json
git add package-lock.json
git commit -m "添加 package-lock.json"
git push6.3 页面空白
可能原因:
base配置错误(最常见)- 构建失败
- 路由配置问题(SPA 应用)
排查步骤:
# 查看最近的 Actions 运行
gh run list
# 查看详细日志
gh run view 运行ID --log
# 检查 Pages 配置
gh api repos/用户名/仓库名/pages6.4 自定义域名不生效
检查 DNS 是否正确:
nslookup journal.hongrui-fu.online如果显示 找不到记录,说明 DNS 还没配置好或还在传播中。
DNS 传播通常需要几分钟,但有时可能长达 48 小时。可以用 https://dnschecker.org/ 查看全球 DNS 状态。
6.5 显示错误的域名
症状:配置了 journal.xxx.com,但显示的是 blog.old-domain.com
原因:你的主仓库 用户名.github.io 配置了旧域名,会影响所有项目。
解决方案:
# 检查主仓库配置
gh api repos/用户名/用户名.github.io/pages
# 移除旧域名
gh api repos/用户名/用户名.github.io/pages -X PUT -f cname=""第七章:命令速查表
首次部署(完整流程)
# 1. 初始化 Git 仓库
git init
git add .
git commit -m "Initial commit"
# 2. 登录 GitHub CLI(只需一次)
gh auth login
# 3. 创建远程仓库并推送
gh repo create 仓库名 --private --source=. --push
# 4. 生成 lock 文件
npm install
git add package-lock.json
git commit -m "添加 package-lock.json"
git push
# 5. 创建 .github/workflows/deploy.yml(内容见第四章)
# 6. 提交工作流配置
git add .
git commit -m "添加 GitHub Actions 部署配置"
git push
# 7. 启用 Pages
gh api repos/用户名/仓库名/pages -X POST -f build_type=workflow
# 8. 查看部署状态
gh run watch配置自定义域名
# GitHub 端
gh api repos/用户名/仓库名/pages -X PUT -f cname="子域名.域名.com"
# 修改 vite.config.ts 的 base 为 '/'
# 提交更改
git add .
git commit -m "配置自定义域名"
git push
# DNS 端:添加 CNAME 记录(在域名服务商控制台)
# 类型: CNAME, 名称: 子域名, 值: 用户名.github.io日常更新
# 修改代码后
git add .
git commit -m "描述这次改了什么"
git push
# Actions 会自动构建并部署总结
回顾一下整个流程:
- Git 管理代码版本,记录每次修改
- GitHub 在云端存储代码
- GitHub Actions 自动执行构建(把 TypeScript/React 编译成浏览器能运行的文件)
- GitHub Pages 托管构建后的静态文件,变成可访问的网站
- DNS 把自定义域名指向 GitHub Pages 服务器
这些工具各司其职,组合起来形成了现代前端的自动化部署流程。一旦配置好,你只需要 git push,其他的全部自动完成。
希望这篇教程能帮你真正理解整个过程,而不只是照着命令敲。下次遇到问题,你就能自己分析和解决了。
参考链接
作者:Hongrui | 最后更新:2025年12月31日