bash
echo "开始编译..."
CURRENT_PATH=`pwd`
CACHE_BASE_PATH=/data/cache/$PROJECT_NAME/$DEPOT_NAME/$CCI_JOB_NAME
# 根据参数决定是否清除缓存
if [ "$CLEAR_CACHE" = "true" ]; then
echo "清除 node_modules 缓存..."
rm -rf $CACHE_BASE_PATH/node_modules
fi
mkdir -p $CACHE_BASE_PATH/node_modules
docker run --network=host --rm \
-v $CURRENT_PATH:/root/workspace \
-v $CACHE_BASE_PATH/node_modules:/root/workspace/node_modules \
-v /data/cache/yarn/v6:/usr/local/share/.cache/yarn/v6 \
-e CI_ENV=1 \
coding-public-docker.pkg.coding.net/public/docker/nodejs:20-2024.01 \
/bin/bash -c "yarn install --frozen-lockfile && yarn build:sit && tar zcvf app-dom_front_sit.tar.gz dist"
echo "编译打包过程结束"
Shell 脚本逐行解析
脚本概述
这是一个用于 CODING CI/CD 构建流程的 Shell 脚本,主要功能是使用 Docker 容器编译前端项目并打包。
逐行代码解析
第 1 行:输出提示信息
bash
echo "开始编译..."
说明 : 使用 echo
命令输出提示信息到终端,告诉用户脚本开始执行了。
第 2 行:获取当前工作目录
bash
CURRENT_PATH=`pwd`
说明:
pwd
命令获取当前工作目录的完整路径- 反引号
pwd
表示命令替换,会执行 pwd 命令并将结果赋值给变量 CURRENT_PATH
变量保存了当前目录路径- 例如:
/root/workspace/your-project
第 3 行:构建缓存路径
bash
CACHE_BASE_PATH=/data/cache/$PROJECT_NAME/$DEPOT_NAME/$CCI_JOB_NAME
说明:
- 定义缓存基础路径变量
$PROJECT_NAME
、$DEPOT_NAME
、$CCI_JOB_NAME
是引用的环境变量(在脚本外部定义)- 这行构建了一个分层的缓存目录结构
- 例如:
/data/cache/myproject/frontend/build-job-01
第 5-9 行:条件清除缓存
bash
if [ "$CLEAR_CACHE" = "true" ]; then
echo "清除 node_modules 缓存..."
rm -rf $CACHE_BASE_PATH/node_modules
fi
说明:
第 6 行 - 条件判断:
if
条件判断语句开始[ ]
是测试命令(test 命令的另一种写法)"$CLEAR_CACHE"
引用环境变量(加引号防止变量为空时出错)=
是字符串相等比较运算符then
表示如果条件为真,执行下面的命令
第 7 行 - 输出提示:
- 输出清除缓存的提示信息
第 8 行 - 删除缓存:
rm -rf
递归强制删除目录及其内容-r
: 递归删除目录-f
: 强制删除,不提示确认
第 9 行 - 结束条件块:
fi
结束if
语句块(if
的反向拼写)
第 11 行:创建缓存目录
bash
mkdir -p $CACHE_BASE_PATH/node_modules
说明:
- 创建缓存目录
-p
参数:如果父目录不存在则自动创建,且如果目录已存在不报错- 确保缓存目录存在,即使之前被删除了
第 12-18 行:启动 Docker 容器并执行编译
bash
docker run --network=host --rm \
-v $CURRENT_PATH:/root/workspace \
-v $CACHE_BASE_PATH/node_modules:/root/workspace/node_modules \
-v /data/cache/yarn/v6:/usr/local/share/.cache/yarn/v6 \
-e CI_ENV=1 \
coding-public-docker.pkg.coding.net/public/docker/nodejs:20-2024.01 \
/bin/bash -c "yarn install --frozen-lockfile && yarn build:sit && tar zcvf app-dom_front_sit.tar.gz dist"
说明:
第 12 行 - Docker 运行命令:
docker run
: 启动 Docker 容器--network=host
: 容器使用宿主机的网络栈(容器可以直接访问宿主机网络)--rm
: 容器退出后自动删除\
是行连接符,表示命令在下一行继续
第 13-15 行 - 挂载卷:
-v
挂载卷(volume),将宿主机目录映射到容器内- 格式:
宿主机路径:容器内路径
- 第 13 行:挂载当前项目目录到容器的
/root/workspace
- 第 14 行:挂载 node_modules 缓存目录(实现依赖缓存复用)
- 第 15 行:挂载 yarn 全局缓存目录(加速 yarn 包下载)
第 16 行 - 设置环境变量:
-e
设置容器内的环境变量CI_ENV=1
告诉程序当前在 CI(持续集成)环境中运行
第 17 行 - 指定镜像:
- 指定要使用的 Docker 镜像
- 这是一个 CODING 提供的 Node.js 20 镜像(2024.01 版本)
第 18 行 - 容器内执行命令:
/bin/bash -c "命令"
: 在容器内执行 bash 命令&&
逻辑与操作符,前一个命令成功才执行下一个yarn install --frozen-lockfile
: 安装依赖,不更新 lockfile(保证依赖版本一致)yarn build:sit
: 执行 sit 环境的构建命令tar zcvf app-dom_front_sit.tar.gz dist
: 将 dist 目录打包成压缩文件z
: 使用 gzip 压缩c
: 创建归档文件v
: 显示详细过程f
: 指定文件名
第 19 行:输出完成信息
bash
echo "编译打包过程结束"
说明: 输出完成提示信息,表示整个编译打包流程已结束。
执行环境说明
脚本执行层次
bash
CODING 构建机器(宿主机)
├── Shell 脚本在这里执行
├── 代码目录(从 Git clone 过来)
└── 启动 Docker 容器
└── 容器内执行编译命令
执行流程
-
CODING 分配构建机器
- 构建机器上已安装 Docker
- 代码自动从 Git 仓库 clone 到工作目录
-
Shell 脚本在宿主机上运行
- 获取路径、准备缓存目录
- 根据条件清除旧缓存
-
启动 Docker 容器
- 容器提供隔离的、统一的编译环境
- 通过卷挂载访问宿主机上的代码和缓存
-
容器内执行编译
- 安装依赖、构建项目、打包产物
- 产物保存在挂载的宿主机目录中
为什么这样设计?
层级 | 作用 | 优势 |
---|---|---|
宿主机 | 运行脚本、管理资源、缓存 | 持久化缓存、灵活控制 |
Docker 容器 | 提供编译环境 | 环境一致性、版本锁定、隔离性 |
学习 Shell 脚本编写
1. 基础知识学习路径
- 变量和引用 : 变量定义、引用(
$VAR
)、命令替换(cmd
或$(cmd)
) - 条件判断 :
if-then-else
、测试表达式[ ]
和[[ ]]
- 循环结构 :
for
、while
、until
- 函数定义: 如何封装可重用代码
- 输入输出 :
echo
、read
、重定向(>
、>>
、<
)、管道(|
)
2. 常用命令掌握
文件操作:
ls
- 列出目录内容cd
- 切换目录mkdir
- 创建目录rm
- 删除文件/目录cp
- 复制文件mv
- 移动/重命名文件
文本处理:
grep
- 搜索文本sed
- 流编辑器awk
- 文本分析工具cut
- 剪切文本列sort
- 排序
系统信息:
pwd
- 显示当前目录whoami
- 显示当前用户ps
- 进程状态df
- 磁盘使用情况du
- 目录空间使用
3. 实践建议
- 从简单脚本开始: 写一些自动化日常任务的小脚本
- 阅读现有脚本: 分析项目中的脚本(就像这个)
- 使用
shellcheck
: 静态分析工具,帮助发现错误和不规范写法 - 学习最佳实践 :
- 变量加引号(
"$VAR"
)防止空格问题 - 使用
set -e
遇错即停 - 添加注释说明脚本功能
- 检查命令执行结果
- 变量加引号(
4. 推荐学习资源
- 在线教程 : Shell 脚本编程30分钟入门
- 书籍: 《Linux命令行与shell脚本编程大全》
- 实践平台: 在自己的项目中逐步应用
- 工具: 使用 VSCode + ShellCheck 插件
5. 针对这个脚本的学习点
- Docker 命令的使用: 理解容器化构建的优势
- CI/CD 环境变量的应用: 如何在构建流程中传递配置
- 缓存策略的实现: 优化构建速度的关键技术
- 构建流程的自动化: 从代码到产物的完整流程
常见问题
Q: 为什么要用 Docker 容器编译?
A: 保证编译环境的一致性,避免"在我机器上可以运行"的问题。容器提供了固定版本的 Node.js、系统库等依赖。
Q: 缓存机制如何工作?
A: 通过挂载宿主机的缓存目录到容器,node_modules 和 yarn 缓存可以在多次构建之间复用,大幅提升构建速度。
Q: --frozen-lockfile
有什么作用?
A: 确保安装的依赖版本与 yarn.lock 文件完全一致,不会自动更新依赖版本,保证构建的可重复性。
Q: 如何调试这个脚本?
A: 可以在脚本中添加 set -x
开启调试模式,或添加更多 echo
语句输出关键变量值。