在 《JS 模块化》系列开篇中,曾提到前端技术的发展不断融入很多后端思想,形成前端的”四个现代化”:工程化、模块化、规范化、流程化。在该系列文章中已详细介绍了模块化的发展及四种模块化规范。本文简单聊聊规范化中的 git 规范。
1 规范化
在企业级开发中,”一千个读者有一千个哈姆雷特”是很常见的事,每个程序员对技术的理解、视角和掌握程度参差不齐,导致编写的代码五花八门。规范化包括很多,我在企业实践中重点关注两个方面: 代码规范 和 git 提交规范。
代码规范最基础的是代码格式,不同的代码格式虽然运行起来没有问题,但代码超级难看,代码乱七八糟、一堆 warning,虽然不影响运行,但看着太恶心,就像下面的情形:
- 估计是为了节省纸张,空格全省略,代码全挤在一起:
const a=b+c
const fn=()=>{}
fn(){}
for(let i=0; i
- 单引号、双引号混合使用,上一行用单引号,下一行偏要用双引号;
- 上一行加分号,后一行省略分号;
- 定义了一些从没有使用的变量;
- 分支判断中只有一句话坚决不写花括号;
- ……
我不能说上面的风格是错误的(写代码就像玩音乐一样,不能说绝对的对错,只是理解不同罢了),无论怎么写,至少一个团队还是应该保证统一的风格吧。于是咱们就使用了 .editorconfig 和 eslint。
.editorconfig 对编辑器的基本格式做了限制,但比较粗糙; eslint 就进行了详细的约束。无论选择 standard 、 airbnb、 prettier 任何一种,都是为了强制团队使用统一的代码风格。
在 《创建 vite vue3 项目》一文中已讨论了如何在基于 vite 的 vue3 项目中如何整合 eslint。
本文重点讨论 git 提交规范。
2 git 提交规范
大家应该都是使用 git 管理代码吧?如果你在企业还是使用 SVN 管理代码,那可以赶快跑路了。git 提交代码使用 git commit -m ‘描述’ 命令。但描述信息很多情况下都是随意填写,git 提交规范就是针对这个描述信息的约束。
2.1 Angular 规范
Angular 团队规范是目前使用较多的 git 提交规范 —— 约定式提交。规范要求提交的描述信息格式为:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
</description></type>
含有 optional 表示可选,故必填的内容是 type 和 description。
type 表示这次提交的类型,包括如下值:
type 含义 feat 新功能 fix 修复 docs 文档变更 style 代码格式(不影响代码运行) refactor 重构(不增加新功能,也不是修改 bug) perf 性能优化 test 添加测试 chore 修改构建过程或辅助工具 revert 回退 build 打包
例如,实现了一个修改用户列表功能,此时提交代码使用如下命令:
git commit -m 'feat: 实现用户列表'
修改了 vite.config.ts 的配置,压缩打包文件:
git commit -m 'chore: 修改vite生产配置'
2.2 Commitizen
确定了git 提交时描述信息的规范,那如何让人遵守执行呢?首先需要让开发同事知道提交信息的内容,此时可以使用工具 commitizen 来完成。 commitizen 是一个 git 提交规范化的工具,提供了 git cz 命令来代替传统的 git commit 命令。使用 git cz 来提交代码, commitizen 会一步步提示输入的字段,并提交所填写的必需字段。换句话说,使用 git cz 命令,底层最后会执行 git commit,但在执行 git commit 前,会校验描述信息是否符合规范。如果不符合规范,则不会执行 git commit,提交失败。
- 全局安装 commitizen
yarn global add commitizen
- 在工程中安装 cz-conventional-changelog
yarn add cz-conventional-changelog -D
- 在工程中初始化 commitizen 的约定式提交:
commitizen init cz-conventional-changelog --yarn --dev --exact
执行完该命令, package.json 文件中会自动生成如下配置:
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
}
完成上述步骤后,便可以使用 git cz 命令来提交代码了。
添加需要提交的文件,添加文件后执行 git cz 命令,提示如下:

使用上下键选择提交的类型,按照提示输入相关内容或必填内容即可完成提交。
3 git hooks
上面实现了 Git 提交规范,但仍然有不听话的同学会使用 git commit,如此一来提交信息依旧是乱七八糟的,此时便需要使用 git hooks 了。
3.1 什么是 git hooks
hooks 意思是”钩子”,也就是在执行某个操作之前或之后要做的事。git hooks 就是 git 操作的钩子,在 git 执行某个操作之前或之后要做的事,如 git 提交后、提交后、合并前、合并后、rebase前、rebase后等。在这里需要重点关注的 git 钩子有两个:
- pre-commit
pre-commit 是 git commit 执行前的钩子,会在获取提交描述信息且提交前被调用,根据该钩子决定是否拒绝提交。可以在这个钩子中对代码进行 eslint 检查。
- commit-msg
commit-msg 也是 git commit 执行前的钩子,用来规范化标准格式,根据标准和提交的描述信息决定是否拒绝提交。可以在这个钩子中检查提价信息是否符合规范。
3.2 commitlint 和 husky
理解 git hooks 后,就是如何在工程中引入上述钩子。此时需要使用到 husky 和 commitlint。两者结合起来可以在提交的描述信息不规范时会导致提交失败,并提示错误。首先安装配置 commitlint。
- 安装 husky 和 commitlink 相关依赖:
yarn add husky @commitlint/cli @commitlint/config-conventional -D
- 在项目根目录创建 commitlint.config.cjs 配置文件:
module.exports = {
extends: [
'@commitlint/config-conventional'
]
}
- 初始化 husky
npx husky install
执行完成后,项目根目录会自动生成一个 .husky 文件夹。
3.3 pre-commit 和 commit-msg 钩子
接下来需要使用 lint-staged 对git 暂存区(git add . 的内容)文件进行 eslint 检查。
- 安装 lint-staged
yarn add lint-staged -D
- 在 package.json 中添加 scripts:
"scripts": {
...
"lint": "eslint \"src/**/*.{js,ts,vue,jsx,tsx}\" --fix"
},
- 在 package.json 添加 lint-staged 配置:
{
.....
"lint-staged": {
"*.{js,ts,jsx,tsx,vue}": [
"npm run lint"
]
}
}
- 分别执行下列命令,为 husky 添加 commit 前的 hook,让其执行 eslint 和 commitlint :
npx husky add .husky/pre-commit 'npx lint-staged'
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
执行完该命令后,会自动在 .husky/ 目录下生成 pre-commi 文件和 commit-msg 文件。
pre-commit 文件内容如下:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-staged
commit-msg 文件内容如下:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no-install commitlint --edit ""
3.4 测试
到此为止便完成了配置,可以按如下步骤进行测试:
git add .
git commit -m '测试提交'
控制台会出现如下错误提示:

使用 git cz 命令重新提交,便可以成功提交。
各位还可以弄点 eslint 错误再提交试试效果。
Original: https://www.cnblogs.com/youyacoder/p/16791663.html
Author: 程序员优雅哥(公/同)
Title: vite vue3 规范化与Git Hooks
相关阅读
Title: MQ系列8:数据存储,消息队列的高可用保障
MQ系列1:消息中间件执行原理
MQ系列2:消息中间件的技术选型
MQ系列3:RocketMQ 架构分析
MQ系列4:NameServer 原理解析
MQ系列5:RocketMQ消息的发送模式
MQ系列6:消息的消费
MQ系列7:消息通信,追求极致性能
1 介绍
在之前的章节中,我们介绍了消息的发送 和 消息通信 的原理。但是这边有一个比较核心的关键点,那就是如果已经把消息传递给Broker。在Broker在被消费之前,如何保证消息的稳定性,避免消息丢失和数据。
这时候就需要数据持久化数据来进行保障了。
根据之前我们 MQ系列2:消息中间件的技术选型 章节做的分析,RabbitMQ支持 1W+ 级别的吞吐,
Kafka 和 Rocket 支持 10W+ 级别的吞吐,想要实现这么大的吞吐,必须具备一个很强悍的存储功能。下面我们来看看。
2 Broker 存储架构
RocketMQ采用文件存储机制(类似Kafka),即直接在磁盘上使用文件来保存消息,而不是采用Redis或者MySQL之类的持久化工具。
它会把消息存储所属相关的文件存储在ROCKETMQ_HOME下,包含三个部分:
2.1 CommitLog 消息元数据
存储消息的元数据,所有消息都会顺序存入到CommitLog文件中。CommitLog由多个文件组成,每个文件固定大小1G。它有如下特征:
- 单个文件默认大小为1G
- 文件名称长度20,保存偏移量,偏移量不够20位的补0。
- 如第1个文件没有偏移量,则为:00000000000000000000
- 第2个文件起始偏移量为1073741824(1G=1073740842),则文件名为 00000000001073741824。
- 第一个1G文件文件写满之后之后转入第2个文件,如此反复,因为是顺序的,所以写入效率较高。
2.2 ConsumeQueue 消息逻辑队列
ConsumeQueue是指存储消息在CommitLog上的索引,一个MessageQueue一个文件,记录当前MessageQueue被哪些消费者组消费到了哪一条CommitLog。它有如下特征:
- ComsumeQueue的结构组成共 20 个字节,包含 8 字节的 commitlog 物理偏移量、4 字节的消息长度、8 字节 tag hashcode
- ConsumeQueue 里只存偏移量信息,内容精悍。加载到内存中,操作效率非常高。
- 一致性保障,CommitLog 里存储了 ConsumeQueues、Message Key、Tag 等所有信息,在 ConsumeQueue 丢失或者故障时候,数据可快速回复。
- 因为每个Topic下可能有多个Queueu,所以存储结构为:HOME/store/consumequeue/{topic}/{queueId}/{fileName}。
2.3 IndexFile 索引文件
IndexFile 是一种可选索引文件,提供了一种可以通过 key 或时间区间来查询消息的方法,并且这种查找消息的方法不影响发送与消费消息的主流程。它的特征如下:
- 算法原理:IndexFile 索引文件的底层实现 为 hash 索引,可以对照 Java 的HashMap比较,通过计算 Key 的 hashcode, 取余获得 hash 槽,并通过拉链法解决哈希冲突。
- 大小限制:IndexFile 以创建时间戳命名,单个 IndexFile 文件大小约为 400M,一个 IndexFile 可以保存 2000W 个索引。
通过上面的三个部件说明可以了解到,RocketMQ 消息存储结构主要是由 CommitLog,ConsumeQueue,IndexFile 三部分组成的。当我们发送消息的时候,会执行如下过程:
- 消息格式化成 CommitLog的字段结构,并按照顺序写入到CommitLog 文件中。
- Broker会按照 ConsumeQueue 的字段结构的要求创建一条索引记录。
- 按需创建IndexFile索引文件。

3 存储的执行过程
通过上面我们已经了解到了,Kafka 和 Rocket 均支持 10W+ 级别的吞吐,那么上述的存储结构是如何保持这样的高超性能的呢?

- 之前的章节我们已经了解到,Broker 启动时同步启动 NettyRemotingServer 进行端口监听,等坐等客户端的连接。
- 当客户端发送请求时,NettyRemotingServer WorkerGroup 处理可读事件,执行 processRequestCommand 处理来源消息数据。
- 接收到消息之后就需要存储下来了,DefaultMessageStore对数据进行校验,校验如下,校验完成之后发送存储指令。
- Broker 无响应时拒绝消息写入
- Broker 角色 为 SLAVE 时也拒绝写入
- 判断是否支持写入,不支持写入时也拒绝
- topic length 小于等于 256 字符,否则拒绝消息写入
- 消息 length 小于等于 65536 字符,否则拒绝消息写入
- PageCache 繁忙时报错误消息,无法写入
- DefaultMessageStore 调用 CommitLog.putMessage 存入消息
- 获取可以写入的 CommitLog 进行写入
- CommitLog(每个CommitLog默认1G大小) 对应 MappedFile(程序视角),当有多个 MappedFiled 时,组成 MappedFileQueue。
- MappedFile 持有物理 CommitLog 的 fileChannel (Java NIO 文件读写的通道),但并没有通过 fileChannel 直接访问物理 CommitLog 文件,而是映射到一个 MappedByteBuffer,并把序列化后的消息写入这个 ByteBuffer 中,已达到提升执行效率的目的。
- 最后写入 MappedFile 相对应的 CommitLog 文件中。
4 总结
- 理解好RabbitMQ 中 Broker 存储的组成要素 CommitLog,ConsumeQueue,IndexFile。
- 当 Broker 收到消息存储请求时,通过调用 CommitLog 对应的 MappedFile,把消息写入MappedFile的MeppedByteBuffer(内存映射)。
Original: https://www.cnblogs.com/wzh2010/p/16631107.html
Author: Hello-Brand
Title: MQ系列8:数据存储,消息队列的高可用保障
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/363509/
转载文章受原作者版权保护。转载请注明原作者出处!