老项目中 npm 更改为 pnpm

86 阅读5分钟

原因: npm和yarn都会有又大又慢的node_modules,最大的问题是 扁平化的node_modules,扁平化虽然解决了依赖地狱问题,但是它也带来了新的问题

1、幽灵依赖,eg:当安装了一个A包,这个A包自己依赖了B包,因为扁平化B包也会被提升到node_modules的根目录,产生的问题就是,你的package.json 里没有声明B包,但是可以引入B包且能正常使用,(万一一天A包升级,不在引入B包,项目就有可能崩溃,甚至不知道B是从哪里来的)

2、磁盘空间的巨大浪费 如果你的电脑上有10个项目,这10个项目都依赖A包,那么再npm和yarn的模式下,你的磁盘上就会存10份A包,造成磁盘的浪费

3、安装速度的瓶颈 虽然npm和yarn都有缓存机制,但是在安装依赖时他们仍然需要大量的I/O操作,去复制和移动这些文件,项目越大安装速度越慢

pnpm的解决方法

1、彻底告别幽灵依赖

在pnpm的node_modules中,你只会看到再package.json中声明的哪些依赖。

项目中A包,它自己所依赖的B包,会被存放在node_modules/.pnpm/ 这个特殊的目录中,

然后通过符号链接(Symbolic Link) 的方式,连接到A包的node_modules中。这就意味着你在项目中想访问B包根本访问不到

2、磁盘的节约

pnpm会再电脑上创建一个全局内容可寻址存储区(content-addressable store),通常在用户主目录下的 .pnpm-store 里

电脑上所有项目的所有依赖,都只会在这个全局仓库里,实实在在的只存一份

当你的项目中需要依赖A包的时候,pnpm不会去复制一份到node_modules,而是通过硬链接(Hard Link) 从全局仓库链接一份过来,硬链接几乎不占用磁盘空间,所以无论有多少个项目依赖了A包,都只会有一份A包,省磁盘空间

3、极速的安装体验

大部分依赖是通过链接的方式实现,而不是复制,所以pnpm在安装依赖时,大大减少了I/O操作,安装速度飞一般的感觉

Monorepo,即“单个仓库多项目管理”,是一种项目代码管理方式,它将多个项目或模块的代码集中管理在一个仓库中。这种方式有助于简化代码共享、版本控制、构建和部署等方面的复杂性,并提供更好的可重用性和协作性

利用pnpm workspace功能,实现一个高效的多项目管理方案

一、根目录下 创建 pnpm-workspace.yaml

packages:
  # 指定根目录直接子目录中的包
  # - 'main'
  # # packages/ 直接子目录中的所有包
  # - 'packages/*'
  # components/ 子目录中的所有包
  - 'src/modules/**'
  # 排除测试目录中的包
  # - '!**/test/**'pnpm

2、npm run installProject 中 installProject文件

(1)移除符号链接(软链)步骤

(2) 移除解压 node_modules.zip 的步骤

(3)保留配置文件的修改

  • 缺少安装:pnpm add -w @vue/babel-helper-vue-jsx-merge-props element-resize-detector
  • client 下需要装一个http-errors pnpm add http-errors --filter kikyo-bff
  • app3 下缺少 pnpm add core-js@3.25.5 --filter kikyo-custom-app3
  • ###client 下缺少一个client 文件夹 (待排查)
  • ###kikyo-release下缺少一个 client.json (待排查)
  • ###client 下 www.js 没有复制进去(待排查)
  • 3、需要重新跑一次pnpm i

4、vue ui 项目管理器(需要各个模块编译之后才能访问)

image.png

image.png

image.png

image.png

image.png

image.png

问题:代码更改后,vue ui 没有自动编译

文件的复制
//sourceFilePath:源文件的完整路径(如 /data/image.jpg)
//destinationFolderPath:目标文件夹路径(如 /backups)
//callBack:复制完成后的回调函数(可选)

function copyFileUtils(sourceFilePath, destinationFolderPath,callBack) {
    // 确保目标文件夹存在
    if (!fs.existsSync(destinationFolderPath)) {
        fs.mkdirSync(destinationFolderPath, { recursive: true });
    }
    const destinationFilePath = path.join(destinationFolderPath, path.basename(sourceFilePath));
    //  **作用**:拼接目标文件的完整路径。
    //`path.basename(sourceFilePath)`:提取源文件名(如 `image.jpg`)。
    // `path.join(...)`:将目标文件夹路径和文件名合并(如 `/backups/image.jpg`)。
    //### 文件的复制
    fs.copyFile(sourceFilePath, destinationFilePath, (err) => {
        if (err) {
            console.error('文件复制失败:', err);
        } else {
            console.log('文件复制成功!');
            if(callBack){
                callBack()
            }
        }
    });
}


//从当前文件所在目录(`__dirname`)出发,向上回退两级目录(`../../`),再进入 `src/modules/client`。
copyFileUtils(path.join(__dirname, '../../src/modules/client/settings/develop/www.js'), path.join(__dirname, '../../src/modules/client'), () => {
  console.log('client模块核心代理www.js已就绪')
})

fs.existsSync(path)

fs.existsSync(path): 验证文件是否存在。path为要验证的文件路径

fs.mkdirSync

fs.mkdirSync(path,{recursive:true}) 创建目标文件夹

recursive: true 表示递归创建多层目录(类似 mkdir -p)。

path.basename

返回最后一部分path.basename(path, [,suffix])

path - 路径

suffix - 要删除的后缀,(可选)

path.join 拼接路径

const path = require('path')  

path.join('/a', 'b', 'c', './', 'd')  // /a/b/c/d
path.join('/a', 'b', 'c', '../', 'd')  // /a/b/d
path.join('/a', 'b/c', 'd')  // /a/b/c/d

__dirname

__dirname 是指获取当前文件在当前项目中的准确路径

fs.readFileSync

jenkins配置

原版备份

nodejs

export MAVEN_HOME=/app/soft/apache-maven-3.6.3 export NODE_HOME=/app/jenkins/tools/jenkins.plugins.nodejs.tools.NodeJSInstallation/nodejs-14.18.3/ #export NODE_HOME=/app/jenkins/tools/jenkins.plugins.nodejs.tools.NodeJSInstallation/nodejs-16.19.0/ export PATH=NODEHOME/bin:{NODE_HOME}/bin:PATH

cd WORKSPACEif["WORKSPACE if [ "isDeleteClientFile" = "YES" ] ; then rm -rf ./client fi

npm config set registry=nexusdev.fsfund.com/repository/…

npm install npm run installProjectProduction npm run vcProjectProduction NODE_ENV=production #npm run {module} NODE_ENV=production #npm run start m={module} NODE_ENV=production config=${config}

解决WORKSPACE/client目录被删除,编译时缺少sqlite3,又无法通过nexus安装问题,以下步骤需要手工到jenkinsWORKSPACE/client目录被删除,编译时缺少sqlite3,又无法通过nexus安装问题,以下步骤需要手工到jenkins的WORKSPACE下执行

#cd /app/jenkins/workspace/kikyo-chat-client-docker/client #export http_proxy=squidtest.fsfund.com:3128 #export https_proxy=squidtest.fsfund.com:3128

当pnpm 已安装

nodejs

export MAVEN_HOME=/app/soft/apache-maven-3.6.3 export NODE_HOME=/app/jenkins/tools/jenkins.plugins.nodejs.tools.NodeJSInstallation/nodejs-14.18.3/ #export NODE_HOME=/app/jenkins/tools/jenkins.plugins.nodejs.tools.NodeJSInstallation/nodejs-16.19.0/ export PATH=NODEHOME/bin:{NODE_HOME}/bin:PATH

cd WORKSPACEif["WORKSPACE if [ "isDeleteClientFile" = "YES" ]; then rm -rf ./client fi

设置 pnpm 的 registry

pnpm config set registry nexusdev.fsfund.com/repository/…

安装项目依赖

pnpm install

运行生产环境的项目安装脚本

pnpm run installProjectProduction

运行生产环境的构建脚本

pnpm run vcProjectProduction NODE_ENV=production #pnpm run {module} NODE_ENV=production #pnpm run start m={module} NODE_ENV=production config=${config}

解决WORKSPACE/client目录被删除,编译时缺少sqlite3,又无法通过nexus安装问题,以下步骤需要手工到jenkinsWORKSPACE/client目录被删除,编译时缺少sqlite3,又无法通过nexus安装问题,以下步骤需要手工到jenkins的WORKSPACE下执行

cd $WORKSPACE/client

export http_proxy=squidtest.fsfund.com:3128

export https_proxy=squidtest.fsfund.com:3128

当pnpm 未安装 This version of pnpm requires at least Node.js v18.12

nodejs

export MAVEN_HOME=/app/soft/apache-maven-3.6.3 export NODE_HOME=/app/jenkins/tools/jenkins.plugins.nodejs.tools.NodeJSInstallation/nodejs-18.18.0/ #export NODE_HOME=/app/jenkins/tools/jenkins.plugins.nodejs.tools.NodeJSInstallation/nodejs-16.19.0/ export PATH=NODEHOME/bin:{NODE_HOME}/bin:PATH

cd WORKSPACEif["WORKSPACE if [ "isDeleteClientFile" = "YES" ]; then rm -rf ./client fi

检查 pnpm 是否已安装

if ! command -v pnpm &> /dev/null; then echo "pnpm 未安装。正在安装 pnpm..." npm install -g pnpm else echo "pnpm 已安装,版本: $(pnpm --version)" fi

设置 pnpm 的 registry

pnpm config set registry=nexusdev.fsfund.com/repository/…

使用 pnpm 进行构建

pnpm install pnpm run installProjectProduction pnpm run vcProjectProduction NODE_ENV=production #pnpm run {module} NODE_ENV=production #pnpm run start m={module} NODE_ENV=production config=${config}

解决WORKSPACE/client目录被删除,编译时缺少sqlite3,又无法通过nexus安装问题,以下步骤需要手工到jenkinsWORKSPACE/client目录被删除,编译时缺少sqlite3,又无法通过nexus安装问题,以下步骤需要手工到jenkins的WORKSPACE下执行

#cd /app/jenkins/workspace/kikyo-chat-client-docker/client #export http_proxy=squidtest.fsfund.com:3128 #export https_proxy=squidtest.fsfund.com:3128