云端部署

用 Vite 做一个习惯打卡单页应用,连接 GitHub 后让 Vercel 自动部署

用 Vite 做一个习惯打卡单页应用,连接 GitHub 后让 Vercel 自动部署:每个分支、每个拉取请求都有自己的预览网址,合并到 main 才更新正式站。页面底部显示当前是 preview 还是 production,刷新任何子页面都不会 404。

BINBHO · 图文教程

用 Vite 做一个习惯打卡单页应用,连接 GitHub 后让 Vercel 自动部署:每个分支、每个拉取请求都有自己的预览网址,合并到 main 才更新正式站。页面底部显示当前是 preview 还是 production,刷新任何子页面都不会 404。

先看清成品

成品是一个 Vite 项目。本文已用 Vite 8.3.4 实际构建:设置 VITE_VERCEL_ENV=preview 构建后,产物里确实写入了 preview;vite preview 本地预览时直接访问 /stats 返回 200。本文环境没有 Vercel 和 GitHub 账号,没有实际连接仓库,也没有生成预览部署。

注意:Vercel 的免费 Hobby 计划仅限个人、非商业用途(官方 Hobby 页面和公平使用准则写明),商业项目需要 Pro 计划。各计划额度以官方页面为准。

做完之后你会得到什么?

成果 说明
打卡应用 两个页面:今天、统计,数据存在浏览器
前端路由 History API,网址是 /stats 而不是 #/stats
SPA 回退 vercel.json 把所有路径重写到 index.html
预览部署 每个分支和拉取请求一个网址
环境标识 页面显示 preview / production

需要准备哪些环境?

项目 要求 说明
Vercel 账号 Hobby 免费计划即可 用 GitHub 账号注册最方便
Node.js 20 或更高 本文使用 22.23.3
Vercel CLI npm i -g vercel 本文核对时最新版为 65.0.0
GitHub 仓库 可选 连接后每次推送自动部署

第一步:怎样建项目?

1. 项目结构

habit-spa/
├── index.html
├── src/main.js
├── vercel.json
├── package.json
└── .gitignore

2. package.json

{
  "name": "habit-spa",
  "private": true,
  "type": "module",
  "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview" },
  "devDependencies": { "vite": "^8.3.4" }
}

3. index.html

<!doctype html>
<html lang="zh-CN">
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>习惯打卡</title></head>
<body>
  <nav><a href="/" data-link>今天</a> · <a href="/stats" data-link>统计</a></nav>
  <main id="app"></main>
  <footer id="env"></footer>
  <script type="module" src="/src/main.js"></script>
</body>
</html>

4. src/main.js

// 单页应用:用 History API 切换页面,数据存 localStorage
const KEY = 'habits-v1';
const HABITS = ['喝水 8 杯', '运动 30 分钟', '读书 20 页'];
const today = () => new Date().toLocaleDateString('sv'); // YYYY-MM-DD
const load = () => JSON.parse(localStorage.getItem(KEY) || '{}');
const save = (d) => localStorage.setItem(KEY, JSON.stringify(d));

function todayPage() {
  const d = load(); const done = d[today()] || [];
  return `<h1>今天 ${today()}</h1>` + HABITS.map((h) =>
    `<label><input type="checkbox" data-h="${h}" ${done.includes(h) ? 'checked' : ''}> ${h}</label><br>`).join('');
}

function statsPage() {
  const d = load();
  const rows = HABITS.map((h) => `<li>${h}:${Object.values(d).filter((x) => x.includes(h)).length} 天</li>`).join('');
  return `<h1>累计打卡</h1><ul>${rows}</ul>`;
}

const routes = { '/': todayPage, '/stats': statsPage };

function render() {
  const page = routes[location.pathname] || (() => '<h1>页面不存在</h1>');
  document.getElementById('app').innerHTML = page();
}

document.addEventListener('click', (e) => {
  const a = e.target.closest('a[data-link]');
  if (a) { e.preventDefault(); history.pushState(null, '', a.href); render(); }
});
document.addEventListener('change', (e) => {
  const h = e.target.dataset.h; if (!h) return;
  const d = load(); const set = new Set(d[today()] || []);
  e.target.checked ? set.add(h) : set.delete(h);
  d[today()] = [...set]; save(d);
});
window.addEventListener('popstate', render);

// 构建时注入的环境标识:预览部署和正式部署显示不同
document.getElementById('env').textContent = `环境:${import.meta.env.VITE_VERCEL_ENV ?? 'local'}`;
render();
要点 说明
VITE_VERCEL_ENV Vercel 文档说明,系统环境变量加上 VITE_ 前缀即可在 Vite 构建时读取,值为 preview、production 或 development
toLocaleDateString('sv') 得到 2026-10-21 这样的本地日期
data-link 拦截站内链接,不刷新页面

5. vercel.json

{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
}

没有这个重写,直接打开或刷新 https://…/stats 会 404,因为服务器上没有 stats 这个文件。

6. .gitignore

node_modules
dist
.vercel
.env*.local

第二步:怎样本地运行?

npm install
npm run dev

打开终端显示的地址,勾选几项,切到“统计”页确认天数增加。然后验证构建:

VITE_VERCEL_ENV=preview npm run build
npx vite preview

本文实际构建输出:

dist/index.html                0.40 kB │ gzip: 0.31 kB
dist/assets/index-BtSGPHD1.js  1.76 kB │ gzip: 1.04 kB
✓ built in 42ms

第三步:怎样接入 GitHub 自动部署?

1. 推送到 GitHub

git init && git add . && git commit -m "init"
git branch -M main
git remote add origin git@github.com:你的用户名/habit-spa.git
git push -u origin main

2. 在 Vercel 导入

Vercel 控制台 Add New → Project,选择这个仓库。框架会自动识别为 Vite,构建命令 npm run build、输出目录 dist,保持默认,点 Deploy。

3. 体验预览部署

git checkout -b dark-mode
# 随便改一处文字
git commit -am "试试新标题" && git push -u origin dark-mode

在 GitHub 上为这个分支开拉取请求,Vercel 机器人会在评论里贴出预览网址。打开后页面底部显示 环境:preview;合并到 main 后,正式网址显示 环境:production。

4. 按环境设置不同的变量

如果以后要接后端,可以给不同环境配置不同地址:

vercel env add VITE_API_BASE preview
vercel env add VITE_API_BASE production

注意:所有 VITE_ 开头的变量都会被打包进前端代码,任何人都能看到,不要放密钥。

出问题时该怎么调?

1. 刷新子页面 404

确认 vercel.json 在项目根目录并且已提交。

2. 页面显示“环境:local”

线上出现这个值,说明构建时没读到变量。到部署详情的构建日志确认使用的是 Vite 框架预设;改了环境变量后需要重新部署。

3. 构建失败

本地先 npm run build。常见原因是 Node 版本太旧,可在项目 Settings → Build and Deployment 选择 Node 版本。

常见问题怎么处理?

现象 原因 解决方法
预览网址别人打不开 开启了部署保护 在项目设置里调整,或登录后访问
数据换浏览器就没了 存在 localStorage 需要同步就接入后端
拉取请求没有预览评论 没装 Vercel GitHub 应用权限 在 GitHub 设置里授权该仓库
资源 404 改了 base 路径 部署在根路径时保持默认
想回滚 新版本有问题 Deployments 里对旧版本使用 Instant Rollback

项目资源

用途 地址
Vite on Vercel https://vercel.com/docs/frameworks/frontend/vite
部署环境 https://vercel.com/docs/deployments/environments
Git 集成 https://vercel.com/docs/git
vercel env 命令 https://vercel.com/docs/cli/env
Vite 环境变量 https://vite.dev/guide/env-and-mode
vercel.json 配置 https://vercel.com/docs/project-configuration

建议先在本地跑通两个页面,再推送 main 完成第一次部署。

然后专门开一个分支练习“改动 → 预览 → 合并”的流程,熟悉之后所有项目都可以按这个方式上线。