持续创作,加速成长!这是我参与「日新计划 6 月更文挑战」的第3天,点击查看活动详情

自从遇到了google/zx,很快我就将原先使用shell脚本的代码,全部转换到了google/zx

相当实例化一个对象可以使用什么命令于使用前端js来写脚本了,对前端来说实在太友好了

使用zx编写脚本,可以随心所欲的使用nodejs模块类库,我的demo使用mysql类库去将日志写入到mysql数据库, 当然你可以调用fs-extra,写入到本地文件当中,选择性很多了

使用mjs模块,可以像使用前端js代码一样轻松使用 import和 export

引用zx中的实例化servlet类异常$符号,可以随意Linux使用shell脚本中的所有命令

同时使用typescript来写zx的脚本,很是不错哟,不过在import时需要写成 ’./xxx.mjs‘,其实调用的就是linux虚拟机mts

可以在代码中随意调用 npm、 yarn、 pnpm等,以及测试你的自卑程度git pull 、git p实例化是什么意思ush 等等。

可以在代码中更好的编写脚本的逻辑控制,虽然在shell脚本中页可以实现,但对于前端工程师来说,用js这简直就是so easy的事情。

完美的使用await async来控制 同步和异步代码的执行顺序shell命令

1、之前通过shell脚本写的打包脚本

脚本入口文件地址 :githushell什么意思b.com/aehyok/2022… 克隆下来,有兴趣的可以apple下载下来看看,cd到本目录下就可以进行测试,将十五个应用编译后的文件自动复制到测试环境

sh build-all.sh  -v 2.5.1.006 -p awpqc  |tee build-log.txt
-v  2.5.1.006 版本号设置
-p awpqc 分别代表五个项目

2、我测试你适合学心理学吗通过zx进行了重写

如今我用google/zx(TypeScript)写的代码入口linux命令地址:github.com/aehyok/2022…

先说一下背景:

  • PC:主应用 + 八个子应用(全部是vue3)
  • APP: 主应用(vue2) + 两个子应用(vue3)
  • Other: P、Q、W 其他三个都是一个应用就完事的
  • 算一下,9+3+3=15个应用

我这脚本就是为了方便打包这15个应用

3、怎么做的呢

  • 十五个应用每次都到对应的目录去yarn build,或者pnpm build,会相当麻烦,而且会有遗漏的可能。

  • 项目在我本地都是可以运行的,所以这里我省去了, npm install 或者 yarn 或者pnpm i 。

  • 通过我的小demo,便可以通过一个命令 pnpm build:all,将上面说的15个应用全部打包完毕,放到指定服务器上。

  • 然后可以查看log日志,确认报错信息,或shellfish者直接线上测试查看发实例化servlet类异常布情况。如果有个别的子应用出现问题,可以单独去打包子应用即可。

  • 对每个子应用的打包目录,做了调整Shell,共同打包到一个release目录,将这个目录作为一个代码仓库,approach方便回退和记录的。

  • 过程:(这里面暂测试英文时使用的命令工具为yarn)

    • 1、到指定的giapplicationt仓库目录,测试抑郁程度的问卷拉取代码 cd path、git pull
    • 2、安测试你适合学心理学吗装依赖 (此步骤省略) yalinux重启命令rn
    • 3、代码仓库只有一个应用的直接编译应用 yarn build
    • 4、代码仓库包含多个应用的 需要先到指定的子应用目录 cd path, 再进行yarn build
    • 5、编译结束,根据版本号version 给代码仓库打上tag标签 git tag git push
    • 6、将编译后的文件拷贝到服务器指定的目录 scp -r
    • 7、所有的代码仓库都编译上传完毕以后,linux创建文件要将release代码仓库进行 git add . git commit git push,然后再打上对应的tag标签,推送到服务器

4、实际操作(根据上面的过程进行一步实例化对象一步的代码实现)

  • 1、拉取代码

    // 精简版代码(不包括写日志)
    export const gitPullBy = async(name: string, path: string) => {
        try {
            const gitPullInfo = await $`cd ${path}; git pull;`;
            if (gitPullInfo.exitCode === 0) {
                console.log('git pull 拉取代码成功')
            }
        } catch {
        }
    };
    
  • 2、安装依赖

    这一步按照道理,拉取代码后,要进行pnpm i,shelly安装依赖的过程。暂时通过手动挡处理:保证了项目在本Linux地开发环境能够运行,也就是说依赖肯定安装好了,要不然都跑不起来,自动化任务或者脚本里,难道能判断依赖是否安装过,或者说有新增依赖,可以通过什么方式来监测吗?

  • 3、直接编译子应linux创建文件

    // 精简版代码
    export const yarnBuildBy = async (path) => {
        try {
            const buildInfo = await $` cd ${path};yarn build;`;
            if (buildInfo.exitCode === 0) {
                console.log(`yarn build end success`);
            }
        } catch(error) {
        }
    }
    
  • 4、多个子应用批量编译linux重启命令

通过promise.all并发一起执行多个字应用的shell是什么意思中文编译

// 精简版代码
export const yarnBuildChildList = async(list) => {
    try {
        const result =await Promise.all(
            list.map((item) => {
            return $`cd ${item}; yarn build`;
            })
        )
        if(result) {
            console.log('all', 'result')
        }
    } catch {
    }
}
  • 5、编译结束,根据版本号打tag标签

    • 首先根据版本号判断是否已经存在相对应的version tag
    • 如果存在的话,先删除标签;如果不存在,直接shell脚本编程100例打tag标签
    • 最后git push 推送到代码仓库即可
    // 全过程代码
    export const gitTag = async () => {
        const { name } = global.project
        const path = baseUrl + name
        // 判断是否已经存在tag标签
        const isExist = await isExistTag(path)
        console.log(isExist, 'isExist')
        if (isExist) {
            // 如果存在泽进行删除tag标签的操作
            let isSuccess = await deleteTag(path);
            if (isSuccess) {
            await addTag(path, isExist);
            } else {
            oneLogger(`delete tag [${global.version}] error`);
            }
        } else {
            await addTag(path,isExist);
        }
    };
    const isExistTag = async (path) => {
        const result = await $` cd ${path};git tag;`;
        console.log("判断是否存在tag", result);
        if (result && result.exitCode === 0) {
            let array = result.stdout.split("n");
            if (array.length > 0 && array.includes(global.version)) {
                return true;
            }
            return false;
        }
    };
    const deleteTag = async (path) => {
        oneLogger(`delete tag [${global.version}] start`);
        const result = await $` cd ${path}; 
                                    git tag -d ${global.version}; 
                                    git push origin :refs/tags/${global.version}`;
        if (result.exitCode === 0) {
            oneLogger(`delete tag [${global.version}] end success`);
            return true;
        }
        return false;
    };
    /**
    *
    * @param {*} path 路径
    * @param {*} isExist 0为不存在,直接创建的;1为已存在删除的,重新创建
    */
    const addTag = async (path, isExist) => {
        const result = await $`cd ${path};
                            git tag -a ${global.version} -m 'chore:version ${global.version}版本号'; 
                            git push origin ${global.version};`;
        if (result && result.exitCode === 0) {
            if (isExist) {
            oneLogger(`re create tag [${global.version}] success`);
            } else {
            oneLogger(`create tag [${global.version}] success`);
            }
        }
    };
    //调用写入mysql日志的
    const oneLogger = (info) => {
        console.log(info);
        const { name } = global.project
        writerLog(name, info, global.version);
    };
    
  • 6、拷贝文件到指定服务器

    这里如果想更方便一些,可以把本地的ssh生成的公钥拷贝到相应的linux服务器的ssh目录

    export const copyFile = async(path: string) => {
        try {
            const result = await $`scp -r /e/work/git/dvs-2.x/release/cms/${path}/* root@139.9.184.171:/usr/local/sunlight/dvs/dvs-uis/${path}/`
            if(result.exitCode === 0) {
                oneLogger(`copy file  [${global.version}] end success`)
            }
            else {
                console.log("fail", $`$?`);
            }
        } catch {
            oneLogger(`copy file [${global.version}] end error`)
        }
    }
    const oneLogger = (info) => {
        console.log(info);
        const { name } = global.project
        writerLog(name, info, global.version);
    };
    
  • 7、整理所有项目编译后的文件shell编程

    对于打包生成的文件进行release目录整理,当然你可以全部编译打包完,再一起copy到指定的服务器,根据需要都可以approve去调整。

// 这一步有打包的代码需要进行git push
export const gitPushBy = async(name: string, path: string) => {
    try {
        await writerLog(name, `git push start`, global.version);
        // const message=`build:前端${name} -- commit-version:${global.version}`
        const message=`build:前端app、qrocde、wechat、park、console(child)commit-version:${global.version}`
        const result = await $`cd ${path}; git add . ; sleep 2; git commit -m ${message}; git push origin;`
        if(result && result.exitCode === 0 ) {
            await writerLog(name, `git push end success`, global.version);
        } else {
            await writerLog(name, `git push error: ${result.stderr}`, global.version); 
        }
    } catch (error){
        console.log(error, 'error')
        if(error.stdout.includes('nothing to commit, working tree clean')) {
            await writerLog(name, `git push nothing to commit`, global.version);
        }
        await writerLog(name, `git push error`, global.version);
    }
}

5、在使用过程中的问题

  • 1appearance、 pre…和post命令的使用

    "prebuild:all": "ts-node-esm pull.mts -v 4.5.3.007",
    "build:all": "concurrently "pnpm build:app"  "pnpm build:pc"  "pnpm build:wechat"  "pnpm build:park"  "pnpm build:qrcode" ",
    "postbuild:all": "ts-node-esm push.mts -v 4.5.3.007",
    

    在执行命令时执行 yarn build:all,那么会先执行命令 yarn prebuild:all, 执行完以后,才会真正执行yarn build:all, 执行完yarn:build:all以后,会执行yarn: postbuild:all。

    也就是pre为提前执行的钩子,post为结束后执行的钩子。但是如果使用pnpm执行 就不会执行pre实例化对象和post钩子。(这里还没找到问题!!!!!)

  • 2、concurrently,并行运行脚本,使用前先安装依赖测试 pnpm i concurrently

    "build:all": "concurrently "pnpm build:app"  "pnpm build:pc"  "pnpm build:wechat"  "pnpm build:park"  "pnpm build:qrcode" ",
    
  • 3、在命令行中 & 为并行, && 串行,在pnpm安装的依赖中行不行,所以使用了concurrently

    "build": "ts-node-esm index.mts -v 4.5.3.007 -p app & ts-node-esm index.mts -v 4.5.3.007 -p pc & ts-node-esm index.mts -v 4.5.3.007 -p wechat & ts-node-esm index.mts -v 4.5.3.007 -p park   & ts-node-esm index.mts -v 4.5.3.007 -p qrcode",
    

    这样使用还是不能并行,pnpm build,或者实例化对象是什么意思yarn build,都一样(这里也没找到问题!!!!!)

6、执行日志管理

我这里暂时是通过测试抑郁症mysql库,写入的数据库日志

  • 1、实例化数据库链接对象

    let _conn = mysql.createConnection({
        // 创建mysql实例,这是我的个人数据库可以访问,尽量只去查看
        host: "139.159.245.209",
        port: "3306",
        user: "meta",
        password: "meta",
        database: "meta",
    });
    
  • 2、通过实例链接数据库

    _conn.connect(function (err) {
        if (err) {
        console.log("fail to connect db", err.stack);
        throw err;
        }
        // 这里正真连接上数据库了。
        console.log(
        "链接成功--db state %s and threadID %s",
        _conn.state,
        _conn.threadId
        );
        logDbStat();  //此为记录数据库链接的线程和状态
    });
    const logDbState = function () {
        console.log(
        "db state %s and threadID %s",
        _conn.state,
        _conn.threadId
        );
    };
    
  • 3、用完后关闭链接

    const close = (conn) => {
        conn.end((err) => {
            if (err) {
            console.log("error ", err);
            } else {
            console.log("关闭成功", conn.state, conn.threadId);
            }
        });
    };
    
  • 4、最后返回一个Promise 方便处理和调用

    return new Promise((resolve, reject) => {
        try {
        let sqlParamsList = [sql];
        if (params) {
            sqlParamsList.push(params);
        }
        _conn.query(...sqlParamsList, (err, res) => {
            if (err) {
            reject(err);
            } else {
            resolve(res);
            close(_conn);
            }
        });
        } catch (error) {
        reject(error);
        }
    });
    
  • 5、封装方法进行调用

    export const writerLog = async (project, content, version) => {
        let id = shortid.generate()
        await executeSql("INSERT INTO CiCdLog values(?,?,?,?,null,null)", [id,
            project,
            content,
            version,
        ]);
    };
    
  • 6、在使用appstore的地方进行import导入,然后调用即APP

    import { writerLog } from "./sql-helper.mjs"
    // 传递三个参数即可
    await writerLog(name, `git push error`, global.version);
    

7、测试命令行编译

一个pcShell代码仓库,一个主应shell什么意思用和两个子应用,脚本所在代码仓库链接地址github.com/aehlinux命令yok/202appearance2…

yarn build

执行yarn build的时候,会先调linux创建文件用 prebuild命令

然后执行完yarn build之后,会调用posappreciatetbuild命令

通过代码产生的写入日志,如下截图所示

google/zx让前端可以使用typescript随心所欲的写脚本

8、总结

zx可以处理很多的事情,这里我就不一一列举了,有兴趣的可以继续深入学习了解探索一下,或许也会发现新的大陆。