需求背景

公司有8个前端项目,共使用四个公共包,基础包(baqi)、医生公共包(baqi-doctor)、患者公共包(baqi-patient)、聊天包(baqi-chat)。
开发分支上使用file引入公共包(file引入的方式可以查看这一篇),到测试和生产上需要使用版本号来引入这几个公共包。这就需要一个方便的publish公共包的工具,写了一个node脚本publish.js

实现

主流程

  1. 计算下一个版本号
  2. 设置npm代理为淘宝
  3. 设置baqi包、baqi-xxx包中package.json的version号
  4. publish baqi包和baqi-xxx包
  5. 替换前端8个项目引入baqi包和baqi-xxx包的版本号
  6. 判断是否安装cnpm,若没安装cnpm,则安装
  7. 新开4个进程,执行cnpm sync命令,同步新发布的包到淘宝代理
  8. 新开8个进程,进入8个前端项目执行npm install

需要注意的是

  1. 可以使用http的get请求获取npm包的信息,url为http://registry.npm.taobao.org/baqi/latest,其中baqi为包名
  2. 需要设置taobao的npm代理,不然执行npm命令进程偶尔会卡住
  3. 设置taobao代理后无法publish,在publish时指定registry为npmjs官方url
  4. publish和进入各项目执行npm install时可以开多个进程执行,提高效率,使用await Promise.all(promiseArr)保证执行顺序
  5. 如在linux下使用,路径会错误,可以使用path.sep()来代替路径的斜杠
  6. 使用process.cwd()来代替__dirname,减少因路径带来的问题

package.json增加执行脚本

"scripts": {"pb": "node bin/publish.js"
},

使用方法

npm run pb <version>

version可选,若输入version,按照指定的版本号publish,若不输入version,自动计算版本号

代码

主流程代码

#!/usr/bin/env node
const fs = require('fs')
const path = require('path')
const { getRequest, execCmdSync, execCmd } = require('./util')const cwd = process.cwd()
const modules = ['baqi', 'baqi-chat', 'baqi-doctor', 'baqi-patient']
const projects = ['doctor_web','patient_web','heart-doctor','heart-patient','tumour-doctor','tumour-patient','mini-hospital','mh-doctor'
]
let version = process.argv[2]main()async function main () {if (version === undefined) {console.log('查找版本号!')version = await computeVersion()console.log('版本号为:' + version)}console.log('设置npm代理')execCmdSync('npm config set registry https://registry.npm.taobao.org')console.log('替换baqi包、baqi-xxx包的version号\n将baqi-xxx包中引入baqi的方式替换成version引入')for (let i = 0; i < modules.length; i++) {replaceVersionAndImport(modules[i])}console.log('publish baqi包和baqi-xxx包')const publishArr = []for (let i = 0; i < modules.length; i++) {console.log('正在publish ' + modules[i])const cdPath = path.join(cwd, '../' + modules[i])publishArr.push(execCmd('cd ' + cdPath + ' && npm publish --registry http://registry.npmjs.org'))}await Promise.all(publishArr) // 不catch,报错就中断console.log('将baqi-xxx包中引入baqi的方式替换成file引入')for (let i = 1; i < modules.length; i++) {replaceImportToFile(modules[i])}console.log('替换所有项目引入baqi包和baqi-xxx包的版本号')for (let i = 0; i < projects.length; i++) {replaceImport(projects[i])}console.log('判断是否安装cnpm')checkCnpm()console.log('新开4个进程,同步cnpm')let cnpmSyncArr = []for (let i = 0; i < modules.length; i++) {cnpmSyncArr.push(execCmd('cnpm sync ' + modules[i]))}await Promise.all(cnpmSyncArr) // 不catch,报错就中断console.log('新开8个进程,进入各项目执行npm install')const npmInstallArr = []for (let i = 0; i < projects.length; i++) {const lockFilePath = path.join(cwd, '../' + projects[i] + '/package-lock.json')if (fs.existsSync(lockFilePath)) {console.log('删除文件' + lockFilePath)fs.unlinkSync(lockFilePath)}const cdPath = path.join(cwd, '../' + projects[i])npmInstallArr.push(execCmd('cd ' + cdPath + ' && npm install'))}try {await Promise.all(npmInstallArr)} catch (e) {console.error(e)}console.log('----------搞定了----------')
}

其他函数代码

function checkCnpm () {try {const out = execCmdSync('where cnpm')if (out.startsWith('信息')) {execCmdSync('npm install -g cnpm')}} catch (e) {execCmdSync('npm install -g cnpm')}
}async function computeVersion () {let maxVersion = ''for (let i = 0; i < modules.length; i++) {const moduleInfo = await getRequest('http://registry.npm.taobao.org/' + modules[i] + '/latest')const packageVersion = moduleInfo.versionif (packageVersion > maxVersion) {maxVersion = packageVersion}}let lastVersion = parseInt(maxVersion.substring(maxVersion.lastIndexOf('.') + 1)) + 1maxVersion = maxVersion.substring(0, maxVersion.lastIndexOf('.') + 1) + lastVersionreturn maxVersion
}function replaceImportToFile (moduleName) {let filePath = path.join(cwd, '../' + moduleName + '/package.json')let fileStr = readPackageJson(filePath)fileStr = fileStr.replace(/("baqi"\s*:\s*").*?(")/g, '$1file:../baqi$2')writePackageJson(filePath, fileStr)
}function replaceImport (projectName) {let filePath = path.join(cwd, '../' + projectName + '/package.json')let fileStr = readPackageJson(filePath)fileStr = fileStr.replace(/("baqi.*\s*:\s*").*?(")/g, '$1' + version + '$2')writePackageJson(filePath, fileStr)
}function replaceVersionAndImport (moduleName) {let filePath = path.join(cwd, '../' + moduleName + '/package.json')let fileStr = readPackageJson(filePath)fileStr = fileStr.replace(/("version": ").*?(")/, '$1' + version + '$2')fileStr = fileStr.replace(/("baqi.*\s*:\s*").*?(")/, '$1' + version + '$2')writePackageJson(filePath, fileStr)
}function writePackageJson (packageJsonPath, str) {fs.writeFileSync(packageJsonPath, str, 'utf8')
}function readPackageJson (packageJsonPath) {const fileStr = fs.readFileSync(packageJsonPath, 'utf8')return fileStr
}

util.js

const http = require('http')
const execSync = require('child_process').execSync
const exec = require('child_process').execfunction execCmdSync (cmdStr) {console.log('执行:' + cmdStr)const out = execSync(cmdStr, { encoding: 'utf8' })return out
}
function execCmd (cmdStr) {return new Promise((resolve,rejcect) => {console.log('执行:' + cmdStr)exec(cmdStr, { encoding: 'utf8' }, function (error, stdout, stderr) {error ? rejcect(error) : resolve(stdout)})})
}
function getRequest (url) {return new Promise(resolve => {console.log('请求URL:' + url)http.get(url, res => {let html = ''res.on('data', function (data) {html += data})res.on('end', function () {console.log('返回:' + html)try {resolve(JSON.parse(html))} catch (e) {resolve(html)}})})})
}
module.exports = {exec,execCmd,getRequest
}

结语

实现了一键发布4个公共包并且修改引用的功能,但有时候只改动某一个地方确要发布4个公共包,下一步计划增加只发布某一个公共包的功能

一键publish的node脚本相关推荐

  1. JAVA包可以构建一个子系统_Windows 10 用于 Linux 子系统的一键构建、打包脚本「 Node、Gradle 项目」...

    最近正在开发一个 Java & Vue.js 全栈项目,该项目由以下几部分组成:Java 后端服务器.基于 Vue.js 的单页应用.基于 JavaFX 的 GUI 客户端以及其他辅助工具等. ...

  2. rancher 一键安装集群脚本

    rancher 一键安装集群脚本 注意:操作系统任意如果是centos8需要更换yum源 cd /etc/yum.repos.d/sed -i 's/mirrorlist/#mirrorlist/g' ...

  3. android批处理脚本,BAT批处理一键生成APK包脚本分享

    BAT批处理一键生成APK包脚本分享 将本bat放到cocos2dx目录下你的工程的project.android下(需修改变量). ASmaker 用来将Resources文件夹下的lua文件批量加 ...

  4. (压缩包在本地目录或由链接请求)使用jszip解压文件或compressing解压文件到指定目录,写个node脚本

    使用jszip解压文件与compressing解压zip文件到指定目录 一.介绍jszip和compressing模块 jszip和compressing模块都是可以压缩和解压缩zip文件,都可以通过 ...

  5. centos 一键安装配置nginx脚本

    centos 一键安装配置nginx脚本 installNginx.ssh 用vi或则vim编辑 installNginx.ssh #!/bin/bash # author:kwin # Email: ...

  6. 一键部署LNMP平台脚本

    分享一个一键部署LNMP平台脚本,设置通过systemd管理Nginx服务,好用! #!/bin/bash yum -y install gcc openssl-devel pcre-devel ta ...

  7. Linux系统一键安全加固shell脚本编写思路

    本次分享一下个人在对Linux系统一键安全加固shell脚本编写时的一些思路: Linux系统一键安全加固shell脚本编写思路 1.编写须知 1.1 脚本使用说明 1.2 主要功能说明: 1.3隐藏 ...

  8. 表妹求我写个node脚本,把java错误码表转成excel并翻译成英文

    java原始代码部分如下 public static final int ERR_ONLINE_DECLINED = 1025; //交易联机拒绝//public static final int E ...

  9. 一键系统优化15项脚本

    一键系统优化15项脚本,适用于Centos6.x 按 Ctrl+C 复制代码 #!/bin/sh ################################################ #A ...

最新文章

  1. LeetCode简单题之石头与宝石
  2. float python_Python中float('INF')的使用
  3. QQ号码采集及邮件发送系统2009
  4. 【CodeForces - 215B 】Olympic Medal (数学,公式推导)
  5. Android深入浅出之Binder机制(转)
  6. ajax get post
  7. hibernate和struts实现分页
  8. Halcon:立体匹配
  9. python爬虫可以做哪些好玩的地方_如何快速的找到好玩的旅游景点信息?Python爬虫帮你轻松解决...
  10. 简单的时间间隔调度任务
  11. 织梦内核PHP在线教育知识付费课程分销网站源码 带手机端+集成支付功能
  12. android 蓝牙耳机 找不到驱动程序,bluetooth外围设备,详细教您bluetooth外围设备找不到驱动程序怎么解决...
  13. 5.5 设置UITableView单元格背景色 [原创iOS开发-Xcode教程]
  14. 转自随风飘荡自由飞翔 SQL技巧:快速把握一些异常精妙的SQL语句
  15. 在 Android 设备上搭建 Web 服务器
  16. 超赞 不愧是美团内部的JVM学习手册,从头到尾全是精华
  17. 牛客网-密码检查-小明同学最近开发了一个网站,在用户注册账户的时候,需要设置账户的密码,为了加强账户的安全性,小明对密码强度有一定要求:。。。。。
  18. 帝国推送插件-免费帝国CMS实时推送插件
  19. 【已解决】App unavailable Unfortunately, Claude is only available in certain countries and regions
  20. IO接口标准(3):HCSL和LPHCSL

热门文章

  1. try/except...else
  2. Git 实现原理,你真的了解吗?
  3. ip68级防水可以泡多久_IP68级别的防水遇水就废,明明只防水溅,为什么还大肆宣传防水!...
  4. idea自动补全对象或方法返回的对象
  5. 英雄联盟手游国服内测服务器维护,英雄联盟手游国服内测资格怎么获得 国服内测资格获取方法一览...
  6. PS 滤镜——极坐标变换到平面坐标
  7. C语言打印输出杨辉三角案例讲解
  8. 备忘录系统——需求篇
  9. elementui 表格表头竖着显示_elementUI Table表格表头自定义
  10. Face Alignment in Full Pose Range: A 3D Total Solution(3DDFA)论文与项目学习