Jenkins前端打包构建老项目拯救指南
最近由于要将一些老的项目部署流程规范化很多老的前端项目打包都会有奇奇怪怪得问题出现这边将一些坑记录下顺便也写下处理思路。前言一般来说前端镜像构建最主要得就是出包只要能出包问题基本解决了百分之八十剩下得都是比较机械固定得步骤。所以一般来说我都是先本地起一个虚拟机出包以后将调整好的编译语句放在jenkins上所以本篇文章主要也是针对前端编译出包这块。一般编译流程如下1.首先一般来说我们都是先看git项目得readme文档在这里你需要得到四个东西分别是涉及到得node版本编译命令打包命令以及是否是hbuilder构建得项目如果是hbuilder构建得这个打包比较麻烦需要在编译环境新建开发环境具体可以参看别的教程情况比较少这边不展开2.常规项目一般安装依赖包都是npm install 但是一般来说这个安装速度非常慢即使配置了国内得镜像仓库也并不会快很多所以我一般都是直接试用yarn install yarn builld 如果可以大功告成如果不行那么你可以蛮试下npm install npm run build 如果可以大功告成好常规思路基本说的差不多如果以上还不能解决你需要理解以下知识这边大概列一下。1.npm ci是个好东西这边援引下别的地方得解释此命令与 npm install 类似不同之处在于它旨在用于自动化环境例如测试平台、持续集成和部署——或任何您希望确保对依赖项进行全新安装的情况。 使用 npm install 和 npm ci 的主要区别是 项目必须有一个现有的 package-lock.json 或 npm-shrinkwrap.json。 如果包锁中的依赖项与 package.json 中的依赖项不匹配npm ci 将退出并出错而不是更新包锁。 npm ci 一次只能安装整个项目无法使用此命令添加单个依赖项。 如果 node_modules 已经存在它将在 npm ci 开始安装之前自动删除。 它永远不会写入 package.json 或任何包锁安装基本上是冻结的。从以上信息我们可以知道npm ci 不会修改lock文件与package.json文件同时严格按锁文件安装整棵项目树2.npm install --package-lock-only 这个也是个好东西--package-lock-only 是 npm 的一个布尔参数用于只生成或更新 package-lock.json 文件而不修改 node_modules。这在需要锁定依赖版本但不想重新安装依赖时非常有用。 例如如果你有现成的 node_modules但缺少 package-lock.json可以直接生成 npm install --package-lock-only --offline --package-lock-only仅生成/更新 package-lock.json忽略 node_modules。 --offline离线模式依赖从本地缓存或现有 node_modules 获取。 这样可确保生成的锁文件与当前依赖版本完全一致非常适合老项目或生产环境还原。 常见场景 从现有 node_modules 生成锁文件 当项目缺失 package-lock.json 时可基于生产环境的 node_modules 生成 npm install --package-lock-only --offline 仅更新锁文件而不安装依赖 在修改了 package.json 后只想同步更新锁文件 npm update --package-lock-only好综上--package-lock-only 是根据package.json确定要安装的包的版本然后创建一个package-lock.json 所以这个命令其实不在乎是否已经有 node_modules3.很多时候会有需要在package.json 中 用到overrides 这个字段这个字段主要在 npm 8 最新版上被支持npm 7 及以下的版本中并没有这个能力不过到还是有办法在旧版 npm 上用上这个能力如果一定要使用 好像也行具体参看百度这边不展开如果需要用我的建议是升级npm版本。4.关于npm 速度慢排查可以在npm install 后面加上 --verbose 这个主要是打印详细执行步骤的信息在这里的输出可以很清晰的看出问题卡在哪里。5.关于npm install 跟npm ci 得区别这边援引一篇文章写得不错链接如下npm install 与 npm ci 的区别与应用场景深解-腾讯云开发者社区-腾讯云大概总结下npm install 当项目存在锁文件时npm install会被锁文件驱动并遵循npm-shrinkwrap.json、package-lock.json、yarn.lock的优先级。 (npm Docs)任何会更新node_modules或package.json依赖的命令包含npm install都会自动同步已有的 lockfile。 (npm Docs)它描述 exact tree并服务于 subsequent installs 生成 identical trees。 (npm Docs)另外当npm检测到老版本 lockfile 时也可能在安装过程中自动升级 lockfile 内容以补齐缺失信息。 (npm Docs)简单来说npm install出的lock文件并不是一成不变的在相当的情况下还会改变lock的内容。npm ci :npm ci 不会修改lock文件与package.json文件同时严格按锁文件安装整棵项目树6.存在lock文件的情况下可能node版本跟npm版本不是很重要或者你可以用20的node打包14的老项目这是可能的。7.不同的环境可能下载的依赖不一样比如chromedriver 这个依赖会有linux版本或者windows版本直接从不同环境拉过来的可能不能直接用。8. .npmrc 这个文件会影响你下载依赖的仓库如果跟你预想的不一样多半是开发提交了这个文件9. npm版本最好跟lockversion匹配不然估计会碰到奇奇怪怪的bug好铺垫的差不多了现在说说实际可能的问题问题 一天一个呆瓜开发提交了老项目的代码同时可能会有不该交的文件交了然后该交的文件没交同时给你指定的npm版本为6.x 对于这个老东西你上了常规手段一打一个报错。好解决方案如下排查下git仓库是否存在lock文件一般这种老项目的切入点都是lock文件如果没有让开发生成一个推送git仓库常规来说到这步也就成了如果这部不行好多半是开发整错环境了这个时候你可以让你们对比下npm list的版本差异通常是因为两个环境的实际依赖版本不一样导致的好如果呆瓜开发不对比或者沟通不畅你可以考虑--package-lock-only手动生成下lock文件然后npm ci 但是这种情况一定要改package.json 这个是绕不过去的。如果开发还是不配合那就让他改代码把哪里报错改哪里补一条最近有打包镜像typescript类型的项目然后跑着跑着突然就发现打镜像寄了然后依赖下载都正常下载完以后报错EPERM EPERM: operation not permitted, write然后感觉有点莫名其妙构建期间使用的是默认root权限几经周折询问ai总结如下即使你已尝试了多种方法问题依旧原因在于这个权限错误是多个因素叠加的结果。 Alpine Linux 的严格权限检查你使用的 node:24-alpine 基础镜像其核心是 musl libc 库。与常用的 glibc 相比musl 对文件系统权限的检查更为严格。在解压和设置文件时间戳futime等操作时这种严格性可能触发权限错误。 Docker 文件系统的限制Docker 的镜像层是只读的。在构建过程中尽管最上层container layer是可写的但 pnpm 的一些底层操作可能因无法穿透到只读层而失败。 pnpm 自身的 bug在 pnpm 的某些版本如 v10.5.0中存在一个已知缺陷在执行配置操作时它会错误地尝试在根目录/ 下创建临时文件如 /.npmrc.X而普通用户甚至 root 在某些环境下没有根目录的写入权限从而导致 EPERM 错误。 问题的根源在于 Alpine Linux (musl libc)、Docker 文件系统机制以及 pnpm 特定版本缺陷这三者组合产生的不兼容性。然后遂换了base镜像由alpine镜像换到slim镜像解决。。。。这边随便总结下两个镜像的区别特性Alpine (如node:24-alpine)Slim (如node:24-slim)基础大小极小 (~5 MB)较小 (~50-80 MB)C 标准库musl libcglibc包管理器apkapt兼容性一般与许多预编译的二进制文件不兼容优秀与绝大多数 Linux 软件兼容性能在某些高并发场景下可能略低通常更稳定表现更好构建速度编译原生模块可能更慢通常更快安全漏洞组件极少攻击面小CVE 数量通常更少组件比 Alpine 多但比完整镜像少