前端部署详解

cenweilings@163.com Lv2

CI/CD

🧠 核心概念:CI/CD是什么?

CI/CD 是现代软件工程中的一套最佳实践和方法论,旨在自动化软件的集成、测试和部署流程。它由两个部分组成:

CI - 持续集成 (Continuous Integration)

CD - 持续交付/持续部署 (Continuous Delivery / Continuous Deployment)

可以把 CI/CD 想象成一个全自动的软件装配流水线。开发者提交代码(如同送上原料),流水线会自动进行一系列质量检测、打包和发布,最终将合格的产品交付给用户。

🔧 详解两个部分

1. CI - 持续集成

核心思想: 开发者频繁地将代码更改合并到共享的主干分支(如每天多次)。每次合并都会自动触发一系列构建和测试,以便快速发现和修复错误。

CI流程

好处:

  • 快速发现错误:问题在引入后几分钟内就能被发现。
  • 减少集成冲突:频繁合并小批量代码,避免在发布前一次性合并大量代码带来的巨大冲突。
  • ✅ 提高代码质量**:自动化测试保障了代码标准。

2. CD - 持续交付 / 持续部署

CD 有两种细微差别的含义:

a) 持续交付 (Continuous Delivery)

核心思想: CI流程结束后,代码总是处于可随时、一键手动部署到生产环境的状态。

流程: 代码 -> CI -> 生成制品 -> 等待手动点击部署

b) 持续部署 (Continuous Deployment)

核心思想: 这是持续交付的更高阶段。只要代码通过所有测试流程,就自动地、无需人工干预地部署到生产环境。

流程: 代码 -> CI -> 生成制品 -> 自动部署到生产环境

可以这样理解:

  • 持续交付 = “软件已经打包好放在门口了,你随时可以签收(手动部署)。”
  • 持续部署 = “软件通过质检后,快递机器人自动送货上门(自动部署)。”

🛠️ CI/CD 工具链

整个流程依赖于一系列自动化工具,常见的工具有:

阶段 流行工具
源代码管理**** Git (GitLab, GitHub, Gitee)
CI/CD 流水线引擎 Jenkins, GitLab CI/CD, GitHub Actions, Drone
构建工具 Maven, Gradle (Java), npm, Webpack (JS), Make
测试工具 JUnit, Selenium, Jest, Cypress
部署工具 Ansible, Kubernetes, Docker, Terraform
监控工具 Prometheus, Grafana, ELK Stack

💡 为什么需要 CI/CD?它的价值是什么?

  1. 加速开发流程
    • 自动化代替手动操作,释放开发者的生产力。
    • 快速反馈,开发者能立即知道这次提交是否破坏了系统。
  2. 提高软件质量
    • 通过自动化测试在早期发现缺陷,修复成本远低于生产环境才发现。
    • 代码规范、安全漏洞扫描等流程被标准化。
  3. 降低发布风险
    • 小批量、频繁的发布使得每次变更的内容很少。如果出现问题,可以快速定位和回滚。
    • 传统的”半年发布一次,一次改动500个功能”的方式风险极高。
  4. 增强项目可见性
    • 每个人都能清晰地看到代码从提交到部署的整个状态,构建是否成功、测试是否通过。

✅ 总结

CI/CD 是一套通过自动化优化软件开发生命周期的实践,其核心目标是:

  • 更快的发布速度
  • 更高质量的软件
  • 更低的发布风险

它不是某个特定的工具,而是一种文化和流程的变革,是现代DevOps理念的核心支柱,已经成为中大型软件开发团队的标配。

OpenVpn与跳板机/堡垒机

🔧 什么是 OpenVPN 客户端?

OpenVPN 客户端是一个安装在您本地设备(如电脑、手机)上的软件程序

它的核心功能是:根据配置文件(.ovpn 文件),与远端的 OpenVPN 服务器建立一条加密的、安全的隧道连接。

  • 它是什么? 一个软件(例如:OpenVPN Connect、Tunnelblick等)。
  • 它在哪里运行? 在你的个人设备上(Windows PC, Mac, Linux, 手机)。
  • 它的作用? 创建加密通道,让你的所有或指定网络流量都通过这个通道流向VPN服务器。

就像一个专门的电话(客户端),用于拨打一个安全的号码(服务器)。


🖥️ 什么是跳板机?

跳板机(Jump Server / Bastion Host)是一台位于某个特定网络区域(如公司内网)的服务器

它的核心功能是:作为一个唯一的、受严格控制的访问入口,所有外部人员必须先连接到这台服务器,才能进一步访问目标网络内部的其他设备。

  • 它是什么? 一台物理或虚拟的服务器/计算机。
  • 它在哪里运行? 在目标网络的入口处(例如公司机房或公有云上)。
  • 它的作用? 提供访问桥梁和安全审计。所有操作都通过它进行,便于监控和记录日志。

就像是大楼的门卫室(跳板机),所有访客(用户)必须先在门卫室登记、核实身份,由门卫带领才能进入大楼内部(内网)。


🔄 它们如何协同工作?(两者的关系)

OpenVPN 客户端和跳板机通常配合使用,但它们扮演完全不同的角色。

工作流程分解:

阶段一:建立安全隧道(认证与连接)

  1. 配置加载:用户在自己的电脑上启动OpenVPN客户端软件,并加载管理员提供的 .ovpn配置文件。这个文件包含了连接所需的所有信息:
    • 跳板机的公网IP/域名
    • 加密算法和协议类型
    • CA根证书(用于验证服务器身份)
    • 客户端证书和私钥(用于向服务器证明自身身份)
    • 其他参数(如使用的端口、是否使用密码等)
  2. 发起连接:客户端根据配置,向跳板机的公网IP和指定端口发起TCP/UDP连接请求。
  3. TLS双向认证(最关键的安全步骤):
    • 服务器认证:跳板机上的OpenVPN服务端将自己的证书发给客户端。客户端用CA根证书验证服务器证书的有效性,确保连接的是真正的公司跳板机,而不是钓鱼服务器
    • 客户端认证:客户端将自己的证书和私钥签名发给服务器。服务器用CA根证书验证客户端证书,确保连接的是授权员工,而不是外人
    • 这个过程通常还辅以用户名/密码认证。
  4. 隧道建立:认证通过后,双方利用协商好的密钥,建立一条加密隧道。跳板机为客户端分配一个内网IP地址(如 10.8.0.100)。此时,用户的电脑在逻辑上已经“接入”了公司内网。

阶段二:访问内部资源(路由与转发)

  1. 发起访问请求:用户需要访问内网的一台Web服务器(192.168.1.100)。他在本地使用SSH命令:ssh developer@192.168.1.100
  2. 流量封装与路由
    • 客户端的操作系统会根据路由表规则,将所有发往 192.168.1.0/24 网段的流量,都指向OpenVPN创建的虚拟网卡。
    • OpenVPN客户端将原始的SSH数据包(TCP协议)整个加密并包裹(封装) 在一个新的数据包内,这个新数据包的目的地是跳板机的公网IP。
    • 这个加密后的数据包通过互联网发送到跳板机。
  3. 跳板机处理(流量枢纽):
    • 跳板机上的OpenVPN服务端解密收到的数据包,解出原始的SSH请求数据包。
    • 跳板机的操作系统内核根据其自身的路由表,发现这个目标是 192.168.1.100 的数据包需要从其内部网卡(如 eth0)发出。
    • 防火墙和访问控制:在转发前,跳板机上的防火墙规则(如 iptables)会进行检查,判断源IP(10.8.0.100)是否有权限访问目标IP(192.168.1.100)的22端口。通过后,才将数据包转发给目标Web服务器。
  4. 响应返回
    • Web服务器处理SSH请求后,将响应包发回给跳板机(因为请求的来源IP是跳板机)。
    • 跳板机收到响应后,再将其加密,通过隧道发回给远端的用户客户端。
    • 客户端解密后,得到原始的SSH响应,完成一次完整的交互。

🛡️ 核心价值与优势

这种架构的优势在于提供了双重安全性和极佳的可管理性

  1. 强身份认证:通过证书方式,同时验证了服务器和客户端的身份,避免了密码泄露和中间人攻击。
  2. 通信加密:所有数据在公网上传输时都是加密的,保证机密性。
  3. 访问隔离:跳板机成为唯一的入口,外部无法直接访问任何其他内网机器,攻击面最小化。
  4. 集中审计与管控:所有对内网的访问都必须经过跳板机,便于记录完整的操作日志监控会话统一设置访问权限策略。管理员只需要在跳板机上修改规则,就可以控制所有用户的权限。

结论:

  • OpenVPN客户端是您用来连接软件
  • 跳板机是您连接上去的那台服务器
  • OpenVPN是实现安全连接的方式之一,而跳板机是一种网络访问策略和架构

您可以不使用OpenVPN而用其他方式(如SSH)登录跳板机;也可以使用OpenVPN连接到一台不是跳板机的服务器(例如只是为了加密咖啡店的公共Wi-Fi流量)。

但当它们结合时,就构成了一个非常经典和强大的安全远程访问方案。

🧠 什么是堡垒机?

如果说「跳板机」是一个基础概念,那么「堡垒机」就是它的完全体、企业级、工业化的形态。

堡垒机(Bastion Host)是一种位于内部网络和外部网络之间的高性能、高安全性的专用服务器,其核心设计理念是 “网络要塞” 。所有内部设备的远程访问(如 SSH, RDP, SFTP)都必须通过它进行,它作为唯一的入口点,集中进行身份认证、授权、审计和监控

您可以把它想象成一个极其严格的银行金库门卫

  1. 唯一入口:所有人都必须从这个门进出。
  2. 严格安检:需要多重身份验证(工牌、指纹、密码)。
  3. 权限分明:你只能进入你有权限进入的区域(金库、柜台、办公室)。
  4. 全程监控:你进去后的一举一动都被全程录像,说了什么话(执行的命令)、拿了什么东西(传输的文件)都有记录。

🆚 堡垒机 vs. 简单跳板机:有何不同?

很多人会混用这两个词,但它们有本质上的区别:

特性 简单跳板机 (Jump Server) 堡垒机 (Bastion Host)
核心功能 网络转发、基础连接 4A管理:认证、授权、账号、审计
安全性 相对较低,依赖系统自身安全 极高,有专门的安全加固和防护
用户体验 命令行,原始 Web图形化界面,易于操作
权限控制 粗粒度(能/不能登录某台机器) 细粒度(能登录,且只能执行某些命令)
审计能力 基础日志(谁什么时候登录了) 强大审计** - **会话录像(全程录屏) - 命令记录(精确到每一条命令) - 文件传输记录
账号管理 分散在各台服务器上 统一账号管理,单点登录(SSO)
本质 一台功能单一的服务器 一套完整的安全运维管控系统

简单说:跳板机主要解决“怎么进去”的问题,而堡垒机在此基础上,更解决了“谁能进”、“能干什么”和“干了什么”的问题。


🛡️ 堡垒机的核心功能(4A管理)

1. 认证 (Authentication):“你是谁?”

  • 多种认证方式:支持密码、SSH密钥、动态令牌(如Google Authenticator)、LDAP/AD域集成、生物识别等。
  • 多因子认证 (MFA):强制要求使用两种及以上方式验证身份,极大提升安全性。

2. 授权 (Authorization):“你能干什么?”

  • 精细化的权限控制
    • 主机权限:允许用户访问哪些服务器(如:只能访问Web服务器,不能访问数据库服务器)。
    • 操作权限:允许用户执行哪些命令(如:可以执行 systemctl restart nginx,但不能执行 rm -rf /)。
    • 时间权限:允许用户在什么时间段内访问(如:只能在工作时间访问)。
  • 临时权限申请与审批:如果需要临时获得更高权限,可以通过工单系统申请,由管理员审批后自动授权,过期自动回收。

3. 账号 (Account):“你的身份是什么?”

  • 统一账号管理:在堡垒机上创建账号,即可映射到后端的多台服务器,无需在每个服务器上单独创建账号。实现了“一个堡垒机账号,访问所有授权资产”。
  • 托管服务器账号:服务器账号和密码可以由堡垒机托管,用户无需知道目标服务器的真实密码。

4. 审计 (Audit):“你干了什么?”(这是堡垒机的灵魂)

  • 会话录像 (Session Recording):** 像录屏一样,完整记录用户在目标服务器上的**所有操作过程,包括敲打的命令、返回的结果。无法抵赖。
  • 命令记录:详细记录执行过的每一条命令及其时间、来源IP。
  • 文件传输审计:记录所有通过SFTP/SCP/RDP上传和下载的文件日志。
  • 行为分析:对异常操作、危险命令(如 rmchmod)进行实时告警。

🏗️ 堡垒机的工作流程

下图以一个运维人员需要通过堡垒机修复网站为例,展示了其核心工作流程与4A功能:

堡垒机工作流程

🚀 常见的堡垒机方案

  1. 开源方案
    • Jumpserver:国内最流行的开源堡垒机,功能全面,对中文支持好,社区活跃。
    • Teleport:现代、轻量级,对云原生和Kubernetes环境支持良好。
    • Apache Guacamole:无客户端堡垒机,通过浏览器即可实现RDP、SSH、VNC等连接。
  2. 商业方案
    • 齐治堡垒机:国内老牌商业产品,市场份额大。
    • ** Cisco Secure Access (前Duo)**、CyberArk:国际知名的商业解决方案,功能强大,价格昂贵。

✅ 总结:为什么需要堡垒机?

  1. 安全第一:极大缩小了网络攻击面,保护了内部资产。
  2. 合规要求:满足等保2.0、ISO27001、GDPR等法规对运维审计的强制性要求。
  3. 权限清晰:实现最小权限原则,避免权限滥用。
  4. 责任界定:出现问题时,可以通过录像和日志快速定位责任人、还原事故现场。
  5. 运维效率:统一入口,简化了账号管理和访问流程。

简而言之,堡垒机是企业IT基础设施中不可或缺的安全与审计基石,尤其对于金融、政府、互联网等对安全性和合规性要求极高的行业来说,是标配产品。

OpenVpn+跳板机/堡垒机实现前端部署

这是一个非常经典的DevOps场景:OpenVpn+跳板机/堡垒机与前端工程部署结合起来,可以构建一个既安全又高效的部署流程。

这种架构的核心思想是:通过 OpenVPN 建立安全通道,通过跳板机/堡垒机作为统一、受控的入口,来执行部署操作。

🧩 核心架构与角色分工

在这种架构下,各个组件的职责非常清晰:

  1. OpenVPN Server负责建“路”。建立一条从开发者本地到部署环境的加密隧道,确保传输安全。
  2. 跳板机/堡垒机 (Bastion Host)负责管“门”和看“人”。它是唯一的部署操作入口,负责身份验证、权限控制和操作审计。
  3. 部署目标服务器负责住“应用”。这是最终运行前端项目(Nginx, Node.js 等)的服务器。
  4. CI/CD 工具 (可选但推荐)负责自动“开车”。例如 Jenkins、GitLab Runner 等,它们可以自动从仓库拉取代码、构建,并通过跳板机执行部署脚本。

整个从前端代码到部署上线的安全部署流程,如图所述:

OpenVpn+堡垒机结合前端部署

🛠️ 两种常见的部署模式

模式一:手动部署(适合小团队或初期)

流程: 开发者本地构建,然后通过跳板机手动上传文件。

本地构建

1
npm run build

这会在项目根目录生成 distbuild 文件夹,里面是静态文件(HTML, CSS, JS)。

  1. 连接VPN:确保 OpenVPN 客户端已连接,获得访问内网的权限。
  2. 通过跳板机上传文件
1
2
3
4
5
6
# 使用 scp 命令,通过跳板机转发到目标服务器
# 注意:跳板机需要配置SSH代理转发或用户有直接权限
scp -r -o 'ProxyJump user@jumpbox-ip' ./dist/* user@target-server-ip:/path/to/nginx/html/

# 或者使用更现代的 rsync
rsync -avz -e "ssh -J user@jumpbox-ip" ./dist/ user@target-server-ip:/path/to/nginx/html/
  1. 通过跳板机执行远程命令(如果需要):
1
2
3
4
# 登录跳板机,再从跳板机SSH到目标服务器
ssh user@jumpbox-ip
# 然后,在跳板机上执行
ssh user@target-server-ip "sudo nginx -s reload"

模式二:自动化部署(推荐,适合成熟团队)

流程: CI/CD 工具(如 Jenkins、GitLab CI)在检测到 Git 标签或特定分支更新后,自动完成所有步骤。

这是一个在 GitLab 中实现的自动化部署流程示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# .gitlab-ci.yml

stages:
- build
- deploy

build_production:
stage: build
image: node:16
rules:
- if: $CI_COMMIT_TAG # 通常在打标签时触发生产环境部署
script:
- npm install
- npm run build
artifacts:
paths:
- dist/ # 将构建产物传递给下一个阶段

deploy_to_production:
stage: deploy
image: alpine
rules:
- if: $CI_COMMIT_TAG
script:
- apk add --no-cache openssh-client rsync
# 使用 SSH 通过跳板机部署 (-o ProxyJump)
- rsync -avz --delete -e "ssh -o StrictHostKeyChecking=no -J $JUMPBOX_USER@$JUMPBOX_IP" dist/ $TARGET_SERVER_USER@$TARGET_SERVER_IP:/app/frontend/
# 通过跳板机执行远程命令,重启服务
- ssh -J $JUMPBOX_USER@$JUMPBOX_IP $TARGET_SERVER_USER@$TARGET_SERVER_IP "sudo systemctl reload nginx"

关键点:

  • $JUMPBOX_IP, $TARGET_SERVER_IP 等变量在 GitLab 的 CI/CD 设置中配置,避免写在代码里。
  • -J 参数是 SSH 的 代理跳跃,让 SSH 连接自动通过跳板机。
  • 堡垒机上需要存放 CI/CD 工具的 SSH 私钥,并且该密钥对目标服务器有访问权限。

⚙️ 部署前的重要准备工作

  1. 网络与权限配置
    • 确保 OpenVPN 服务器配置的路由规则,能让客户端访问到跳板机和目标服务器。
    • 在跳板机上为每个开发者或CI/CD服务创建账号,并配置严格的 SSH 密钥认证。
    • 配置跳板机的权限控制,确保用户只能访问特定的目标服务器。
  2. 堡垒机审计
    • 开启堡垒机的会话录制功能,记录所有通过它执行的部署命令和文件传输操作。一旦出问题,可以快速回放定位。
  3. 目标服务器配置
    • Nginx 配置示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
server {
listen 80;
server_name your-app.com;
root /app/frontend; # 前端文件部署的目录
index index.html;

# 处理 SPA 路由(如 Vue Router 的 history 模式)
location / {
try_files $uri $uri/ /index.html;
}

# 启用 gzip 压缩
gzip on;
gzip_types text/css application/javascript;
}

✅ 这种架构的优势

  1. 极致安全
    • 内部服务器完全不用暴露到公网,攻击者无法直接扫描到。
    • 所有部署操作都经过加密隧道严格审计
  2. 权限清晰
    • 开发者可能根本不知道目标服务器的密码,而是通过堡垒机的授权来访问,实现了权限最小化原则。
  3. 流程标准化
    • 无论是谁部署,都必须走同一个通道,执行相同的流程,减少了人为出错的可能。
  4. 可追溯性
    • 结合堡垒机的录像功能,可以清晰看到、在什么时间部署了什么执行了什么命令,便于故障排查和审计。

⚠️ 注意事项

  • 复杂度:初始设置比直接部署到公网服务器要复杂,但长期来看收益巨大。
  • 性能:如果 CI/CD 服务器在海外,而跳板机和目标服务器在国内,传输大量文件可能会慢,可以考虑在目标服务器上直接构建。
  • 成本:需要维护额外的跳板机/堡垒机组件。

总结: OpenVPN + 跳板机/堡垒机的部署模式,是企业级前端工程部署的最佳实践之一。 它通过牺牲一点点部署的便利性,换来了极高的安全性和规范性,非常适合对安全有要求的中大型项目。

SaaS使用的部署方式到底叫什么呢?

描述:没有使用jenkins,开发者通过堡垒机连入目标网络中通过git拉取代码并执行打包命令后生成dist或build文件夹,执行shell脚本将打包后的静态资源放到对应的目标服务器的路径下。

手动或半自动的基于堡垒机的 Git 拉取部署。

更具体地说,它属于 “Git-Based Deployment” 的一种演变形式,核心特点是通过安全堡垒机作为跳板,直接在目标环境或邻近网络中执行构建和部署

🧩 这种部署模式的详细流程拆解

yjt中SaaS的前端部署方式

它与纯CI/CD自动化部署的核心区别在于,流程图中黄色框线的部分(从 git push重启服务)完全由开发者手动触发和执行,而非由CI/CD工具(如Jenkins、GitLab CI)自动触发。


⚙️ 这种模式的特点

优点:

  1. 环境高度一致:在目标网络内进行构建,可以有效避免“在我本地是好的”这类问题。构建环境与生产环境一致(操作系统、Node版本等)。
  2. 安全性高:所有操作都通过受审计的堡垒机进行,目标服务器无需暴露到公网,也无需在本地和服务器之间开放额外的端口。
  3. 简单直接,无需复杂配置:不需要搭建和维护一整套CI/CD系统(如Jenkins),对于小团队或项目初期来说,成本更低,更轻量。
  4. 依赖少:只需要目标服务器上有Git和Node.js环境即可,不需要安装CI/CD的Agent。

缺点:

  1. 自动化程度低:严重依赖人工操作。开发者需要手动登录、执行一系列命令。容易因操作失误(比如忘了拉最新代码、在错误目录执行)导致部署失败。
  2. 无法实现真正的持续交付:部署过程不是自动触发的,通常需要人工干预,无法做到代码一提交就自动测试和部署。
  3. 可追溯性较差:虽然堡垒机会记录执行了哪些命令,但**“谁在什么时候部署了哪个版本的代码”** 这一信息没有与代码提交(Git Tag/Commit ID)强关联地记录下来。出问题时,需要回溯堡垒机日志。
  4. 效率较低:每次部署都需要在服务器上重新执行完整的构建过程,占用服务器资源,如果服务器性能不佳,构建时间会很长。

🚀 如何优化这种模式?

即使不引入Jenkins,也可以让这个流程变得更高效、更可靠:

1. 编写自动化部署脚本

将一系列手动命令写成一个Shell脚本,例如 deploy.sh,放在代码库根目录。

(这就是SaaS的做法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/bash
# deploy.sh

set -e # 遇到错误就退出

echo "1. Pulling latest code..."
git pull origin main

echo "2. Installing dependencies..."
npm install

echo "3. Building project..."
npm run build

echo "4. Backing up old version..."
tar -czf /app/backup/frontend-$(date +%Y%m%d-%H%M%S).tar.gz /usr/share/nginx/html/

echo "5. Deploying new version..."
rsync -av --delete ./dist/ /usr/share/nginx/html/

echo "6. Reloading Nginx..."
sudo systemctl reload nginx

echo "Deployment completed successfully!"

使用方式: 开发者登录后,只需要执行一条命令:

1
bash deploy.sh

2. 使用 Git Hooks(简单CI)

代码服务器的Git仓库上配置 post-receive Hook(例如使用Gitea),当收到push时,自动通知目标服务器执行拉取和部署脚本。这实现了简单的自动触发。

3. 使用 SSH 直接执行远程命令

开发者可以在本地电脑上通过一条命令完成部署,无需手动登录。

1
ssh -J user@jumpbox-ip user@target-server-ip "cd /path/to/project && bash deploy.sh"

4. 引入版本标记

在脚本中加入步骤,在部署成功后,给当前的提交打上一个Tag。

1
2
git tag deploy-$(date +%Y%m%d-%H%M%S)
git push origin --tags

这样就能清晰地知道生产环境对应的是哪个代码版本。


✅ 总结

这是一种 “基于堡垒机的半自动 Git 拉取部署”

  • 它不是什么? 它不是全自动的CI/CD(如Jenkins Pipeline),也不是传统的FTP上传部署。
  • 它是什么? 它是一种在安全约束条件下介于手动部署和全自动部署之间的实用型方案。

适用场景:

  • 内部系统、管理后台等对发布频率要求不高的项目。
  • 团队规模较小,尚未引入完整CI/CD工具链的初期阶段。
  • 对安全性要求极高,所有内部网络访问必须通过堡垒机的环境。

对于很多项目来说,这是一个非常好的起点。随着项目发展,当您觉得每次手动运行脚本也很麻烦时,就是考虑引入 GitLab CI/CD、Github Actions 等真正自动化工具的时候了。

待完善内容

  • CI/CD工具:jekins
  • Docker
  • Title: 前端部署详解
  • Author: cenweilings@163.com
  • Created at : 2025-03-25 16:00:00
  • Updated at : 2025-09-14 12:31:59
  • Link: https://blog-git-main-cenweilings-projects.vercel.app/2025/03/25/前端部署详解/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments