从零构建Vue3全栈工程化体系:脚手架、CI/CD与Docker部署实战

1. 项目缘起:为什么我们需要一个“猴子代码”?

在团队里待久了,你肯定遇到过这种场景:新项目启动,大家摩拳擦掌准备大干一场,结果光是搭建开发环境、配置构建工具、搞CI/CD流水线就花了两三天。每个人电脑上的Node版本、包管理器、IDE插件都不一样,张三能跑起来的项目,李四一拉下来就报错。好不容易本地跑通了,要部署上线又是一堆麻烦:手动构建、手动上传、手动重启服务,一个不小心就出线上事故。

这就是典型的前端工程化问题。它不是一个技术难题,而是一个效率和组织难题。我们需要的不是某个高深莫测的框架,而是一套能快速复制、稳定运行、并且团队里每个人都能无脑上手的“标准答案”。

这就是我折腾“MonkeyCode”的初衷。你可以把它理解为一个高度定制化的前端项目脚手架,但它又不止于脚手架。它更像一个“工程化解决方案包”,里面打包了从项目初始化、开发规范、构建优化,到自动化测试、容器化部署、CI/CD流水线的一整套东西。目标很简单: 用一套命令,生成一个“开箱即用”的现代化Vue 3项目,并且连上云端的生产线,实现代码提交即部署。

为什么叫“MonkeyCode”?一方面,它想做到像猴子一样“简单复制”就能用,降低心智负担;另一方面,也是提醒自己,工具是为人服务的,别把工程化搞成束缚创造力的枷锁。接下来,我就把这套从零到一的完整过程拆开给你看。

2. 核心蓝图:MonkeyCode工程化体系包含什么?

在动手写第一行代码之前,我们必须想清楚这个“解决方案包”到底要解决哪些具体问题。一个完整的前端工程化体系,远不止 vue create 那么简单。我把它分成了四个层次,像搭积木一样层层递进。

2.1 第一层:项目脚手架与开发规范

这是地基。我们需要一个能快速生成项目骨架的命令行工具。这个骨架必须包含:

  • 技术栈锁定 :Vue 3 + TypeScript + Vite 作为基础。这是当前性能和开发体验的黄金组合。Vite的闪电般的热更新和构建速度,是开发效率的保障。
  • 目录结构规范 :不是随意的 src 下面放所有东西。我会预设好 components , views , utils , apis , stores , types 等目录,并且约定它们的职责。比如, components 下再分 common (全局通用)和 business (业务相关),避免后期组件混乱。
  • 代码规范与质量门禁 :集成ESLint(语法检查)、Prettier(代码格式化)、Stylelint(样式检查)。关键一步是在 package.json scripts 里加入 "lint": "eslint . --ext .vue,.js,.ts,.jsx,.tsx --fix" "format": "prettier --write ." 。更狠的是配置Git Hooks(通过 husky lint-staged ),在 git commit 时自动检查暂存区的文件,不合格的代码根本提交不上去。
  • 基础工具封装 :封装好常用的工具函数(如请求拦截、日期格式化)、Vue组合式函数(如 usePagination 分页逻辑)和全局组件(如 Loading Message )。这些是避免重复造轮子的关键。

2.2 第二层:构建优化与产物管理

本地开发爽了,还得保证线上用户访问也快。这里涉及构建过程的深度定制。

  • 环境变量管理 :区分 development test production 等多环境。使用 dotenv 和Vite的环境变量模式( .env.development , .env.production ),将API地址、密钥等敏感信息与代码分离。
  • 构建策略优化
    • 依赖分包(ManualChunks) :将 vue vue-router pinia element-plus 等几乎不变的第三方库单独打包成一个 vendor 块,利用浏览器缓存。
    • 按需引入 :对于 Element Plus 这类大型UI库,必须配置自动按需引入,避免全量导入导致包体积膨胀。
    • 资源压缩与Hash :配置 vite build 选项,启用 terser 代码压缩,为静态资源(JS、CSS、图片)添加内容Hash,便于长期缓存和增量更新。
  • 产物分析 :集成 rollup-plugin-visualizer ,构建后会生成一个可视化的依赖分析图(一个HTML文件),让你一眼看出是哪个依赖让你的包变“胖”了,从而有针对性地优化。

2.3 第三层:自动化测试与质量保障

没有测试的代码就像没有刹车的汽车。对于MonkeyCode,我要求生成的模板必须内置测试能力。

  • 单元测试(Unit Test) :使用 Vitest (与Vite生态完美契合,速度快)替代Jest。为工具函数、组合式函数、纯逻辑组件编写单元测试。配置好测试覆盖率报告( --coverage )。
  • 组件测试(Component Test) :使用 @vue/test-utils 来测试Vue组件。模拟用户交互,断言组件渲染输出和状态变化。
  • 端到端测试(E2E Test) :使用 Cypress Playwright 。虽然重,但对于核心用户流程(如登录、下单)是必要的保障。在CI/CD流水线中,可以在部署前自动运行E2E测试。
  • 测试脚本集成 :在 package.json 中配置 "test:unit" , "test:e2e" 等脚本,并确保它们能在CI环境中无头(headless)运行。

2.4 第四层:CI/CD与自动化部署

这是将代码变动自动、安全、可靠地交付到用户手中的最后一步,也是工程化的终极体现。我选择的是 GitLab CI/CD + Docker + 云服务器 的组合,这也是目前中小团队最实用、成本可控的方案。

  • GitLab CI/CD :利用GitLab自带的CI/CD功能,通过在项目根目录创建 .gitlab-ci.yml 文件来定义流水线。它比Jenkins更轻量,与代码仓库集成度更高。
  • Docker容器化 :将应用和其运行环境(Node版本、Nginx配置等)一起打包成Docker镜像。这解决了“在我机器上能跑”的经典问题,保证了环境一致性。
  • 部署流程 :代码推送到特定分支(如 main ) -> 触发CI流水线 -> 运行测试 -> 构建Docker镜像 -> 将镜像推送到私有仓库(如阿里云容器镜像服务) -> 在服务器上拉取新镜像并重启容器。

这四层构成了MonkeyCode的完整闭环。下面,我们就从第一层开始,一步步实现它。

3. 从零手搓MonkeyCode CLI与Vue3项目模板

我们不依赖 vue-cli ,而是自己创建一个更灵活的CLI工具来生成项目。这能让我们对模板有百分百的控制权。

3.1 创建MonkeyCode CLI工具

首先,我们新建一个目录 monkeycode-cli

mkdir monkeycode-cli && cd monkeycode-cli
npm init -y

编辑 package.json ,设置入口文件并添加必要的依赖。我们不需要复杂的命令行框架,用Node.js原生 fs path 模块和 inquirer (用于交互式提问)就够了。

{
  "name": "monkeycode-cli",
  "version": "1.0.0",
  "description": "A CLI to generate Vue3 project with full engineering stack.",
  "main": "index.js",
  "bin": {
    "monkeycode": "./bin/monkeycode.js"
  },
  "scripts": {},
  "dependencies": {
    "inquirer": "^9.0.0",
    "chalk": "^4.1.2", // 用于终端彩色输出
    "fs-extra": "^11.1.0" // 增强的文件操作,比原生fs更好用
  }
}

创建 bin/monkeycode.js 文件,并在开头加上Shebang,让它成为可执行脚本。

#!/usr/bin/env node
console.log('Welcome to MonkeyCode!');
// ... 后续逻辑

通过 npm link 命令,将这个包链接到全局,这样我们就可以在任意地方使用 monkeycode 命令了。

npm link

3.2 设计交互式模板生成逻辑

CLI的核心逻辑是:询问用户几个关键选项 -> 根据选项选择模板 -> 将模板文件复制到目标目录 -> 动态替换模板中的变量(如项目名)。 我们在 index.js 中实现:

const inquirer = require('inquirer');
const fs = require('fs-extra');
const path = require('path');
const chalk = require('chalk');

const templates = {
  'vue3-standard': {
    url: 'https://github.com/your-org/vue3-standard-template.git', // 你的模板仓库地址
    description: 'Vue 3 + TypeScript + Vite + Pinia + Element Plus'
  },
  // 未来可以扩展更多模板,如 'vue3-mobile', 'react-standard'
};

async function createProject() {
  const answers = await inquirer.prompt([
    {
      type: 'input',
      name: 'projectName',
      message: '请输入项目名称:',
      default: 'my-vue3-app'
    },
    {
      type: 'list',
      name: 'template',
      message: '请选择项目模板:',
      choices: Object.keys(templates).map(key => ({
        name: `${key} (${templates[key].description})`,
        value: key
      }))
    },
    {
      type: 'confirm',
      name: 'useE2E',
      message: '是否需要集成E2E测试 (Cypress)?',
      default: false
    }
  ]);

  const targetDir = path.join(process.cwd(), answers.projectName);
  if (fs.existsSync(targetDir)) {
    console.log(chalk.red(`目录 ${targetDir} 已存在!`));
    process.exit(1);
  }

  console.log(chalk.blue(`正在创建项目 ${answers.projectName}...`));
  // 这里简化处理,实际应该去拉取远程模板或复制本地模板
  // 我们假设有一个本地的模板目录 `templates/vue3-standard`
  const templateDir = path.join(__dirname, 'templates', answers.template);
  await fs.copy(templateDir, targetDir);

  // 动态更新 package.json 中的项目名
  const pkgPath = path.join(targetDir, 'package.json');
  const pkg = require(pkgPath);
  pkg.name = answers.projectName;
  await fs.writeJson(pkgPath, pkg, { spaces: 2 });

  console.log(chalk.green(`项目创建成功!`));
  console.log(chalk.yellow(`cd ${answers.projectName}`));
  console.log(chalk.yellow(`npm install`));
  console.log(chalk.yellow(`npm run dev`));
}

createProject().catch(console.error);

这个CLI工具虽然简单,但已经具备了核心的交互和模板复制功能。真正的精髓在于我们准备好的那个 templates/vue3-standard 模板。

3.3 构建“开箱即用”的Vue3项目模板

现在,我们来精心打造这个模板。在 monkeycode-cli/templates/vue3-standard 目录下,创建一个标准的Vue3项目。

# 在模板目录下
npm create vue@latest . -- --typescript --router --pinia --eslint --prettier

根据提示选择Yes或No,我们这里已经预设了要TS、Router、Pinia、ESLint和Prettier。

接下来是深度定制:

1. 规范目录结构:

src/
├── apis/           # 所有API请求封装,按模块划分
├── assets/         # 静态资源
├── components/     # 组件
│   ├── common/     # 全局通用组件 (如Button, Modal)
│   └── business/   # 业务相关组件
├── composables/    # Vue组合式函数
├── layouts/        # 布局组件
├── router/         # 路由配置
├── stores/         # Pinia状态管理,按模块划分
├── styles/         # 全局样式、变量
├── types/          # TypeScript类型定义
├── utils/          # 工具函数
├── views/          # 页面视图组件
├── App.vue
└── main.ts

2. 配置ESLint + Prettier + Husky: 在生成的 .eslintrc.cjs .prettierrc 基础上,我们可以根据团队习惯调整规则。比如,强制使用 === ,变量命名必须使用 camelCase 等。 安装 husky lint-staged

npm install husky lint-staged -D
npx husky init

编辑 package.json ,添加 lint-staged 配置:

"lint-staged": {
  "*.{js,ts,vue}": [
    "eslint --fix",
    "prettier --write"
  ]
}

.husky/pre-commit 钩子文件中写入:

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-staged

这样,每次提交前都会自动检查和修复代码格式问题。

3. 集成Element Plus并配置按需导入:

npm install element-plus @element-plus/icons-vue
npm install -D unplugin-vue-components unplugin-auto-import

修改 vite.config.ts

import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

export default defineConfig({
  plugins: [
    // ...
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver()],
    }),
  ],
})

现在,你可以在组件中直接使用 ElButton ,而无需手动 import ,插件会自动处理。

4. 封装Axios请求实例: src/utils/request.ts 中,创建一个配置了拦截器、基础URL、超时时间的Axios实例,并导出。在 src/apis/user.ts 等文件中引入这个实例,定义具体的API函数。这样做的好处是统一错误处理、请求/响应拦截(如添加token、处理通用错误码)。

至此,一个具备基础工程化能力的Vue3项目模板就准备好了。CLI工具会将它复制到用户指定的目录。接下来,我们要为这个项目注入灵魂——自动化部署流水线。

4. 构建CI/CD流水线:GitLab CI + Docker实战

本地开发环境再完美,代码上不了线也是白搭。我们采用GitLab CI/CD,因为它与Git仓库无缝集成,配置简单直观。

4.1 编写 .gitlab-ci.yml 文件

在项目模板的根目录,我们预先创建好 .gitlab-ci.yml 文件。这个文件定义了整个CI/CD的流程(Pipeline),它由多个按顺序或并行执行的“作业(Job)”组成。

# .gitlab-ci.yml
stages:
  - test      # 测试阶段
  - build     # 构建阶段
  - deploy    # 部署阶段

variables:
  DOCKER_IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA # 定义镜像标签,使用提交哈希

# 缓存 node_modules,加速后续作业
cache:
  key: ${CI_COMMIT_REF_SLUG}
  paths:
    - node_modules/

# 1. 单元测试作业
unit-test:
  stage: test
  image: node:18-alpine # 使用Node官方镜像作为运行环境
  script:
    - npm ci --cache .npm --prefer-offline # 使用ci命令,它比install更严格,适合CI环境
    - npm run test:unit -- --coverage # 运行单元测试并生成覆盖率报告
  artifacts:
    when: always
    paths:
      - coverage/ # 将测试覆盖率报告保存为产物,可在GitLab界面查看
    reports:
      junit:
        - junit.xml # 如果有JUnit格式的测试报告,可以在这里配置
  only:
    - merge_requests # 仅在合并请求时运行,加快主分支推送速度
    - main

# 2. 构建作业
build:
  stage: build
  image: node:18-alpine
  script:
    - npm ci --cache .npm --prefer-offline
    - npm run build # 执行Vite构建,生成dist目录
  artifacts:
    paths:
      - dist/ # 将构建产物保存,后续部署作业可以使用
  only:
    - main # 仅当代码推送到main分支时触发构建

# 3. 构建并推送Docker镜像
docker-build-push:
  stage: build
  image: docker:20.10.16 # 使用Docker in Docker (dind)环境
  services:
    - docker:20.10.16-dind # 启动一个Docker守护进程服务
  variables:
    DOCKER_HOST: tcp://docker:2375
    DOCKER_TLS_CERTDIR: ""
  script:
    - echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY # 登录到容器镜像仓库
    - docker build -t $DOCKER_IMAGE_TAG . # 根据项目根目录的Dockerfile构建镜像
    - docker push $DOCKER_IMAGE_TAG # 推送镜像到仓库
  dependencies:
    - build # 声明依赖build作业,确保先有构建产物
  only:
    - main

# 4. 部署到服务器
deploy-to-server:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache openssh-client # 安装ssh客户端
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | ssh-add - # 添加存储在GitLab CI变量中的SSH私钥
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
  script:
    # 通过SSH连接到部署服务器,执行部署脚本
    - ssh -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "cd /path/to/deploy/script && ./deploy.sh $DOCKER_IMAGE_TAG"
  only:
    - main
  when: manual # 设置为手动触发,点击按钮才部署,增加安全性

这个配置文件定义了一个清晰的流水线:代码推送到 main 分支后,先运行单元测试(如果是合并请求也会触发),然后并行进行项目构建和Docker镜像的构建与推送,最后等待手动点击触发部署到服务器。

注意 :这里有几个关键的安全和配置点:

  1. $CI_REGISTRY_USER , $CI_REGISTRY_PASSWORD , $CI_REGISTRY , $SSH_PRIVATE_KEY , $SERVER_USER , $SERVER_IP 这些都是 GitLab CI/CD Variables 。你需要在GitLab项目的 Settings -> CI/CD -> Variables 中设置。 绝对不要 将这些敏感信息硬编码在YAML文件或代码里。
  2. docker-build-push 作业使用了 services: - dind ,这需要在GitLab Runner的配置中启用Docker in Docker特权模式。对于共享Runner,GitLab.com通常已配置好;对于自托管Runner,需要在 config.toml 中配置 privileged = true
  3. deploy-to-server 设置为 when: manual (手动触发),这是一个重要的安全实践,防止每一次提交都自动上线。你可以在GitLab Pipeline界面看到一个“播放”按钮,点击它才会执行部署。

4.2 编写项目Dockerfile

要让Docker镜像构建成功,我们需要在项目根目录提供一个 Dockerfile 。这里采用 多阶段构建 ,以减小最终镜像体积。

# Dockerfile
# 第一阶段:构建阶段
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production --cache .npm --prefer-offline
COPY . .
RUN npm run build

# 第二阶段:运行阶段
FROM nginx:alpine
# 将构建产物从builder阶段复制到Nginx的默认静态文件目录
COPY --from=builder /app/dist /usr/share/nginx/html
# 如果需要自定义Nginx配置,可以复制进去
# COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

这个Dockerfile非常高效。第一阶段用Node环境安装依赖并构建,生成 dist 目录。第二阶段使用轻量级的 nginx:alpine 镜像,只把第一阶段的构建产物复制过来,抛弃了Node环境的所有中间文件和源码,使得最终镜像非常小巧(通常只有几十MB)。

4.3 编写服务器端部署脚本

最后,我们需要在部署服务器上准备一个简单的Shell脚本 deploy.sh ,GitLab CI会通过SSH远程执行它。

#!/bin/bash
# deploy.sh
set -e # 遇到错误立即退出

IMAGE_TAG=$1 # 从CI传入的镜像标签,如 registry.example.com/group/project:abc1234

echo "开始部署,镜像标签: $IMAGE_TAG"

# 1. 拉取最新的镜像
docker pull $IMAGE_TAG

# 2. 停止并删除旧容器(如果存在)
CONTAINER_NAME="my-vue3-app"
if [ "$(docker ps -aq -f name=$CONTAINER_NAME)" ]; then
    echo "停止并移除旧容器..."
    docker stop $CONTAINER_NAME
    docker rm $CONTAINER_NAME
fi

# 3. 运行新容器
echo "启动新容器..."
docker run -d \
  --name $CONTAINER_NAME \
  --restart always \ # 设置容器总是重启,应对服务器重启等情况
  -p 8080:80 \ # 将宿主机的8080端口映射到容器的80端口
  $IMAGE_TAG

# 4. 清理旧的、无用的Docker镜像,释放磁盘空间
echo "清理无用镜像..."
docker image prune -f

echo "部署完成!"

将这个脚本放在服务器的某个路径下(如 /path/to/deploy/script/ ),并赋予执行权限 chmod +x deploy.sh 。当GitLab CI的 deploy-to-server 作业触发时,就会通过SSH执行这个脚本,完成服务的更新。

5. 避坑实录:那些我踩过的“猴子坑”

工程化的道路从来不是一帆风顺的。下面分享几个我在搭建这套体系时遇到的典型问题和解决方案,希望能帮你省下几个小时甚至几天的调试时间。

5.1 GitLab Runner 注册与配置的“网络迷踪”

问题:在自托管服务器上安装GitLab Runner后,执行作业总是卡在 Preparing environment 或直接失败。 排查过程:

  1. 检查Runner状态 sudo gitlab-runner status ,确保服务是 running 的。
  2. 查看Runner日志 sudo gitlab-runner run 在前台运行,观察实时日志。发现错误信息是 dial tcp x.x.x.x:443: i/o timeout
  3. 网络分析 :Runner需要连接GitLab服务器(通常是 gitlab.com 或你的私有地址)来获取作业。服务器可能因为防火墙或网络策略无法访问外网。
  4. 解决方案
    • 方案A(如果有网络权限) :为服务器配置正确的HTTP/HTTPS代理。在Runner的配置文件(通常是 /etc/gitlab-runner/config.toml )中,找到对应的Runner,添加 environment = ["http_proxy=http://your-proxy:port", "https_proxy=http://your-proxy:port"]
    • 方案B(内网环境) :搭建一个内网GitLab实例,并将Runner注册到内网地址。这是最稳定可靠的方案。
    • 方案C(使用Shell Executor) :如果只是简单项目,可以将Runner的执行器(executor)从 docker 改为 shell 。这样作业会在Runner机器本身的Shell中运行,避免了Docker网络问题,但牺牲了环境隔离性。

心得 :CI/CD工具链的网络连通性是第一步,也是最容易出问题的一步。务必先确保Runner能稳定“回连”到GitLab。

5.2 Docker镜像构建缓慢与体积膨胀

问题:每次构建Docker镜像都要好几分钟,而且镜像越来越大。 根因分析:

  1. 没有合理利用Docker缓存 :Dockerfile的每一条指令都会生成一个镜像层。如果 COPY . . 放在了 npm install 之前,那么任何源码文件的改动都会导致缓存失效,需要重新安装所有 node_modules
  2. 构建上下文(Build Context)过大 docker build . 命令中的 . 会把当前目录所有文件(包括 node_modules , .git , 日志文件等)发送给Docker守护进程,如果文件很多很大,传输和准备就会很慢。
  3. 最终镜像包含了构建工具 :如果你用 FROM node:18 作为最终运行镜像,它会包含完整的Node和npm,而运行一个Vue编译后的静态站点根本不需要这些。

优化方案(即我们上面采用的方案):

  1. 调整Dockerfile指令顺序 :把变化频率低的指令放前面(如 COPY package*.json ./ RUN npm ci ),变化频率高的指令放后面(如 COPY . . )。
  2. 使用 .dockerignore 文件 :在项目根目录创建 .dockerignore ,忽略不需要的文件。
    node_modules
    .git
    .DS_Store
    *.log
    .env.local
    dist
    
  3. 采用多阶段构建 :正如我们之前的Dockerfile所示,第一阶段用完整Node环境构建,第二阶段只复制构建产物到轻量级Nginx镜像中,最终镜像体积可能只有原来的1/10。

5.3 CI/CD流水线中的环境变量“捉迷藏”

问题:在GitLab CI作业中, npm run build 能成功,但构建出的页面访问API时却指向了 localhost 。 排查过程:

  1. 检查代码,发现API地址是通过 import.meta.env.VITE_API_BASE_URL 获取的。
  2. 在本地 .env.production 文件中明明配置了 VITE_API_BASE_URL=https://api.myapp.com
  3. 查看GitLab CI构建日志,发现构建命令是直接 npm run build ,没有指定模式。
  4. 根本原因 :Vite(或类似的构建工具)在构建时,会从 当前Shell进程的环境变量 .env 文件中读取 VITE_ 开头的变量。在CI环境中, .env.production 文件可能不存在,或者Shell中没有设置这些变量。

解决方案: 在 .gitlab-ci.yml build 作业中,通过 variables 关键字注入环境变量。

build:
  stage: build
  variables:
    VITE_API_BASE_URL: "https://api.myapp.com" # 在这里定义
    # 或者更安全地从GitLab CI变量中读取:
    # VITE_API_BASE_URL: $PRODUCTION_API_URL
  script:
    - npm run build

这样,在CI执行 npm run build 时, VITE_API_BASE_URL 就被正确设置了。

重要提醒 :永远不要在代码仓库中提交包含真实密码、密钥的 .env 文件。 .env.example 可以提交,用于说明需要哪些变量。真实的生产环境变量只应通过CI/CD平台的安全变量功能或服务器环境来设置。

6. 进阶与扩展:让猴子代码更“智能”

基础流程跑通后,我们可以考虑一些进阶优化,让整个体系更健壮、更高效。

6.1 基于Git Tag或分支的差异化部署

目前的流水线只监听 main 分支。在实际开发中,我们可能有 develop (开发环境)、 staging (预发布环境)、 main (生产环境)等多个分支。 可以在 .gitlab-ci.yml 中利用 rules 关键字进行更精细的控制:

docker-build-push:
  # ... 其他配置
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      variables:
        ENVIRONMENT: "production"
        DOCKER_IMAGE_TAG: $CI_REGISTRY_IMAGE:prod-$CI_COMMIT_SHORT_SHA
    - if: $CI_COMMIT_BRANCH == "staging"
      variables:
        ENVIRONMENT: "staging"
        DOCKER_IMAGE_TAG: $CI_REGISTRY_IMAGE:staging-$CI_COMMIT_SHORT_SHA
      when: manual # 预发布环境可以手动触发构建

然后在构建脚本或Dockerfile中,根据 ENVIRONMENT 变量使用不同的环境配置文件(如 .env.staging )。

6.2 集成代码扫描与安全检测

除了单元测试,可以在CI中集成静态代码安全扫描(SAST)和依赖漏洞扫描。

  • 使用 npm audit :在 package.json 的脚本中添加 "audit": "npm audit --audit-level=high" ,并在CI的 test 阶段执行它。如果发现高危漏洞,可以让流水线失败。
  • 集成SonarQube :对于更全面的代码质量分析,可以配置一个 sonar 作业,在构建后运行SonarScanner,将分析结果上传到SonarQube服务器,从复杂度、重复率、代码坏味道、安全漏洞等多个维度评估代码质量。

6.3 部署回滚与监控

自动化部署了,也要能快速回滚。一个简单的回滚策略是:

  1. 在服务器上,每次部署新镜像前,给当前正在运行的容器打一个标签,例如 my-app:previous
  2. 如果新版本出现问题,只需执行一个回滚脚本,将服务重新指向 my-app:previous 镜像即可。
  3. 更成熟的做法是使用Kubernetes的滚动更新和版本管理功能,可以做到无缝升级和秒级回滚。

监控方面,可以在Docker容器中集成应用性能监控(APM)工具的Agent,或者在服务器层面使用Prometheus+Grafana来监控容器资源使用情况、应用接口健康状态等。

折腾完这一整套,从输入 monkeycode create my-project 到代码提交后自动部署上线,整个过程已经高度自动化。它可能不是最完美的方案,但绝对是一个能立刻用起来、并且能随着团队成长而不断演进的坚实起点。工程化的最终目的不是炫技,而是让开发者能更专注于创造业务价值,而不是在环境配置和部署琐事上浪费时间。希望这套“猴子代码”的思路,能给你带来一些切实的启发。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值