前端工程化与 CI/CD 落地实践


作为一个既懂前端又懂服务器的工程师,最值钱的能力是把”代码”和”部署”打通。本文落地一条完整的 CI/CD 流水线:提交代码后自动 lint、测试、构建,打包成 Docker 镜像推送到仓库,再在服务器上用 Nginx 容器提供访问。整条链路跑通,就是实打实的工程化加分项。

一、为什么需要 CI/CD

没有 CI/CD 的项目常见痛点:

  • 每次发版手动 npm run build、手动 scp 上传,容易漏文件、传错环境;
  • 代码合并前没人跑测试,问题到线上才暴露;
  • 回滚靠”找上次的压缩包”,没有版本记录。

CI/CD 的价值一句话:把”人工容易出错”的环节全部自动化,让每一次提交都经过相同的、可复现的流水线。持续集成(CI)保证质量,持续交付/部署(CD)保证快速上线。

二、整体架构

开发者 push 代码
   │
   ▼
GitHub Actions(CI)
   ├── lint + unit test(质量门禁)
   ├── npm run build(构建产物)
   └── docker build + push(制作并推送镜像)
   │
   ▼
服务器(CD)
   └── docker pull + docker run(Nginx 容器提供服务)

三、前端配置:Dockerfile + Nginx

前端项目要能容器化,需要处理 SPA 的前端路由回退问题(否则刷新子页面 404,这是我在《vue-cli 项目在 nginx 下子页面刷新404》里讲过的经典坑)。

# 多阶段构建:先用 node 构建,再用 nginx 运行(镜像小)
# 阶段1:构建
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# 阶段2:运行
FROM nginx:1.27-alpine
# SPA 路由回退 + gzip 的 nginx 配置
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
# nginx.conf —— 解决 SPA 刷新 404,并开启 gzip 压缩
server {
    listen 80;
    server_name _;
    root /usr/share/nginx/html;
    index index.html;

    gzip on;
    gzip_types text/plain text/css application/javascript application/json;

    # 关键:所有找不到的文件回退到 index.html(前端路由)
    location / {
        try_files $uri $uri/ /index.html;
    }

    # 静态资源长缓存
    location /assets/ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}

npm ci 而不是 npm install:它会严格按照 package-lock.json 安装,保证 CI 环境与本地一致,且更快更可靠。

四、CI 流水线:GitHub Actions

在仓库创建 .github/workflows/deploy.yml

name: CI/CD

on:
  push:
    branches: [ main ]
  workflow_dispatch:   # 支持手动触发

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: 安装依赖
        run: npm ci

      - name: 代码规范检查
        run: npm run lint

      - name: 单元测试
        run: npm run test

      - name: 构建
        run: npm run build

      - name: 构建并推送 Docker 镜像
        run: |
          docker build -t my-app:$ .
          echo "$" | docker login -u "$" --password-stdin
          docker push my-app:$

      - name: 服务器部署(SSH 执行脚本)
        uses: appleboy/ssh-action@v1
        with:
          host: $
          username: $
          key: $
          script: |
            docker pull my-app:$
            docker stop my-app || true
            docker rm my-app || true
            docker run -d --name my-app -p 8080:80 my-app:$

敏感信息用 SecretsREGISTRY_USERSERVER_SSH_KEY 等一律存到仓库 Settings → Secrets,绝不能写进代码。这也是运维安全意识的一个加分体现。

五、回滚与灰度

有了镜像版本(用 commit sha 或 tag 标记),回滚就非常简单:

# 一键回滚到上一个版本
docker stop my-app && docker rm my-app
docker run -d --name my-app -p 8080:80 my-app:<旧版本sha>

更进阶的是蓝绿部署(两套环境切换)或金丝雀发布(灰度放量),配合 Nginx 的 upstream 负载均衡——这正好接上我之前写的《Nginx 负载均衡》文章。

六、总结:这条链路的面试价值

为什么这条流水线值得写进你的项目经历?

  1. 体现”全链路”思维:不是只会写前端,而是理解代码如何走到线上;
  2. 体现质量意识:lint + 单测作为质量门禁,防止烂代码合并;
  3. 体现运维能力:Docker 镜像、Nginx 配置、SSH 部署,正好是你擅长的领域;
  4. 体现可维护性:版本化、可回滚、自动化,这是团队协作和大项目最看重的。

面试讲项目时,能用一句话概括:”我搭建了一条从代码提交到 Docker 容器部署的全自动流水线,每次提交都会自动过 lint、单测、构建,并滚动发布到服务器,出问题能秒级回滚。”——这句话的含金量,远超”我会写 Vue 页面”。

结合我博客里的《Docker 常用命令》《Centos 安装 docker-compose》《Nginx 负载均衡》《基于 Docker 搭建 frp 内网穿透》等文章,你已经具备从开发到部署的完整知识闭环。


Similar Posts

Content