共计 10457 个字符,预计需要花费 27 分钟才能阅读完成。
一 目录
不折腾的前端,和咸鱼有什么区别
目录 |
---|
一 目录 |
二 前言 |
三 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…