Node脚本快速同步CNPM项目内用到的依赖

简介: 还是为了解决之前的问题;公司用CNPM作为内部私有仓,没有开启全量实时同步;所以有些包会相对落后,所以常用同步上游就显得很重要了;我想了想,每次都要手动去执行个别的包或者少量包的查询,操作太多了;原理还是遵循CNPM更新机制,可以看看上篇帖子哈~

网络异常,图片无法展示
|


前言


还是为了解决之前的问题;


公司用CNPM作为内部私有仓,没有开启全量实时同步;


所以有些包会相对落后,所以常用同步上游就显得很重要了;


我想了想,每次都要手动去执行个别的包或者少量包的查询,操作太多了;


原理还是遵循CNPM更新机制,可以看看上篇帖子哈~


考虑的点


  • 设置一个根路径,会自动检索下所有项目的packaeg.json(不包含node_modules)
  • 包括所有git subtree或者monorepo的package.json
  • 支持延时执行,一瞬间太多要同步的,会把内部搭建cnpm搞崩;
  • 同步过,再下一个执行同步的会自动过滤.也就是同步过同名包不会再发同步请求


使用成本极低,一个Node环境装几个常用的npm包;


环境


  • Node 14.16.1


效果图


网络异常,图片无法展示
|


源码


const globby = require('globby');
const fs = require('fs');
const path = require('path');
const axios = require('axios');
const chalk = require('chalk');
const isPlainObject = require('lodash/isPlainObject');
const options = {
    baseRootPath: '/Users/linqunhe/Code/ONES',  // 检索的根路径
    ignorePackage: ['@ones-ai', '@ones'], // 忽略的包名,就是不管有木有缓存都不同步
    delayTime: 10, // 每一次执行延时的时间,随着执行次数会递增 , 2000 = 2s
    maxRetry: 3, // 整个逻辑,中间有错误重试机制最大次数
    privateHostName: 'xxxxx', // 内网部署CNPM的访问域名
}
let cachePkgList = [];
let retryCount = 0;
const baseDep = ['npm', 'pnpm', 'yarn','recoil','typescript','mobx','mobx-react','react','redux','vite'];
function onesNpmSyncUpdate(pkgList, isArray = false) {
    const syncReq = (pkgName) => {
        return axios.put(`${options.privateHostName}/sync/${pkgName}?sync_upstream=true`).then(res => {
            if (res && res.data && res.data.ok) {
                const data = [
                    {
                        '执行时间': new Date().toISOString(),
                        'NPM包名': pkgName,
                        '同步状态': res.data.ok
                    }
                ]
                console.dir(data);
            }
        }).catch(err => {
            if (err) console.log('🍑 NPM包名', chalk.red(`${pkgName}`.padEnd(60)), '👀 同步状态:  ', chalk.green('false'));
        })
    }
    if (isArray) {
        pkgList.forEach(pkgName => {
            syncReq(pkgName)
        })
    }else{
      syncReq(pkgList);
    }
}
function arrayTypeData(array) {
    let decoratorsArr = []
    let normalArr = []
    for (let item of array) {
        if (item && typeof item === 'string') {
            if (item.startsWith('@') && item.includes('/')) {
                decoratorsArr.push(item)
            } else {
                normalArr.push(item)
            }
        }
    }
    return {
        decoratorsArr,
        normalArr
    }
}
function getPackageJsonDepKey(json = { dependencies: {}, devDependencies: {} }, ignore = []) {
    const { dependencies, devDependencies, peerDependencies } = json;
    let dependenciesKey = [];
    let devDependenciesKey = [];
    let peerDependenciesKey = [];
    if (dependencies && isPlainObject(dependencies)) {
        dependenciesKey = Object.keys(dependencies);
    }
    if (devDependencies && isPlainObject(devDependencies)) {
        devDependenciesKey = Object.keys(devDependencies);
    }
    if (peerDependencies && isPlainObject(peerDependencies)) {
        peerDependenciesKey = Object.keys(peerDependencies);
    }
    const allDepKey = [...new Set([...dependenciesKey, ...devDependenciesKey, ...peerDependenciesKey])]
    return allDepKey.filter(item => {
        for (const iterator of ignore) {
            if (item.indexOf(iterator) !== -1) {
                return false;
            }
        }
        return true
    })
}
function readPackageJson(path) {
    try {
        const data = fs.readFileSync(path, { encoding: 'utf8' });
        if (data && typeof data === 'string') {
            return JSON.parse(data)
        }
    } catch (error) {
        console.log('%c 🍦 error: ', 'font-size:20px;background-color: #EA7E5C;color:#fff;', path, error);
    }
}
function getUpdatePkgList(depKeyArr) {
    if (Array.isArray(depKeyArr) && depKeyArr.length <= 0) return [];
    let newUpdatePkgList = [];
    let uniDepKeyArr = [...new Set(depKeyArr)];
    if (Array.isArray(cachePkgList)) {
        if (cachePkgList.length <= 0) {
            cachePkgList = uniDepKeyArr;
            newUpdatePkgList = cachePkgList;
        } else {
            newUpdatePkgList = uniDepKeyArr.filter(item => !cachePkgList.includes(item))
            cachePkgList = [...new Set(cachePkgList.concat(uniDepKeyArr))]
        }
    }
    return newUpdatePkgList
}
function updatePkgList(depKeyArr, index) {
    const { decoratorsArr, normalArr } = arrayTypeData(depKeyArr);
    if (Array.isArray(normalArr) && normalArr.length > 0) {
        onesNpmSyncUpdate(normalArr, true)
    }
    if (Array.isArray(decoratorsArr) && decoratorsArr.length > 0) {
        decoratorsArr.forEach(item => {
            onesNpmSyncUpdate(item)
        })
    }
}
const sleep = (time) => new Promise((resolve) => {
    console.log(`🎳🎳🎳 ${chalk.green(`${time / 1000} s`)} 后执行更新操作!`);
    setTimeout(resolve, time);
})
const getExecFileBaseInfo = (abPath) => {
    const { base, dir, ext } = path.parse(abPath);
    const data = [{
        '执行时间': new Date().toISOString(),
        '所在目录': dir,
        '执行文件': base,
        '文件类型': ext,
    }]
    console.table(data);
}
const runScript = async (options) => {
    const pkgGlob = `${options.baseRootPath}/**/**/package.json`;
    let index = 1;
    let execTime = 1000;
    let depKeyArr = [...baseDep];
    try {
        for await (const path of globby.stream(pkgGlob, { ignore: ['**/node_modules'] })) {
            const packageJson = readPackageJson(path);
            if (packageJson && isPlainObject(packageJson)) {
                const packageDepKey = getPackageJsonDepKey(packageJson, options.ignorePackage);
                if (Array.isArray(packageDepKey) && packageDepKey.length > 0) {
                    depKeyArr = [...depKeyArr, ...packageDepKey]
                }
            }
            const newUpdatePkgList = getUpdatePkgList(depKeyArr);
            if (newUpdatePkgList.length <= 0) {
                continue
            } else {
                getExecFileBaseInfo(path);
                if (index <= 1) {
                    updatePkgList(newUpdatePkgList, index);
                } else {
                    await sleep(execTime * index)
                    updatePkgList(newUpdatePkgList, index);
                }
                index = ++index;
            }
        }
    } catch (error) {
        if (error) {
            if (retryCount < options.maxRetry) {
                console.log('%c 🍞 error: ', 'font-size:20px;background-color: #B03734;color:#fff;', error, '准备重试');
                runScript(options);
                retryCount = ++retryCount;
            }
        }
    }
}
runScript(options);


目录
相关文章
|
机器学习/深度学习 Kubernetes 监控
Kubernetes 节点故障自愈方案:结合 Node Problem Detector 与自动化脚本
本文深入探讨了Kubernetes节点故障自愈方案,结合Node Problem Detector(NPD)与自动化脚本,提供技术细节、完整代码示例及实战验证。文章分析了硬件、系统和内核层面的典型故障场景,指出现有监控体系的局限性,并提出基于NPD的实时事件捕获与自动化诊断树的改进方案。通过深度集成NPD、设计自动化修复引擎以及展示内核死锁恢复的实战案例,文章详细说明了自愈流程的实现步骤与性能优势。此外,还提供了生产环境部署指南、高可用架构设计及安全防护措施,并展望了机器学习增强故障预测和混沌工程验证的进阶优化方向。全文约1.2万字,适合希望提升Kubernetes集群稳定性的技术人员阅读。
887 2
|
JavaScript 安全 前端开发
关于Node.js,一定要学这个10+万Star项目 !!
一篇关于Node.js的宝藏项目——Node.js Best Practices。该项目在GitHub上已有102k Star,汇集了100+条最佳实践,涵盖架构、安全、性能等多方面。每条实践不仅有简明说明和详细解释,还附带代码示例及资源链接。文中通过三个实战案例(利用CPU多核、避免阻塞事件循环、使用中间件处理错误)展示了其实际应用价值,并推荐了几条对前端转Node.js开发者特别有用的最佳实践。强烈建议每位Node.js开发者学习此项目,理解“怎么做”与“为什么要这么做”,以提升开发能力。
530 3
node环境之当我们遇到需要付费的依赖库@fortawesome/fontawesome-pro导致npm install无法进行怎么办-fontawesome-pro依赖库
node环境之当我们遇到需要付费的依赖库@fortawesome/fontawesome-pro导致npm install无法进行怎么办-fontawesome-pro依赖库
606 3
node环境之当我们遇到需要付费的依赖库@fortawesome/fontawesome-pro导致npm install无法进行怎么办-fontawesome-pro依赖库
|
JavaScript Shell C#
多种脚本批量下载 Docker 镜像:Shell、PowerShell、Node.js 和 C#
本项目提供多种脚本(Shell、PowerShell、Node.js 和 C#)用于批量下载 Docker 镜像。配置文件 `docker-images.txt` 列出需要下载的镜像及其标签。各脚本首先检查 Docker 是否安装,接着读取配置文件并逐行处理,跳过空行和注释行,提取镜像名称和标签,调用 `docker pull` 命令下载镜像,并输出下载结果。使用时需创建配置文件并运行相应脚本。C# 版本需安装 .NET 8 runtime。
1261 3
|
JavaScript 应用服务中间件 Linux
宝塔面板部署Vue项目、服务端Node___配置域名
本文介绍了如何使用宝塔面板在阿里云服务器上部署Vue项目和Node服务端项目,并配置域名。文章详细解释了安装宝塔面板、上传项目文件、使用pm2启动Node项目、Vue项目打包上传、以及通过Nginx配置域名和反向代理的步骤。
6346 2
宝塔面板部署Vue项目、服务端Node___配置域名
|
JavaScript
Nodejs的cnpm包管理器快速入门
介绍Node.js的cnpm包管理器,包括cnpm的实现原理、如何安装cnpm、使用cnpm安装软件包,以及Node.js搜索包的流程。
668 2
Nodejs的cnpm包管理器快速入门
|
缓存 JavaScript 安全
2022年最新最详细的安装Node.js以及cnpm(详细图解过程、绝对成功)
这篇文章提供了2022年最新最详细的Node.js和cnpm安装教程,包括步骤图解、全局配置路径、cnpm安装命令、nrm的安装与使用,以及如何管理npm源和测试速度。
2022年最新最详细的安装Node.js以及cnpm(详细图解过程、绝对成功)
|
SQL JavaScript 关系型数据库
node博客小项目:接口开发、连接mysql数据库
【10月更文挑战第14天】node博客小项目:接口开发、连接mysql数据库
|
JavaScript Linux 网络安全
VS Code远程调试Nodejs项目
VS Code远程调试Nodejs项目
|
数据采集 资源调度 JavaScript
Node.js 适合做高并发、I/O密集型项目、轻量级实时应用、前端构建工具、命令行工具以及网络爬虫和数据处理等项目
【8月更文挑战第4天】Node.js 适合做高并发、I/O密集型项目、轻量级实时应用、前端构建工具、命令行工具以及网络爬虫和数据处理等项目
580 5