侧边栏壁纸
  • 累计撰写 22 篇文章
  • 累计创建 5 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

SRE-Resume-完整指南-001

SRE Resume 前端项目 - 从代码到部署完整指南

这是什么项目?

想象一下:这是一份"会动的简历",就像把纸质简历变成了一个炫酷的交互式网站。

它用 React + TypeScript 构建,通过 Vite 打包,最后装进 Docker 容器里,像一份精美的数字名片,随时可以展示给面试官。

本文档将带你了解:

  • 🎯 项目架构与代码逻辑
  • ⚙️ 技术栈选型与配置
  • 📦 构建打包流程
  • 🐳 Docker 容器化部署
  • 🚀 性能优化策略

一、项目概览

1.1 项目信息

项目属性
项目名称 guobin-sre-resume
版本 1.0.0
Docker 镜像 sre-resume:v1.0.0
项目类型 单页应用(SPA)
用途 SRE 工程师个人简历展示网站

1.2 核心技术栈

技术栈就像做菜的食材清单

每个技术都是一道工序,组合起来才能做出美味的"简历网站"。

技术分类 技术选型 作用
前端框架 React 18.3.1 构建用户界面的核心框架
开发语言 TypeScript 5.6.3 提供类型安全,减少运行时错误
构建工具 Vite 5.4.11 快速开发服务器 + 高效打包
样式方案 Tailwind CSS 3.4.17 原子化 CSS,快速构建 UI
图标库 Lucide React 轻量级图标库
Web 服务器 Nginx 1.27-alpine 生产环境静态资源服务器
容器化 Docker 应用打包与部署

二、代码架构与逻辑

2.1 目录结构

sre-resume/
├── src/                    # 源代码目录
│   ├── components/         # React 组件
│   │   ├── Hero/          # 首屏英雄区域
│   │   ├── Projects/      # 项目展示
│   │   ├── ui/            # 通用 UI 组件
│   │   └── ...            # 其他业务组件
│   ├── data/              # 静态数据
│   │   └── resume.ts      # 简历数据配置
│   ├── hooks/             # 自定义 Hooks
│   ├── styles/            # 全局样式
│   ├── utils/             # 工具函数
│   ├── App.tsx            # 根组件
│   └── main.tsx           # 应用入口
├── dist/                  # 构建产物(npm run build 生成)
├── index.html             # HTML 入口
├── vite.config.ts         # Vite 配置
├── tailwind.config.js     # Tailwind 配置
├── Dockerfile             # Docker 构建文件
├── nginx.conf             # Nginx 配置
└── package.json           # 项目依赖配置

2.2 核心代码逻辑

2.2.1 应用入口(main.tsx)

入口文件就像房子的地基

所有代码都从这里开始构建,它是整个应用的起点。

// src/main.tsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
import './styles/index.css';

// 创建 React 根节点并渲染应用
createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <App />
  </StrictMode>
);

解读:

  • StrictMode:React 严格模式,帮助发现潜在问题
  • createRoot:React 18 新的渲染 API,支持并发特性
  • ./styles/index.css:全局样式入口

2.2.2 根组件(App.tsx)

根组件就像建筑的主体框架

它决定了整个网站的结构和加载策略。

核心特性:

  1. 懒加载(Lazy Loading)
// 滚动到对应区域再加载组件,缩减首屏 JS 体积
const Competencies = lazy(() =>
  import('./components/Competencies').then((m) => ({ default: m.Competencies }))
);

为什么这样做?

  • 首屏只加载必要的代码,其他组件等用户滚动到对应区域再加载
  • 减少首屏 JavaScript 体积,加快页面打开速度
  1. 空闲预取(Idle Prefetch)
// 首屏渲染后空闲时段预取所有懒加载 chunk
function useIdlePrefetch() {
  useEffect(() => {
    const run = () => {
      void import('./components/Competencies');
      void import('./components/Projects/Projects');
      // ... 预取其他组件
    };
    // 使用 requestIdleCallback 在浏览器空闲时预取
    if (window.requestIdleCallback) {
      window.requestIdleCallback(run, { timeout: 2000 });
    }
  }, []);
}

解读:

  • 首屏渲染完成后,利用浏览器空闲时间提前加载其他组件
  • 用户点击导航时不会看到 loading 状态,体验更流畅
  1. 组件结构
<div className="relative min-h-screen bg-bg-base text-text font-sans antialiased">
  <BackgroundFX />      {/* 背景特效 */}
  <Nav />               {/* 导航栏 */}
  <main>
    <Hero />            {/* 首屏英雄区域 */}
    <LazySection><Competencies /></LazySection>  {/* 核心能力 */}
    <LazySection><Projects /></LazySection>      {/* 项目经验 */}
    <LazySection><Experience /></LazySection>    {/* 工作经历 */}
    <LazySection><Skills /></LazySection>        {/* 技能列表 */}
    <LazySection><Branding /></LazySection>      {/* 个人品牌 */}
    <LazySection><Contact /></LazySection>       {/* 联系方式 */}
  </main>
</div>

2.2.3 数据配置(resume.ts)

数据配置就像简历的内容库

所有简历信息都集中在这里管理,方便维护和更新。

数据结构:

export type ResumeData = {
  meta: {              // 元信息
    name: string;
    targetPosition: string;
    targetCity: string;
    expectedSalary: string;
    education: string;
    yearsOfExperience: number;
  };
  basic: {             // 基本信息
    name: string;
    title: string;
    phone: string;
    email: string;
    blog: string;
    github: string;
    linkedin: string;
  };
  careerSummary: string;              // 职业总结
  coreCompetencies: CoreCompetency[]; // 核心能力
  skills: { ... };                    // 技能列表
  experience: Experience[];           // 工作经历
  projects: Project[];                // 项目经验
  certifications: Certification[];    // 证书
  personalBrand: { ... };             // 个人品牌
};

优势:

  • 类型安全:TypeScript 自动检查数据结构
  • 集中管理:所有简历数据在一处维护
  • 易于扩展:添加新字段只需修改类型定义

三、构建配置详解

3.1 Vite 配置(vite.config.ts)

Vite 就像一个超级打包机

它能把所有源代码、样式、图片打包成浏览器能直接运行的文件。

核心配置项:

export default defineConfig({
  plugins: [react(), inlineEntryCss()],  // 插件配置

  server: {
    host: '0.0.0.0',      // 允许外部访问
    port: 5173,           // 开发服务器端口
    strictPort: false,    // 端口被占用时自动尝试下一个
  },

  build: {
    assetsInlineLimit: 32768,  // 小于 32KB 的资源内联进 HTML
    cssCodeSplit: false,       // CSS 不分割,便于内联
    target: 'es2020',          // 目标浏览器版本
    rollupOptions: {
      output: {
        chunkFileNames: 'assets/[name]-[hash].js',  // 懒加载 chunk 命名
      },
    },
  },
});

自定义插件:CSS 内联

/**
 * 构建后把主入口 CSS 内联到 index.html 的 <style> 标签
 * 节省一次往返请求,关键路径资源合并
 */
function inlineEntryCss(): Plugin {
  return {
    name: 'inline-entry-css',
    apply: 'build',
    enforce: 'post',
    closeBundle() {
      // 读取 dist/index.html
      // 找到 style-*.css 文件
      // 将 <link> 标签替换为 <style> 标签
      // 删除原 CSS 文件
    },
  };
}

为什么这样做?

  • 减少 HTTP 请求:CSS 直接嵌入 HTML,浏览器不用再发一次请求
  • 加快首屏渲染:关键路径资源合并,减少网络往返时间

3.2 Tailwind 配置(tailwind.config.js)

Tailwind 就像一个 CSS 积木库

提供大量预定义的样式类,像搭积木一样快速构建 UI。

export default {
  content: ['./index.html', './src/**/*.{ts,tsx}'],  // 扫描哪些文件

  theme: {
    extend: {
      colors: {
        bg: {
          base: '#020617',    // 深色背景
          elev: '#0F172A',    // 卡片背景
          card: '#0B1220',    // 悬浮卡片
        },
        primary: {
          DEFAULT: '#22D3EE', // 主色调(青色)
          glow: 'rgba(34, 211, 238, 0.4)',  // 发光效果
        },
        // ... 更多颜色定义
      },

      fontFamily: {
        mono: ['JetBrains Mono', 'Fira Code', 'Menlo', 'monospace'],
        sans: ['Inter', 'Noto Sans SC', 'system-ui', 'sans-serif'],
      },

      animation: {
        'fade-in': 'fadeIn 0.6s ease-out',
        'slide-up': 'slideUp 0.6s ease-out',
        'cursor-blink': 'cursorBlink 1s step-end infinite',
        // ... 更多动画
      },
    },
  },
};

设计系统:

  • 统一的颜色体系:背景、文字、边框、状态色
  • 字体栈:代码字体(JetBrains Mono)+ 正文字体(Inter)
  • 动画库:淡入、滑入、闪烁等常用动画

四、构建打包流程

4.1 开发模式

# 启动开发服务器
npm run dev

# 预期输出:
#   VITE v5.4.11  ready in 300 ms
#   ➜  Local:   http://localhost:5173/
#   ➜  Network: http://192.168.1.100:5173/

# 解读:
# - 热更新:修改代码自动刷新页面
# - 快速启动:Vite 利用浏览器原生 ES 模块,无需打包即可启动

4.2 生产构建

# 构建生产版本
npm run build

# 实际执行的命令:
# tsc -b && vite build

# 解读:
# - tsc -b:TypeScript 类型检查 + 编译
# - vite build:打包生成 dist/ 目录

# 预期输出:
# dist/
# ├── index.html           # 入口 HTML(CSS 已内联)
# └── assets/
#     ├── index-[hash].js  # 主 JS 包
#     ├── Competencies-[hash].js  # 懒加载 chunk
#     ├── Projects-[hash].js      # 懒加载 chunk
#     └── ...              # 其他懒加载 chunk

构建产物特点:

  • ✅ CSS 内联到 HTML:减少 HTTP 请求
  • ✅ 代码分割:首屏 JS 体积最小化
  • ✅ 文件名带 hash:利于浏览器缓存
  • ✅ Tree Shaking:未使用的代码自动删除

4.3 预览构建结果

# 本地预览生产构建
npm run preview

# 预期输出:
#   ➜  Local:   http://localhost:4173/

# 解读:
# - 使用 Vite 预览服务器模拟生产环境
# - 验证构建结果是否正确

五、Docker 容器化部署

5.1 Dockerfile 解析

Dockerfile 就像一份安装说明书

它告诉 Docker 如何把应用打包成一个"集装箱",可以在任何地方运行。

# ============================================
# Dockerfile(单阶段,纯 nginx)
#   宿主机本地 npm run build 产出 dist/
#   Docker 只负责打包 nginx 镜像
# ============================================

FROM nginx:1.27-alpine

# 自定义 nginx 配置
COPY nginx.conf /etc/nginx/conf.d/default.conf

# 把宿主机已构建好的 dist 直接放进去
COPY dist /usr/share/nginx/html

EXPOSE 80

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD wget -qO- http://127.0.0.1/ >/dev/null 2>&1 || exit 1

LABEL org.opencontainers.image.title="sre-resume" \
      org.opencontainers.image.description="SRE Resume static site (nginx, single stage)" \
      org.opencontainers.image.version="1.0.0"

CMD ["nginx", "-g", "daemon off;"]

逐行解读:

指令 说明
FROM nginx:1.27-alpine 使用官方 Nginx 镜像(Alpine 版本,体积小)
COPY nginx.conf ... 复制自定义 Nginx 配置
COPY dist ... 复制构建产物到 Nginx 静态资源目录
EXPOSE 80 声明容器监听 80 端口
HEALTHCHECK 健康检查:每 30 秒访问一次首页
LABEL 添加镜像元数据(名称、描述、版本)
CMD 启动 Nginx(前台运行)

为什么用单阶段构建?

  • 构建在宿主机完成,Dockerfile 只负责打包
  • 镜像体积更小(不包含 Node.js)
  • 构建速度更快(利用宿主机缓存)

5.2 Nginx 配置(nginx.conf)

Nginx 就像一个超级接待员

它站在门口接收访客请求,把静态文件发给访客,还能处理路由跳转。

server {
  listen 80 default_server;
  server_name _;
  root /usr/share/nginx/html;
  index index.html;

  # 开启 gzip 压缩
  gzip on;
  gzip_vary on;
  gzip_min_length 1024;
  gzip_proxied any;
  gzip_comp_level 6;
  gzip_types
    text/plain
    text/css
    text/javascript
    application/javascript
    application/json
    application/xml
    image/svg+xml;

  # 静态资源强缓存(1 年)
  location /assets/ {
    expires 1y;
    add_header Cache-Control "public, immutable";
    access_log off;
    try_files $uri =404;
  }

  # SPA fallback:所有请求都走 index.html
  location / {
    try_files $uri $uri/ /index.html;
  }

  # 安全相关 headers
  add_header X-Content-Type-Options "nosniff" always;
  add_header X-Frame-Options "SAMEORIGIN" always;
  add_header Referrer-Policy "strict-origin-when-cross-origin" always;

  # 隐藏 nginx 版本
  server_tokens off;
}

核心配置解读:

  1. Gzip 压缩
gzip on;
gzip_comp_level 6;  # 压缩级别(1-9,6 是平衡点)
gzip_types text/plain text/css application/javascript;

效果:

  • 文本文件压缩率 60-80%
  • 减少网络传输时间
  • CPU 开销可控
  1. 静态资源缓存
location /assets/ {
  expires 1y;  # 缓存 1 年
  add_header Cache-Control "public, immutable";
}

为什么可以缓存 1 年?

  • Vite 构建时文件名带 hash(如 index-abc123.js
  • 文件内容变化 → hash 变化 → 文件名变化
  • 浏览器可以放心长期缓存
  1. SPA 路由支持
location / {
  try_files $uri $uri/ /index.html;
}

解读:

  • 用户访问 /projects 时,Nginx 找不到对应文件
  • try_files 将请求回退到 index.html
  • React Router 在前端处理路由
  1. 安全 Headers
Header 作用
X-Content-Type-Options: nosniff 防止 MIME 类型嗅探
X-Frame-Options: SAMEORIGIN 防止点击劫持
Referrer-Policy 控制 Referrer 信息泄露
server_tokens off 隐藏 Nginx 版本号

5.3 镜像构建与运行

构建镜像

# 构建镜像
docker build -t sre-resume:v1.0.0 .

# 预期输出:
# [+] Building 12.5s (8/8) FINISHED
#  => exporting to image
#  => => writing image sha256:abc123...
#  => => naming to docker.io/library/sre-resume:v1.0.0

# 解读:
# - 从当前目录(.)构建
# - 标签为 sre-resume:v1.0.0
# - 构建时间约 10-15 秒

运行容器

# 运行容器
docker run -d -p 8080:80 --name sre-resume sre-resume:v1.0.0

# 参数解读:
# -d:后台运行
# -p 8080:80:宿主机 8080 端口映射到容器 80 端口
# --name sre-resume:容器名称
# sre-resume:v1.0.0:使用的镜像

# 访问网站
# 浏览器打开 http://localhost:8080

查看容器状态

# 查看运行中的容器
docker ps

# 预期输出:
# CONTAINER ID   IMAGE              COMMAND                  STATUS          PORTS
# abc123def456   sre-resume:v1.0.0   "nginx -g 'daemon of…"   Up 2 minutes    0.0.0.0:8080->80/tcp

# 查看容器日志
docker logs sre-resume

# 查看健康状态
docker inspect --format='{{.State.Health.Status}}' sre-resume
# 输出:healthy

停止和清理

# 停止容器
docker stop sre-resume

# 删除容器
docker rm sre-resume

# 删除镜像
docker rmi sre-resume:v1.0.0

六、性能优化策略

6.1 首屏优化

首屏优化就像让客人进门就能看到精心布置的客厅

不用等所有房间都装修好,先展示最重要的部分。

优化策略 实现方式 效果
懒加载 React.lazy() + Suspense 首屏 JS 减少 60%
CSS 内联 自定义 Vite 插件 减少 1 次 HTTP 请求
空闲预取 requestIdleCallback 点击导航无 loading
字体异步 media=“print” + onload 字体不阻塞渲染

6.2 资源优化

优化策略 配置 效果
小资源内联 assetsInlineLimit: 32768 < 32KB 资源嵌入 HTML
代码分割 React.lazy() 按需加载,减少首屏体积
Tree Shaking Vite 自动 删除未使用代码
文件名 hash [name]-[hash].js 长期缓存

6.3 网络优化

优化策略 配置 效果
Gzip 压缩 nginx gzip on 文本压缩 60-80%
强缓存 expires 1y 静态资源长期缓存
HTTP/2 nginx 默认支持 多路复用,减少连接

6.4 性能指标

# 使用 Lighthouse 测试性能
lighthouse http://localhost:8080 --view

# 预期指标:
# Performance: 90+
# First Contentful Paint: < 1.5s
# Largest Contentful Paint: < 2.5s
# Total Blocking Time: < 200ms

七、常见问题与解决方案

7.1 构建问题

问题 1:TypeScript 类型错误

# 现象
npm run build
# Error: Type 'string' is not assignable to type 'number'

# 原因
# 类型定义与实际数据不匹配

# 解决方案
# 1. 检查 tsconfig.json 配置
# 2. 修复类型定义或数据
# 3. 重新构建

问题 2:构建产物体积过大

# 现象
# dist/assets/index-xxx.js 体积 > 500KB

# 排查步骤
# 1. 分析依赖体积
npx vite-bundle-visualizer

# 2. 检查是否引入了不必要的库
# 3. 使用懒加载拆分代码

7.2 Docker 问题

问题 1:镜像构建失败

# 现象
docker build -t sre-resume:v1.0.0 .
# Error: COPY failed: stat /var/lib/docker/tmp/dockerxxx/dist: no such file or directory

# 原因
# dist/ 目录不存在,未执行 npm run build

# 解决方案
npm run build
docker build -t sre-resume:v1.0.0 .

问题 2:容器启动后无法访问

# 现象
# curl http://localhost:8080 无响应

# 排查步骤
# 1. 检查容器是否运行
docker ps

# 2. 检查端口映射
docker port sre-resume

# 3. 查看容器日志
docker logs sre-resume

# 4. 进入容器检查
docker exec -it sre-resume sh
ls /usr/share/nginx/html  # 检查静态文件是否存在

7.3 Nginx 问题

问题 1:SPA 路由刷新 404

# 现象
# 访问 /projects 正常,刷新后 404

# 原因
# Nginx 找不到 /projects 文件

# 解决方案
# 确保 nginx.conf 中有:
location / {
  try_files $uri $uri/ /index.html;
}

问题 2:静态资源加载失败

# 现象
# 浏览器控制台:Failed to load resource: the server responded with a status of 404

# 排查步骤
# 1. 检查 dist/ 目录结构
ls -R dist/

# 2. 检查 Nginx 配置
docker exec -it sre-resume cat /etc/nginx/conf.d/default.conf

# 3. 检查文件权限
docker exec -it sre-resume ls -la /usr/share/nginx/html/assets/

八、完整部署流程

8.1 一键部署脚本

#!/bin/bash
# deploy.sh - 一键构建与部署脚本

set -e  # 遇到错误立即退出

echo "🚀 开始构建与部署..."

# 1. 安装依赖
echo "📦 安装依赖..."
npm install

# 2. 类型检查
echo "🔍 类型检查..."
npm run build

# 3. 构建 Docker 镜像
echo "🐳 构建 Docker 镜像..."
docker build -t sre-resume:v1.0.0 .

# 4. 停止旧容器(如果存在)
echo "🛑 停止旧容器..."
docker stop sre-resume 2>/dev/null || true
docker rm sre-resume 2>/dev/null || true

# 5. 启动新容器
echo "🚀 启动新容器..."
docker run -d -p 8080:80 --name sre-resume sre-resume:v1.0.0

# 6. 等待健康检查
echo "⏳ 等待健康检查..."
sleep 10

# 7. 检查状态
if [ "$(docker inspect --format='{{.State.Health.Status}}' sre-resume)" = "healthy" ]; then
  echo "✅ 部署成功!"
  echo "🌐 访问地址:http://localhost:8080"
else
  echo "❌ 部署失败,请检查日志:"
  docker logs sre-resume
  exit 1
fi

8.2 部署流程图

┌─────────────────┐
│  源代码(src/)  │
└────────┬────────┘
         │ npm run build
         ▼
┌─────────────────┐
│  构建产物(dist/)│
└────────┬────────┘
         │ docker build
         ▼
┌─────────────────┐
│  Docker 镜像     │
│  sre-resume:v1.0.0│
└────────┬────────┘
         │ docker run
         ▼
┌─────────────────┐
│  运行中的容器     │
│  Nginx + 静态文件 │
└────────┬────────┘
         │ 访问
         ▼
┌─────────────────┐
│   用户浏览器      │
│  http://localhost:8080 │
└─────────────────┘

九、总结

9.1 技术亮点

亮点 说明
🎯 类型安全 TypeScript 全栈类型检查
极致性能 懒加载 + CSS 内联 + 空闲预取
🐳 容器化 Docker 统一部署环境
🔒 安全加固 Nginx 安全 Headers + 版本隐藏
📦 体积优化 Tree Shaking + 代码分割

9.2 关键命令速查

# 开发
npm run dev              # 启动开发服务器

# 构建
npm run build            # 构建生产版本
npm run preview          # 预览构建结果

# Docker
docker build -t sre-resume:v1.0.0 .    # 构建镜像
docker run -d -p 8080:80 --name sre-resume sre-resume:v1.0.0  # 运行容器
docker logs sre-resume   # 查看日志
docker stop sre-resume   # 停止容器

# 排查
docker exec -it sre-resume sh          # 进入容器
docker inspect sre-resume              # 查看容器详情

9.3 文件清单

文件 作用 重要程度
[package.json](file:///root/package.json) 项目依赖配置 ⭐⭐⭐
[vite.config.ts](file:///root/vite.config.ts) 构建配置 ⭐⭐⭐
[tailwind.config.js](file:///root/tailwind.config.js) 样式配置 ⭐⭐
[Dockerfile](file:///root/Dockerfile) Docker 构建文件 ⭐⭐⭐
[nginx.conf](file:///root/nginx.conf) Nginx 配置 ⭐⭐⭐
[src/App.tsx](file:///root/src/App.tsx) 根组件 ⭐⭐⭐
[src/data/resume.ts](file:///root/src/data/resume.ts) 简历数据 ⭐⭐

十、扩展阅读

10.1 相关文档

10.2 学习路径

基础 → React → TypeScript → Vite → Tailwind → Docker → Nginx

文档版本: v1.0.0
最后更新: 2026-06-08
作者: 郭斌(SRE Engineer)

0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区