一 目录
不折腾的前端,和咸鱼有什么区别
目录 |
---|
一 目录 |
二 前言 |
三 Node 编写 bash 脚本的解决方案 |
四 编程前置 |
五 敞开端口 |
六 删除文件/文件夹 |
七 Git 操作 |
7.1 工作中罕用 Git 指令 |
7.2 切换分支 |
八 总结 |
九 参考文献 |
二 前言
明天 jsliang 在工作中又爽了一把,开明了 VIP 通道:
- 主动下载 Excel 文件
- 拷贝到指定目录
- 执行多语言导入操作
- 将导入的资源
git push
下来
尽管看上去粗略的操作是这样,没有什么可讲的。
然而在操作中的时候,可能就比拟繁琐了,例如单单导入资源后,进行的 git
操作:
- 增加暂存区:
git add .
- 切换分支:
git checkout -b <branch>
- 提交本地版本库:
git commit -m "feat: 「多语言」新资源 #master_0720"
- 提交近程分支:
git push --set-upstream origin <branch>
当然,不仅仅是这个,你提交前必定还得校验下你的多语言资源增加完后,构建是否能顺利通过……
所以,叨了那么多,其实单纯是为了引出 bash
指令的操作。
在工作中,你可能会碰到:
- Git 系列操作
- 敞开被占用的零碎端口
- 删除指定文件/文件夹等
- ……
然而,对于这些操作你可能一时半会又遗记它的指令,或者它的指令太繁琐了,所以 jsliang 感觉将这些内容装起来,岂不省事?
三 Node 编写 bash 脚本的解决方案
其实对于这个解决方案,jsliang 还是嫌麻烦,所以间接上了 ShellJS
:
- ShellJS - Unix shell commands for Node.js
如果小伙伴感觉这样间接上计划有点唐突,心愿有个参考比照,能够看:
- Node.js 写 bash 脚本终极计划
作者比对了 Node 自带的 child_process
API、ShellJS
和 zx
,最终采取了 zx
的计划。
当然,jsliang 工作中用的还是 ShellJS
,不想那么累再摸索同类库了,所以就装置 ShellJS
吧~
- 装置:
npm i shelljs
- 装置 TS 编译:
npm i @types/shelljs -D
装置结束,开始折腾!
四 编程前置
为了让代码不显得那么又臭又长。
jsliang 写完文章后,通篇浏览 3 次以上,将下文中反复的代码和问题状况给整顿到这里来了,所以小伙伴们拷贝代码前,最初仔细阅读这一章节内容,托付啦~
warn! please read the following carefully
全文目录如下,小伙伴们记得提前新建好目录:
而后反复代码如下:
src/common/index.ts
import { inquirer } from '../base/inquirer';import { Result } from '../base/interface';// 零碎操作import { sortCatalog } from '../base/file/sortDir';import { deleteDir } from '../base/file/deleteDir';// 多语言import { downLoadExcel } from './language/download';import { importLanguage } from './language/import';import { exportLanguage } from './language/export';// shell 操作import { closePort } from '../base/shell/closePort';import { gitCheckout } from '../base/shell/gitCheckout';// 问题记录器const answers = { q0: '', q1: '', q2: '', q3: '', q4: '', q5: '', q6: '', q7: '', q8: '',};const common = (): void => { // 问题路线:看 questionList.ts const questionList = [ // q0 { type: 'list', message: '请问须要什么服务?', choices: ['公共服务', '多语言'], }, // q1 { type: 'list', message: '以后公共服务有:', choices: ['文件排序', '敞开端口', '删除文件夹', 'Git 操作'], }, // q2 { type: 'input', message: '须要排序的文件夹为?(绝对路径)', }, // q3 { type: 'list', message: '请问多语言须要什么反对?', choices: [ '下载多语言资源', '导入多语言资源', '导出多语言资源', ], }, // q4 { type: 'input', message: '资源下载地址(HTTP)?', default: 'https://www.kdocs.cn/l/sdwvJUKBzkK2', }, // q5 { type: 'input', message: '你须要敞开的端口是?', }, // q6 { type: 'input', message: '你须要删除的门路是?(全门路)', }, // q7 { type: 'list', message: '请问 Git 须要什么反对?', choices: [ '切换分支', // More... ], }, // q8 { type: 'inupt', message: 'Git 分支名是?', }, ]; const answerList = [ // q0 - 请问须要什么服务? async (result: Result, questions: any) => { answers.q0 = result.answer; switch (result.answer) { case '公共服务': questions[1](); break; case '多语言': questions[3](); break; default: break; } }, // q1 - 以后公共服务有: async (result: Result, questions: any) => { answers.q1 = result.answer; switch (result.answer) { case '文件排序': questions[2](); break; case '敞开端口': questions[5](); break; case '删除文件夹': questions[6](); break; case 'Git 操作': questions[7](); break; default: break; } }, // q2 - 须要排序的文件夹为?(绝对路径) async (result: Result, _questions: any, prompts: any) => { answers.q2 = result.answer; const sortResult = await sortCatalog(result.answer); if (sortResult) { console.log('排序胜利!'); prompts.complete(); } }, // q3 - 请问多语言须要什么反对? async (result: Result, questions: any, prompts: any) => { answers.q3 = result.answer; switch (result.answer) { case '下载多语言资源': case '导入多语言资源': questions[4](); break; case '导出多语言资源': const exportResult = await exportLanguage(); if (exportResult) { console.log('导出胜利!'); prompts.complete(); } default: break; } }, // q4 - 资源下载地址(HTTP)? async (result: Result) => { answers.q4 = result.answer; const download = async (): Promise<any> => { const downloadResult = await downLoadExcel(result.answer); if (downloadResult) { console.log('下载胜利!'); return true; } }; switch (answers.q3) { case '下载多语言资源': await download(); break; case '导入多语言资源': await download(); const importResult = await importLanguage(); if (importResult) { console.log('导入结束!'); } default: break; } }, // q5 - 你须要敞开的端口是? async (result: Result, _questions: any, prompts: any) => { answers.q5 = result.answer; const closeResult = await closePort(result.answer); if (closeResult) { console.log('敞开胜利'); prompts.complete(); } }, // q6 - 你须要删除的门路是?(全门路) async (result: Result, _questions: any, prompts: any) => { answers.q6 = result.answer; const deleteResult = await deleteDir(result.answer); if (deleteResult) { console.log('删除胜利'); prompts.complete(); } }, // q7 - 请问 Git 须要什么反对? async (result: Result, questions: any) => { answers.q7 = result.answer; questions[8](); }, // q8 - Git 分支名是? async (result: Result, _questions: any, prompts: any) => { answers.q8 = result.answer; const checkoutResult = await gitCheckout(result.answer); if (checkoutResult) { console.log('切换胜利'); prompts.complete(); } }, ]; inquirer(questionList, answerList);};export default common;
src/common/questionList.ts
// common 板块的问题征询路线export const questionList = { '公共服务': { // q0 '文件排序': { // q1 '须要排序的文件夹': 'Work 工作', // q2 }, '敞开端口': { // q1 '须要敞开的端口': 'Work 工作', // q5 }, '删除文件夹': { // q1 '须要删除的门路': 'Work 工作', // q6 }, 'Git 操作': { // q1 '切换分支': { // q7 '分支名': 'Work 工作', // q8 }, }, }, '多语言': { // q0 '下载多语言资源': { // q3 '下载地址': 'Work 工作', // q4 }, '导入多语言资源': { // q3 '下载地址': 'Work 工作', // q4 }, '导出多语言资源': { // q3 '导出全量资源': 'Work 工作', '导出单门资源': 'Work 工作', } },};
前面文章表明:
更新 src/common/index.ts
更新 src/common/questionList.ts
这种状况,小伙伴们就不必操作啦,本文有 3 个中央都有这种形容的。
同样,为了防止援用和运行代码的时候,报 TypeScript 谬误,新增的 3 个文件结尾也列一下:
src/base/file/deleteDir.ts
import shell from 'shelljs';export const deleteDir = async (path: string): Promise<boolean> => { console.log(path)};
src/base/shell/closePort.ts
import shell from 'shelljs';export const closePort = async (port: string): Promise<boolean> => { console.log(port);};
src/base/shell/gitCheckout.ts
import shell from 'shelljs';/** * @name 切换分支 * @description 指令合并: * 1. git checkout ${branch} * 2. git pull * @param {string} branch 分支名 */export const gitCheckout = (branch: string): boolean => { console.log(branch)};
另外common
下的sortCatalog.ts
迁徙到base/file
目录下,并且改名为sortDir.ts
了。
那么,筹备结束,开始输入!
五 敞开端口
在起一些神奇的服务时,会碰到端口被占用的场景,这时候就须要敞开端口:
- 查看端口占用状况:
netstat -ano|findstr "端口号"
PS F:\xxx> netstat -ano|findstr "3001" TCP 0.0.0.0:3001 0.0.0.0:0 LISTENING 33396 TCP 10.13.144.170:63001 183.2.199.241:443 ESTABLISHED 28228 TCP [::]:3001 [::]:0 LISTENING 33396
- 终止 PID:
taskkill -F -PID PID号
PS F:\xxx> taskkill -F -PID 33396胜利: 已终止 PID 为 33396 的过程。
那么到了 Node 工具库这边,必定就不要本人去这样操作啦,搞个省事的形式吧:
更新 src/common/index.ts
更新 src/common/questionList.ts
而后编写 closePort.ts
:
src/base/shell/closePort.ts
import shell from 'shelljs';export const closePort = async (port: string): Promise<boolean> => { await shell.exec(`netstat -ano | findstr :${port}`); // Windows 下会返回一个端口占用清单,须要自行删除 console.log('已找到下面清单列表,请执行指令删除端口:taskkill -F -PID PID号'); return await true;};
注:Windows 打印后果最开端的为 PID 号
当然,因为 3001
可能会有好几个 ip
对应的端口,所以前面那个步骤咱们仅做了提醒,而不是敞开了所有 3001
的端口(须要用户手动操作)。
然而这样总好过咱们去记忆这个指令(毕竟 Windows 和 Mac 等的操作指令还不通)
执行 npm run jsliang
,运行后果如下:
这样咱们就封装好了敞开端口的,因为不是一键彻底敞开,实用指数给到 ☆☆☆
六 删除文件/文件夹
之前在公司为了钻研 Windows 如何疾速删除 node_modules
,jsliang 还真翻了下材料找到 3 种删除文件/文件夹的形式:
cmd.exe
:rd /s /q <path>
PowerShell
:rd -r <path>
Mac
:rm -rf <path>
通过屡次亲自体验,在公司中的 32G 内存,500 SSD 的台式电脑中,通过 PowerShell
的删除操作比 cmd.exe
的快(别问我为啥,反正就是快点,仅集体体验,不做迷信撑持)。
而后看了下 ShellJS
,是有删除形式的:
- ShellJS:
rm()
删除文件,rm('rf', <path>)
删除文件夹
当然!奔着摸索精力,咱们看看它源码咋实现的:
- GitHub:ShellJS - rm.js
function rmdirSyncRecursive(dir, force, fromSymlink) { // 1. 先删除目录中的所有文件 let files = fs.readdirSync(dir); for (var i = 0; i < files.length; i++) { // 1.1 如果是目录则递归调用 rmdirSyncRecursive() // 1.2 如果是文件则调用 fs.unlinkSync() 执行删除 } // 2. 再删除目录 fs.rmdirSync();}
当然,外面有些细节还是写得不错的,这里就不开展具体解说,感兴趣的小伙伴能够点击下面链接摸索下源码。
所以,咱们就用 ShellJS
的办法吧!如果前面感觉不难受再替换为零碎指令。
更新 src/common/index.ts
更新 src/common/questionList.ts
而后开始编写 deleteDir.ts
:
src/base/file/deleteDir.ts
import shell from 'shelljs';export const deleteDir = async (path: string): Promise<boolean> => { /** * cmd.exe:rd /s /q <path> * PowerShell:rd -r <path> * Mac:rm -rf <path> * ShellJS:rm() 删除文件,rm('rf', <path>) 删除文件夹 */ await shell.rm('-rf', path); return true;};
执行 npm run jsliang
,打印内容如下:
搞定,出工!因为不分明 Node 操作和零碎指令哪个比拟快,所以暂定实用指数 ☆☆☆
七 Git 操作
那么最初,来到重头 Git 操作。
想必有些小伙伴会跟 jsliang 一样懒?
git add .
git commit -m "xxx"
git push
曾经到了麻痹的状态了,jsliang 甚至开发了特定的 VS Code 插件:
注:VS Code 也卷,更新太快了我插件承受不了(肯定水平上最新 VS Code 用不了该插件),所以我的 VS Code 版本锁死 v1.53.2
,啥时候有空操作再更新这个插件了
在 VS Code 插件中,进行疾速的提交操作。
所以在一些惯例的 Git 操作咱们还是心愿能封装起来(不须要记指令,也不想点页面,让它自行跑起来吧)
7.1 工作中罕用 Git 指令
jsliang 在工作中常常应用,并记住了的对应指令:
git pull
:拉取代码并主动合并,jsliang 这边还会用git pull --rebase origin master
,表明拉取近程分支并基于该分支进行改变git checkout -b <newBranch>
:从以后分支切新分支git branch -D <branch>
:依据分支名删除指定分支git add <files>
:提交到暂存区git commit <description>
:提交到本地版本库。如果你们仓库有eslint
查看之类的,强烈推荐git commit -m "xxx" --no-verify
(有时候真不想搞啥查看)git push
:提交到近程库。个别新分支操作为git push -- set upstream origin <branch>
git cherry-pick <commitHash>
:将指定的提交(commit
)利用于其余分支git stash
:暂存内容。将暂存区的内容存储到栈中(屡次stash
能够通过屡次pop
推出来)git stash pop
:签出内容。将git stash
中的内容推出来git reset --soft HEAD^
:回退版本并保留内容。这个HEAD^
是指上一个版本,也能够写成HEAD~1
(就是 commit id)
值得一提的是,jsliang 之前还尝试用过:git worktree
,它能够同时批改多个版本。
然而因为嫌麻烦(要记指令),所以就没用了
同一个 Git 仓库,须要同时批改多个分支,或者须要在 A 分支上参照 B 分支的内容进行批改。
当然这种状况能够用 git clone
拷贝一个新仓库,然而如果你的仓库有点大(几 G 那种),那还是有点嫌麻烦的。
于是就有了 git worktree
,指令如下:
# 将 abc 分支切出到另一个目录 jsliang 中# 留神:这个目录不能在主仓库中git worktree add ../jsliang abc # git add [<选项>] <门路> [<提交>]# 获取帮忙git worktree -h# 查看每个工作树的详细信息git worktree list# 更残缺的工作树信息# git worktree list --porcelain# 锁定内容,避免被主动删除git worktree lock# 解锁内容git worktree unlock# 迁徙到新目录git worktree move abc ../jsliang2# 删除某条工作树git worktree remove ../jsliang# 革除工作树信息git worktree prune
罕用 git worktree
指令:
- 切出分支:
git worktree add ../jsliang abc
- 罕用操作:
git add .
、git commit -m "xxx"
、git push
- 敞开分支:
git worktree prune
当然,还有 Git 设置代理
迷信上网状况下,有时候 Git 并没有失效,克隆或者 push
操作一样卡慢,就须要设置 Git 代理。
- 设置代理
git config --global http.proxy 代理地址
git config --global https.proxy 代理地址
- 勾销代理
git config --global --unset http.proxy
git config --global --unset https.proxy
- 查看曾经设置的代理
git config --global --get http.proxy
git config --global --get https.proxy
我拿当初用的迷信上网代理软件,就设置了 git config --global http.proxy http://127.0.0.1:10809
,Git 晦涩度晋升了挺多。
7.2 切换分支
吧啦吧啦说了一通,上面开始干点正活,咱们搞个简略的切换分支:
更新 src/common/index.ts
更新 src/common/questionList.ts
接着更新下 gitCheckout.ts
:
src/base/shell/gitCheckout.ts
import shell from 'shelljs';/** * @name 切换分支 * @description 指令合并: * 1. git checkout ${branch} * 2. git pull * @param {string} branch 分支名 */export const gitCheckout = (branch: string): boolean => { if (!shell.which('git')) { shell.echo('Error: 请先装置 Git!'); shell.exit(1); } console.log('开始切换分支:'); const checkoutResult = shell.exec(`git checkout ${branch}`); if (checkoutResult.code !== 0) { shell.echo('Error: 切分支失败!'); shell.exit(1); } console.log('开始拉取代码,请稍等:'); const pullResult = shell.exec('git pull'); const { stdout, stderr } = pullResult; if (pullResult.code === 0) { if (stdout.includes('from the remote, but no such ref was fetched.')) { console.log('你的分支是最新的'); } } else if (pullResult.code === 1) { if (stderr.includes('There is no tracking information for the current branch.')) { console.log('不存在近程分支'); } } return true;};
而后运行:npm run jsliang
,跟着指令输出分支名:
此时因为是咱们轻易输出的一个分支,所以它表明切换分支失败了。
当然,小伙伴们能够根据实在业务往里面装载更多的内容,这里就不开展具体解说,仅做抛砖引玉先吧~
八 总结
其实最近两天还有在通过汇总 bash
指令来压缩一些工作流程的事,然而碍于一时半会想不到更好的我的项目例子,所以就没有一一铺开解说,所以小伙伴们碰到这种状况,欢送来吐槽评论留言,衷心示意心愿能和小伙伴们一起探讨。
那么,对于 ShellJS
咱们就铺垫那么一点了,前面 jsliang 在生存、工作中碰到一些乏味的知识点再增加进来吧~
So,下期再会!
九 参考文献
- GitHub:ShellJS - Unix shell commands for Node.js
- 掘金: nodejs写bash脚本终极计划!
- GitHub:Git worktree 作用及应用
- 简书:git worktree 的应用
- 知乎:Git屠龙技:应用Git Worktree并行开发测试
- 政企云前端团队:我在工作中是如何应用 Git 的
- SegmentFault:Git 屠龙技:应用 Git Worktree 并行开发测试
- 何方的编程之路:Git如何应用代理(VPN)
- 阮一峰:cherry-pick
jsliang 的文档库由 梁峻荣 采纳 常识共享 署名-非商业性应用-雷同形式共享 4.0 国内 许可协定 进行许可。<br/>基于 https://github.com/LiangJunrong/document-library 上的作品创作。<br/>本许可协定受权之外的应用权限能够从 [https://creativecommons.org/l...](https://creativecommons.org/l...