拿下奇怪的前端报错(二):nvm不可用报错`GLIBC_2.27‘‘GLIBCXX_3.4.20‘not Found?+ 使用docker构建多个前端项目实践

简介: 本文介绍了在多版本Node.js环境中使用nvm进行版本管理和遇到的问题,以及通过Docker化构建流程来解决兼容性问题的方法。文中详细描述了构建Docker镜像、启动临时容器复制构建产物的具体步骤,有效解决了不同项目对Node.js版本的不同需求。

有些前端的小伙伴可能会好奇,nvm是什么?这里接简单介绍下,它是一个Nodejs版本管理工具。为什么需要它呢?当然是需要多个Nodejs版本的时候,那什么时候需要多个Nodejs版本?那肯定是在有点年头的公司了,例如vue2的很多依赖都是在Nodejs14年代的,如果你升级到Node20,那很可能会报错。如果你用vite创建新项目,那也肯定是没法在Node14下运行。(如果你问为啥要Nodejs,欢迎留言,或者看一部它的纪录片哈)

迭代过快虽然能够享受到各种新科技,但对于很多公司来说,去适配nodejs版本也是不太值得投入的成本。ε=(´ο`*)))唉,想想前端就累呀

报错信息具体内容

# node -v
node: /lib64/libm.so.6: version `GLIBC_2.27' not found (required by node)
node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by node)
node: /lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found (required by node)
node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by node)
node: /lib64/libc.so.6: version `GLIBC_2.28' not found (required by node)
node: /lib64/libc.so.6: version `GLIBC_2.25' not found (required by node)

image.gif

nodejs都不可用,更别说构建了,如果构建不出东西,在这个依赖框架的年代,就相当于白干啊!突然怀念jquery的时代了,(#^.^#)

触发场景

  1. 有老的vue项目,需要nodejs14 (这个必须的,18+就构建不了!)
  2. 有新的vue3项目,需要nodejs20+ (vite需要的,ε=(´ο`*)))唉,自己开发是挺爽,但没想到CI这里出问题了哈)
  3. 必须要jenkins上部署和构建(jenkins跑在linux上,之前我被windows server版docker搞的头发掉了一大撮)
  4. 构建物必须是一个docker镜像,这几个项目放在一个镜像(就是要一次构建多个项目)

好像上面是这个时代比较通用的了,于是便很自然的安装了nvm,构建不同项目之前,用nvm切换下。

问题分析

但是,当我构建vue3项目是,就遇到上面的报错了。呃,搜索一通,么得什么头绪,我发现切回去node16就可以了,啊,竟然是版本问题,后面发现是宿主机的centos版本太低了,我的天!我没想到一个前端竟然遇到这个问题,也算是长姿势了!

于是这时候就有个解决办法了,那就是让运维的部署点高版本的centos吧!提了个需求,但不知道何时才能实现,等等等

解决办法

看到这里,问题大概就是找到了,也可以解决了:那就是升级centos版本

解决问题思路扩展

在docker容器内构建项目

但是我从第一性原理开始想,为啥我需要安装这个Nodejs呢?既然产出物是前端代码,部署又不需要这个nodejs(只需要一个nginx镜像+那些构建物),构建的时候能不能使用Docker构建,只要用不同的镜像去构建,不就可以了?说干就干。

下面是Dockerfile构建脚本: 阶段1构建,注意不同的项目修改自己node:版本 (这里用到了docker的多阶段构建,想了解的可以自己去研究,或许后期我会抽空介绍它的好处)

# 构建阶段
FROM node:20.16-alpine as builder
# 设置工作目录
WORKDIR /app
# 复制package.json和package-lock.json(如果存在)
COPY package*.json ./
# 安装项目依赖
RUN npm install
# 复制项目文件到工作目录
COPY . .
# 构建应用
RUN npm run build

image.gif

这个构建的产出物在镜像内的/app/dist,如果是直接docker部署,可以使用第二个stage直接复制到新的镜像中,但此时为考虑到某些场景需要提取出这个目录,就需要一个辅助的nodejs方法:

1. 构建

2. 启动容器

3. 复制到目标目录

启动临时容器复制到宿主机目录

一个全功能辅助的nodejs脚本

下面这个方法是一个build.cjs脚本内容,构建的时候,定义好需要构建的模块,然后node build.cjs就可以了,这里不展开。

function buildRunCopy(imageName, dockerfileDir, containerDist, outputDir) {
  // 生成容器名称
  const containerName = `container-${imageName}`;
  // 构建 Dockerfile 路径和输出目录的绝对路径
  const dockerfilePath = path.resolve(dockerfileDir, "Dockerfile");
  const hostDir = path.resolve(outputDir);
  try {
    // 创建宿主机目录(如果不存在的话)
    if (!fs.existsSync(hostDir)) {
      fs.mkdirSync(hostDir, { recursive: true });
    }
    // 构建 Docker 镜像
    console.log("Building Docker image...");
    execSync(
      `docker build -t ${imageName} -f ${dockerfilePath} ${dockerfileDir}`,
      {
        stdio: "inherit",
        cwd: dockerfileDir,
      }
    );
    console.log("Docker image built successfully.");
    // 运行 Docker 容器
    console.log("Running Docker container...");
    execSync(`docker run --name ${containerName} -d ${imageName}`);
    console.log("Docker container started successfully.");
    // 复制容器内的目录到宿主机目录
    execSync(`docker cp ${containerName}:/${containerDist} ${hostDir}`);
    console.log("Files copied successfully.");
  } catch (error) {
    console.error(`Error: ${error.message}`);
    throw error;
  } finally {
    // 停止并移除 Docker 容器
    try {
      console.log("Removing Docker container...");
      execSync(`docker rm -f ${containerName}`);
      console.log("Docker container removed successfully.");
    } catch (removeError) {
      console.error(`Error removing Docker container: ${removeError.message}`);
    }
  }
}

image.gif

脚本函数用法举例

下面就是一个例子:将项目某个test-app下面的项目进行构建,并将其构建物从/app/dist复制到原项目下面的dist目录

// 构建 build.cjs 
  const basePath = path.join(projectsBasePath, "test-app");
  const tmpDistFolder = path.join(basePath, "dist");
  console.info(`清理构建临时目录`);
  fs.rmSync(tmpDistFolder, { recursive: true, force: true });
  buildRunCopy("test-app", basePath, "/app/dist", basePath);

image.gif

然后就可以实现使用docker构建项目了,宿主机的nodejs只需要跑这个脚本,构建过程用到的nodejs是来自于容器内的,想用啥版本直接修改Dockerfile文件就可了


相关文章
|
5月前
|
人工智能 前端开发 Docker
从本地到云端:用 Docker Compose 与 Offload 构建可扩展 AI 智能体
在 AI 智能体开发中,开发者常面临本地调试与云端部署的矛盾。本文介绍如何通过 Docker Compose 与 Docker Offload 解决这一难题,实现从本地快速迭代到云端高效扩容的全流程。内容涵盖多服务协同、容器化配置、GPU 支持及实战案例,助你构建高效、一致的 AI 智能体开发环境。
539 2
从本地到云端:用 Docker Compose 与 Offload 构建可扩展 AI 智能体
|
5月前
|
JavaScript Docker 容器
使用Docker多阶段构建优化镜像大小
使用Docker多阶段构建优化镜像大小
453 100
|
5月前
|
缓存 安全 Linux
优化Docker镜像大小的多阶段构建实践
优化Docker镜像大小的多阶段构建实践
416 99
|
5月前
|
缓存 前端开发 Docker
Docker Layer Caching:加速你的容器构建
Docker Layer Caching:加速你的容器构建
|
5月前
|
安全 Go Docker
使用Docker多阶段构建优化镜像大小
使用Docker多阶段构建优化镜像大小
|
10月前
|
Docker 容器 Perl
云效flow构建docker镜像更换apt源为阿里镜像源
在 Dockerfile 中添加命令以更换 Debian 源为阿里云镜像,加速容器内软件包下载。核心命令通过 `sed` 实现源地址替换,并更新 apt 软件源。其中 `cat` 命令用于验证替换是否成功,实际使用中可删除该行。
2001 32
|
5月前
|
Java Docker 容器
使用Docker多阶段构建优化镜像大小
使用Docker多阶段构建优化镜像大小
260 8
|
10月前
|
监控 Java Go
无感改造,完美监控:Docker 多阶段构建 Go 应用无侵入观测
本文将介绍一种基于 Docker 多阶段构建的无侵入 Golang 应用观测方法,通过此方法用户无需对 Golang 应用源代码或者编译指令做任何改造,即可零成本为 Golang 应用注入可观测能力。
489 85
|
9月前
|
存储 消息中间件 前端开发
PHP后端与uni-app前端协同的校园圈子系统:校园社交场景的跨端开发实践
校园圈子系统校园论坛小程序采用uni-app前端框架,支持多端运行,结合PHP后端(如ThinkPHP/Laravel),实现用户认证、社交关系管理、动态发布与实时聊天功能。前端通过组件化开发和uni.request与后端交互,后端提供RESTful API处理业务逻辑并存储数据于MySQL。同时引入Redis缓存热点数据,RabbitMQ处理异步任务,优化系统性能。核心功能包括JWT身份验证、好友系统、WebSocket实时聊天及活动管理,确保高效稳定的用户体验。
527 4
PHP后端与uni-app前端协同的校园圈子系统:校园社交场景的跨端开发实践