未整理

未整理

复习目录

  • js
  • css
  • vue
  • node
  • 项目
  • echarts
  • d3
  • element
  • electron
  • 各种库
    • polyfill
  • 各种库的 index

未整理

  • echarts输出到dom里是什么元素

  • 进程和线程的区别
  • import懒加载底层原理,分包,为什么可以显示到界面
  • 网站怎么支持多语言
  • refresh token
  • 编写一个自定hook,涉及useState,useEffect,async/await
  • Eslint代码检查的过程
  • JS的加载会阻塞浏览器渲染吗
  • Webpack项⽬中通过script标签引⼊资源
  • 应⽤上线后,怎么通知⽤⼾刷新当前⻚⾯
  • HTTP是⼀个⽆状态的协议,那么Web应⽤要怎么保持⽤⼾ 的登录态呢
  • 如何检测⽹⻚空闲状态(⼀定时间内⽆操作)
  • 为什么Vite速度⽐Webpack快
  • 列表分⻚,快速翻⻚下的竞态问题
  • 优化图片
  • OAuth2.0是什么登录⽅式
  • 后端⼀次性返回树形结构数据,数据量⾮常⼤,前端该如何 处理
  • token进⾏⾝份验证了解多少
  • 在前端应⽤如何进⾏权限设计
  • 浏览器的存储有哪些
  • 为何现在市⾯上做表格渲染可视化技术的,⼤多数都是 canvas,⽽很少⽤svg的
  • 前端有哪些跨⻚⾯通信⽅式

统计

统计

dataview

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
console.log(dv.pages(`"Codes"`))
const groups = dv.pages(`"Codes"`).groupBy(p => p.file.folder)
//不想展示的文件夹
const folderArr = ["MOD","后端","python","本地","git"]
for (let group of groups) {
if (group.key!="Codes" && folderArr.filter(f => group.key.includes(f)).length == 0) {
dv.paragraph(group.key);
dv.table(["Name","key points","阅读次数"],
group.rows
.sort(k => k.file.name, 'asc')
.map(function(k){
return [k.file.link,
k["key-points"]?k["key-points"].toString():" ",
`<progress value="${k["times-of-view"]}" max="10"></progress>`,
]
}))
}
}

统计print

统计

dataview

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
const {createButton} = app.plugins.plugins["buttons"]
const groups = dv.pages(`"Codes"`).groupBy(p => p.file.folder)
//不想展示的文件夹
const folderArr = ["MOD","后端","python","本地","git"]
let cdata = []
dv.el("b",
createButton({
app,
el: this.container,
args: {name: '导出',class:'tiny'},
clickOverride: {click: downloadCSV, params: [cdata,"data.csv"]}
})
);
for (let group of groups) {
if (group.key!="Codes" && folderArr.filter(f => group.key.includes(f)).length == 0) {
dv.paragraph(group.key);
let tableData = dv.table(["Name","key points","阅读次数"],
group.rows
.sort(k => k.file.name, 'asc')
.map(function(k){
cdata.push([
k.file.path.replace(/Codes\/|\.md/g, ''),
k["key-points"]?k["key-points"].toString():" "
])
return [k.file.link,
k["key-points"]?k["key-points"].toString():" ",
k["times-of-view"]]
}));
}
}
console.log(cdata)
// 将二维数组转换为 CSV 格式的字符串
function arrayToCSV(data) {
return data.map(row => {
return row.map(cell => {
// 如果单元格包含逗号、换行符或双引号,需要用双引号包裹
if (typeof cell === "string" && (cell.includes(",") || cell.includes("\n") || cell.includes('"'))) {
return `"${cell.replace(/"/g, '""')}"`; // 替换双引号为两个双引号
}
return cell;
}).join(","); // 用逗号分隔单元格
}).join("\n"); // 用换行符分隔行
}
// 下载 CSV 文件
function downloadCSV(data, filename = "data.csv") {
const csvString = arrayToCSV(data);
const blob = new Blob([csvString], { type: "text/csv;charset=utf-8;" });
const link = document.createElement("a");
if (link.download !== undefined) { // 特性检测
// 创建一个 blob URL
const url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", filename);
link.style.visibility = "hidden";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
//downloadCSV(cdata)

自我介绍

自我介绍

三个阶段
第一个阶段在亚信实习,主要负责前端开发,参与开发了两个项目包括电商服务分析平台和中信集团的企业画像项目,基本独立负责前端开发,使用到 zrender,echarts,bootsript,EasyUI 等技术栈,离职原因
第二阶段在昌信工作

考卷

前端

JavaScript & html

  1. function 创建(2),作用(3),子类型(3)
  2. object 创建(3),属性(3),创建属性,属性的描述 2*4
  3. Array of from isArray length prototype
  4. Array.prototype 修改添加 5 ,查找 5,遍历 4,排序 2,合并,其他
  5. Object 创建 2,获得对象的属性 5,修改对象的属性 2,其他 3
  6. Object.prototype constructor, hasOwnProperty, isPrototypeOf,propertyIsEnumerable,toString,valueOf
  7. String length, name, ptototype, fromCharCode, fromCodePoint, raw
  8. String.prototype 查找 11 ,拼接,截取 3,替换,转换 5,分割,填充,重复
  9. RegExp 属性 source,flags,global,ignoreCase,multiline,lastIndex
  10. RegExp 方法 exec,test,toString
  11. Promise 状态 4方法 3
  12. 方法统计
    • 正则相关 8
    • 回参新数组 4
    • 修改原数组 8
  13. 闭包
  14. 原型链
    1. 原型对象
    2. 对象的原型访问
    3. 继承
    4. constructor
    5. prototype
    6. Prototype __proto__
    7. 四个等式
  15. **运算符
    • instanceof object instanceof constructor
    • typeof(9)typeof obj 回参 string
    • ++前置后置
    • delete object['property'] 回参布尔
    • ?? ??=
  16. 运算顺序 括号,一元,算数,关系,相等,逻辑,赋值,逗号
  17. js 选择器 5
  18. 事件循环 (Event Loop)
    • 事件循环
    • 调用顺序 5
  19. es6 (5)
  20. this (6)
  21. 正则正则表达式
    • 表达式 3
    • 元字符
    • 量词 6
  22. HTML5 9
  23. Cookie 属性 6
  24. 严格模式 5

CSS

  1. CSS 选择器 CSS 选择器
    1. 基本选择器 #.tag
    2. 组合选择器 后代 ,子代 >,相邻兄弟 +,通用兄弟 ~
    3. 伪类选择器 链接,结构 :nth-child(n),动态 :focus
    4. 伪元素选择器 ::before
  2. CSS 选择器权重!important 10000,内联 1000,id100,类属性伪类 10,元素伪元素 1,通用,子,兄弟,后代 0
  3. CSS 动画 CSS 动画
    1. 渲染过程 样式计算、布局、绘制和合成
    2. GPU 加速 transform,opacity
    3. 重排
      1. DOM 结构变化
      2. 元素尺寸变化
      3. 内容变化
      4. 样式计算
      5. 其他滚动条,元素聚焦
    4. 重绘 是指在元素的几何属性没有变化,但是元素的外观(如颜色、阴影、边框颜色等)发生变化时,浏览器需要重新绘制元素的过程 CSS滤镜效果
  4. CSS 居中居中
    1. 居中 水平 3,垂直 2
    2. 水平垂直 flex,grid,绝对定位+transform,table-cell
  5. CSS3 CSS3 新内容
    1. 布局相关 2
    2. 动画与效果 3
    3. 视觉效果 3
    4. 字体与文本 2
    5. 其他特性 3
  6. flex
    1. 容器 flex container
      • flex-direction:定义主轴的方向(是水平还是垂直)。
      • flex-wrap:定义项目是否应该在必要时换行。
      • flex-flowflex-directionflex-wrap的简写形式。
      • justify-content:定义项目在主轴上的对齐方式。
      • align-items:定义项目在交叉轴上的对齐方式。
      • align-content:定义多行项目在交叉轴上的对齐方式。
    2. 项目 flex items
      • order:定义项目的排序顺序。数值越小,越靠前。
      • flex-grow:定义项目的放大比例。如果容器有多余的空间,项目可以放大。
      • flex-shrink:定义项目的缩小比例。如果容器空间不足,项目可以缩小。
      • flex-basis:定义项目在主轴上的初始大小。
      • align-self:允许单个项目有与其他项目不同的对齐方式。
      • flexflex-growflex-shrinkflex-basis的简写形式,默认值为0 1 auto

网络

  1. TCP/IP 协议
    1. 链路层 以太网、Wi-Fi、PPP
    2. 网络层 IP
    3. 传输层 TCP、UDP
    4. 应用层 HTTP、FTP、DNS、SSH
  2. OSI(开放系统互连)七层模型:物理层,数据链路层,网络层,传输层,回话层,表示层,应用层
  3. http HyperText Transfer Protocol,超文本传输协议
    • http 请求 请求头,请求体;
    • http响应 状态行,相应头,响应体
    • 特点 无状态,无连接,媒体独立,简单快速
    • http2/3 二进制分帧、多路复用、服务器推送、头部压缩,性能和可靠性
    • https Secure
  4. WebSocket 在单个 TCP 连接上进行全双工通信的方式
    • 特点
      • 长连接 持久连接
      • 全双工通信 服务器和客户端之间同时进行数据的发送和接收
      • 基于 HTTP 的握手->WebSocket 握手-> WebSocket 连接
      • 支持二进制数据传输Blob 或 ArrayBuffer
    • WebSocket API
      • 属性
        • readyState 0,1,2,3
        • bufferedAmount表示已发送但尚未被浏览器传输的数据量(以字节为单位)
        • extensions表示服务器选择的 WebSocket 扩展
        • protocol
        • url
      • 方法
        • constructor(url, [protocols])
        • send(data) 向服务器发送数据
        • close([code], [reason])
      • 事件 socket.addEventListener('open',(e)=>{}) 等价 ws.onopen
        • open:当 WebSocket 连接成功建立时触发。
        • error:当 WebSocket 连接发生错误时触发。
        • message:当从服务器接收到数据时触发。
        • close:当 WebSocket 连接关闭时触发。
    • 工作流握手, 数据传输,关闭
    • 心跳用于维持客户端与服务器之间长连接的一种保活机制
      • 客户端建立连接
      • 客户端定时发送心跳数据包
      • 服务器在设定时间内没有收到心跳,会发送关闭连接请求
      • 服务器定时发送心跳数据包,客户端接收并返回响应
      • 客户端在设定时间内没有收到心跳,会重新连接

Vue

  1. Vue 基本知识
    • 基础
      • 初始化
      • 常用模板语法
      • 生命周期函数
      • 数据和方法 data() & methods
      • 计算属性和侦听器 computed & watcher
    • 组件
      • 组件 component
        • 全局,局部
        • 命名方式
      • 组件传值
      • 插槽 slot 和具名插槽
      • 动态组件和异步组件
    • 动画
    • 高级语法
      • 混入mixin
      • 自定义指令directive
      • 传送门teleport Vue3
      • render
      • plugin
    • composition api
      • setup
      • ref 和 reactive
      • toRef 和 toRefs
      • context 参数 3
      • 计算属性computed
      • watch和watchEffect
      • provide, inject
      • 模版 ref
  2. Vue 特点 数据绑定,虚拟 DOM,事件,计算属性和侦听器,指令系统,keep-alive,$属性 6$ 方法 8
  3. Vue 组件通信
    • props 和 $emit
    • none-props 和 $attrs
    • 插槽 slot
    • Vuex/Pinia
    • provide/inject
  4. Vue 生命周期函数
    1. Vue2
      • 创建 beforeCreate,created
      • 挂载beforeMount,mounted
      • 更新 beforeUpdate,updated
      • 销毁 beforeDestroy,destroyed
      • keep-alive activated,deactivated
    2. Vue3
      • setup 在 created,移除创建 2 个
      • 挂载beforeMount,mounted
      • 更新 beforeUpdate,updated
      • 销毁 beforeUnmount,unmounted
      • keep-alive activated,deactivated
      • 渲染onRenderTracked,onRenderTriggered
  5. Vuex
    • state 存储应用的状态
    • mutations 用于同步修改状态的方法
    • actions 用于异步操作,最终通过调用 mutations 修改状态
    • getters 类似于 Vue 的计算属性,用于派生状态
    • 顺序
      1. dispatch 方法,派发一个 action,名字叫做change
      2. 感知到 change 这个action,执行store 中 actions 下面的 change 方法
      3. commit 提交一个叫做 change 的数据改变
      4. mutation 感知到提交的change改变,执行 change 方法改变数据
  6. pinia State(状态):存储需要共享的数据。Getters(计算属性):基于状态的派生值。Actions(操作方法):用于修改状态的函数
  7. Vue 插件 Vue-devtools,router,Vuelidate,Axios,状态管理,lazyload

其他

  1. 兼容性
    • CSS 解析差异
    • JavaScript API
    • 响应式布局
    • 图片兼容性
    • 字体兼容性性
  2. 安全 https,数据加密,安全储存,权限控制,输入验证
  3. 跨域 CORS 域名、协议或端口不同
    1. CORS 头部
    2. jsonp 淘汰
    3. 文档域
    4. PostMessage
    5. WebSocket
    6. 代理服务器
  4. 登录鉴权
    1. cookie 自动携带,服务器存储;安全风险,太小,
    2. token(JWT JSON Web Token)无状态,安全,支持跨域;需要手动携带,有存储风险
    3. Session 安全,服务控制;服务器负担,跨域限制
    4. OAuth2.0 标准化,安全;复杂
  5. cookie 设置 HttpOnly 和 Secure 标志,防止跨站脚本攻击和非安全传输
  6. electron
    1. 主进程
    2. 渲染进程
    3. preload
    4. 通信 ipcMainipcRenderer
    5. 常用模块
      1. dialog
      2. menuMenuItem 模块
      3. shell 模块用于在系统中打开外部链接、文件管理器等
      4. clipboard 模块用于读写系统剪贴板的内容
      5. powerMonitor 模块用于监听系统电源状态,如系统唤醒、待机
      6. systemPreferences 模块用于访问系统偏好设置,如颜色模式
      7. globalShortcut 模块用于注册全局快捷键,即使应用不活跃时也能捕获键盘输入
      8. fs
      9. chokidar 监听文件变化
    6. 缓存

搜索

搜索

深度优先搜索和广度优先搜索

深度优先搜索(Depth-First Search,DFS)和广度优先搜索(Breadth-First Search,BFS)是两种常见的图(或树)遍历算法,它们在数据结构和算法设计中有着广泛的应用。以下是对这两种算法的详细解释:

1. 深度优先搜索(DFS)

深度优先搜索是一种“尽可能深地搜索树的分支”的算法。它的基本思想是从一个节点开始,沿着路径尽可能深入地搜索,直到无法继续为止,然后回溯到上一个节点,继续探索其他分支。

实现方式

  • 递归实现:使用递归函数,每次递归调用处理一个节点,然后继续处理它的子节点。
  • 非递归实现:使用栈(Stack)来模拟递归过程。将节点压入栈中,每次从栈中弹出一个节点,处理它的子节点,并将子节点压入栈中。

特点

  • 优点
    • 实现简单,递归版本尤其简洁。
    • 对于某些问题(如迷宫问题、连通性问题)效率较高。
  • 缺点
    • 可能会陷入无限循环(如果没有正确处理访问过的节点)。
    • 在某些情况下,可能会占用较多的系统栈空间(递归实现)。

应用场景

  • 迷宫求解
  • 搜索树的遍历
  • 图的连通性判断
  • 求解组合问题(如八皇后问题)

2. 广度优先搜索(BFS)

广度优先搜索是一种“逐层搜索”的算法。它的基本思想是从一个节点开始,先访问所有与该节点相邻的节点,然后再逐层扩展,直到找到目标节点或遍历完所有节点。

实现方式

  • 使用队列(Queue)来实现。将起始节点加入队列,每次从队列中取出一个节点,处理它的所有未访问的邻接节点,并将这些邻接节点加入队列。

特点

  • 优点
    • 能够找到从起点到目标的最短路径(在无权图中)。
    • 不容易陷入无限循环(只要正确处理访问过的节点)。
  • 缺点
    • 需要存储大量的节点,空间复杂度较高。
    • 实现相对复杂,需要维护队列。

应用场景

  • 最短路径问题(如无权图的最短路径)
  • 社交网络中的朋友关系分析
  • 图的层次遍历
  • 二叉树的层次遍历

3. 深度优先与广度优先的比较

特性 深度优先搜索(DFS) 广度优先搜索(BFS)
数据结构 栈(递归或显式栈) 队列
遍历顺序 深入到底,再回溯 逐层遍历
空间复杂度 较低(递归深度) 较高(队列存储所有节点)
时间复杂度 O(V + E)(V是节点数,E是边数) O(V + E)
最短路径 不一定找到最短路径 在无权图中能找到最短路径
应用场景 迷宫求解、连通性问题 最短路径问题、层次遍历

4. 代码示例

以下是深度优先搜索和广度优先搜索在图遍历中的简单实现(Python):

DFS代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def dfs(graph, start):
visited = set()
stack = [start]
while stack:
node = stack.pop()
if node not in visited:
visited.add(node)
print(node)
# 将未访问的邻接节点加入栈
stack.extend([n for n in graph[node] if n not in visited])
# 示例图
graph = {
'A': ['B', 'C'],
'B': ['D', 'E'],
'C': ['F'],
'D': [],
'E': ['F'],
'F': []
}
dfs(graph, 'A')

BFS代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from collections import deque
def bfs(graph, start):
visited = set()
queue = deque([start])
while queue:
node = queue.popleft()
if node not in visited:
visited.add(node)
print(node)
# 将未访问的邻接节点加入队列
queue.extend([n for n in graph[node] if n not in visited])
# 示例图
graph = {
'A': ['B', 'C'],
'B': ['D', 'E'],
'C': ['F'],
'D': [],
'E': ['F'],
'F': []
}
bfs(graph, 'A')

总结来说,深度优先搜索和广度优先搜索各有优缺点,选择哪种算法取决于具体问题的需求。

快速找到一个树形数组中的某个值

在JavaScript中,如果需要快速找到一个树形数组(Tree-like Array)中的某个值,可以通过深度优先搜索(DFS)或广度优先搜索(BFS)来实现。由于树形结构通常是递归定义的,DFS通常更适合这种场景,因为它可以通过递归来自然地遍历树的每个节点。
以下是一个基于DFS的实现方法,用于快速找到树形数组中的某个值。假设树形数组的每个节点是一个对象,包含id(唯一标识符)和children(子节点数组)。

示例树形数组结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const tree = [
{
id: 1,
name: "Node 1",
children: [
{
id: 2,
name: "Node 2",
children: [
{
id: 4,
name: "Node 4",
children: []
}
]
},
{
id: 3,
name: "Node 3",
children: []
}
]
}
];

实现方法:基于DFS的递归查找

以下是一个函数,用于查找树形数组中具有特定id的节点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function findNode(tree, targetId) {
// 遍历当前层的节点
for (const node of tree) {
// 如果当前节点的id匹配目标值,直接返回该节点
if (node.id === targetId) {
return node;
}
// 如果当前节点有子节点,递归查找子节点
if (node.children && node.children.length > 0) {
const result = findNode(node.children, targetId);
// 如果在子节点中找到目标节点,返回结果
if (result) return result;
}
}
// 如果遍历完所有节点仍未找到,返回null
return null;
}
// 示例调用
const targetId = 4;
const foundNode = findNode(tree, targetId);
console.log(foundNode ? `Found: ${JSON.stringify(foundNode)}` : "Node not found");

代码解释:

  1. 遍历当前层的节点:通过for...of循环遍历树形数组的每一层。
  2. 检查当前节点是否匹配目标值:如果当前节点的id等于目标值,直接返回该节点。
  3. 递归查找子节点:如果当前节点有子节点(children),递归调用findNode函数在子节点中查找目标值。
  4. 返回结果:如果在子节点中找到目标节点,返回结果;如果遍历完所有节点仍未找到,返回null

优点:

  • 简洁高效:利用递归自然地遍历树形结构,代码简洁易读。
  • 通用性:适用于任意深度的树形数组。

注意事项:

  1. 性能优化:如果树形结构非常大,递归可能会导致性能问题(如栈溢出)。可以通过非递归方式(使用栈)实现DFS来避免递归深度问题。
  2. 唯一性假设:假设id是唯一的,如果id可能重复,需要根据具体需求调整逻辑。

非递归实现(可选)

如果担心递归深度问题,可以使用显式栈来实现DFS的非递归版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function findNodeNonRecursive(tree, targetId) {
const stack = [...tree]; // 将根节点数组压入栈
while (stack.length > 0) {
const node = stack.pop();
if (node.id === targetId) {
return node; // 找到目标节点
}
if (node.children && node.children.length > 0) {
// 将子节点压入栈
stack.push(...node.children);
}
}
return null; // 未找到
}
// 示例调用
const foundNodeNonRecursive = findNodeNonRecursive(tree, targetId);
console.log(foundNodeNonRecursive ? `Found: ${JSON.stringify(foundNodeNonRecursive)}` : "Node not found");

总结

对于树形数组的查找问题,基于DFS的递归实现是最直观和高效的方法。如果树形结构非常大,可以考虑使用非递归的栈实现来避免递归深度问题。

面试真题

面试真题

  • 布局
  • tree 型数组遍历/深度优先和广度优先搜索
  • array 返回值 Array
  • 封装修改vue 插件
  • 性能实战,插件,组件前端性能优化
  • 性能Performance API
  • lodash 和 json 的区别
  • 事件
  •  ES Modul

优码

  • 自定义指令
  • 生命周期函数
  • 组件 name 的作用
  • keep-alive
  • 表单必填项
  • 组件间传值
  • ❌uesState 伪类
  • ❌webpack 实现大文件拆包
  • 把扁平化数组转换成tree array
  • 字符串找出重复最多的字母

git commit规范

git commit 规范

git commit 规范是团队协作中非常重要的部分,它可以帮助团队成员更好地理解代码的历史变更、快速定位问题,并维护代码库的整洁性。以下是一些常见的 git commit 规范:

1. Conventional Commits 规范

Conventional Commits 是一种流行的规范,适用于需要自动生成变更日志、版本号管理的项目。它要求提交信息遵循以下格式:

1
2
3
<type>[optional scope]: <description>
[optional body]
[optional footer]

主要部分说明

  • <type>:提交的类型,常见的有:
    • feat:新功能(feature)
    • fix:修复错误(bug fix)
    • docs:文档更新
    • style:代码格式化(不影响代码运行的变动)
    • refactor:代码重构(既不是新功能也不是修复错误)
    • test:测试相关(如添加或修改测试用例)
    • chore:构建过程或辅助工具的变动
  • [optional scope]:可选的范围,用于指定提交影响的范围(如模块名或文件名)。
  • <description>:简短描述提交的内容,建议控制在 50 个字符以内。
  • [optional body]:详细描述,可以进一步解释提交的动机、解决的问题等。
  • [optional footer]:用于引用问题编号、关闭 issue 等。

示例

1
2
3
4
feat: add new user authentication feature
This commit adds a new user authentication feature using OAuth 2.0.
It includes the necessary API calls and UI components.
Closes #123

2. Angular Commit Message Conventions

Angular 团队也有一套类似的规范,它在 Conventional Commits 的基础上更详细地定义了提交类型和格式:

1
2
3
4
5
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>

主要部分说明

  • <type>:提交类型,如 featfixdocs 等。
  • (<scope>):作用范围,通常是一个模块或文件名。
  • <subject>:简短描述,建议使用祈使句。
  • <body>:详细描述,可以解释为什么要这么做。
  • <footer>:用于引用 issue 编号、Breaking Change 等。

示例

1
2
3
4
5
feat(user-auth): add OAuth 2.0 authentication
This commit adds OAuth 2.0 authentication to the user module.
It includes the necessary API calls and UI components.
Closes #123
BREAKING CHANGE: The old authentication method is removed.

3. 一般性提交规范

如果你的项目没有严格遵循上述规范,也可以采用以下通用的提交规范:

  • 提交信息清晰简洁:尽量用简短的语句描述提交的主要内容,避免使用模糊的词汇。
  • 使用祈使句:如“Add new feature”而不是“Added new feature”。
  • 分层提交:将一个大的功能拆分成多个小的提交,每个提交只解决一个问题。
  • 避免冗长的提交信息:如果需要详细说明,可以在提交信息中引用相关的文档或 issue 编号。
  • 遵循项目约定:如果项目有特定的提交规范,务必遵守。

4. 工具支持

为了帮助团队成员遵循提交规范,可以使用一些工具:

  • Commitizen:一个命令行工具,可以引导开发者按照规范输入提交信息。
  • Husky + Commitlint:Husky 可以在提交时运行脚本,Commitlint 可以校验提交信息是否符合规范。

5. 其他建议

  • 提交前检查代码:确保代码已经通过测试,没有明显的错误。
  • 合理使用分支:将功能或修复放在独立的分支上,提交后再合并到主分支。
  • 保持提交历史清晰:避免频繁的合并冲突和复杂的提交历史。
    通过遵循这些规范,可以大大提高代码的可维护性和团队协作效率。

gitflow

gitflow

Git之GitFlow工作流 | Gitflow Workflow(万字整理,已是最详)-CSDN博客
GitFlow 是一种流行的分支管理策略,由 Vincent Driessen 在 2010 年提出。它为团队提供了一种清晰的分支结构和工作流程,特别适合多人协作的项目。GitFlow 流程的核心思想是将代码库划分为几个主要的分支,每个分支都有明确的职责,从而确保代码的稳定性和可维护性。

一、主要分支及其职责

(一)main 分支(或 master 分支)

  • 职责main 分支是项目的主分支,代表了当前生产环境中的稳定代码。它只包含已经经过充分测试并准备发布的代码。
  • 操作:通常只有在发布新版本时,才会从其他分支(如 developrelease 分支)合并代码到 main 分支。

(二)develop 分支

  • 职责develop 分支是开发分支,用于集成所有新功能和修复。它是所有开发工作的基础分支。
  • 操作
    • 开发人员从 develop 分支拉取最新代码开始新功能的开发。
    • 完成开发后,将代码合并回 develop 分支。
    • 定期将 develop 分支的代码合并到 main 分支(通过 release 分支)。

(三)feature 分支

  • 职责feature 分支用于开发新功能。每个新功能都有一个独立的分支,以避免相互干扰。
  • 命名规范:通常以 feature/ 开头,例如 feature/new-login-page
  • 操作
    • develop 分支创建 feature 分支。
    • feature 分支上完成开发后,通过 Pull Request(PR)或 Merge Request(MR)将代码合并回 develop 分支。

(四)release 分支

  • 职责release 分支用于准备发布新版本。它允许团队在发布前进行最后的测试和修复。
  • 命名规范:通常以 release/ 开头,例如 release/1.0.0
  • 操作
    • develop 分支创建 release 分支。
    • release 分支上进行最后的测试和修复。
    • 发布完成后,将 release 分支的代码合并到 maindevelop 分支,并打上版本标签(如 v1.0.0)。

(五)hotfix 分支

  • 职责hotfix 分支用于快速修复生产环境中的紧急问题。
  • 命名规范:通常以 hotfix/ 开头,例如 hotfix/fix-login-bug
  • 操作
    • main 分支创建 hotfix 分支。
    • hotfix 分支上完成修复后,通过 PR 或 MR 将代码合并回 maindevelop 分支,并打上版本标签。

二、GitFlow 工作流程

(一)日常开发

  1. 创建 feature 分支
    1
    2
    3
    git checkout develop
    git pull origin develop
    git checkout -b feature/new-feature
  2. 开发新功能
    • feature 分支上进行开发。
    • 完成开发后,提交代码到远程仓库:
      1
      2
      3
      git add .
      git commit -m "Add new feature"
      git push origin feature/new-feature
  3. 合并到 develop 分支
    • 创建 PR 或 MR,将 feature 分支的代码合并到 develop 分支。
    • 审查代码并合并。

(二)发布新版本

  1. 创建 release 分支
    1
    2
    3
    git checkout develop
    git pull origin develop
    git checkout -b release/1.0.0
  2. 准备发布
    • release 分支上进行最后的测试和修复。
    • 如果需要,可以创建 PR 或 MR 将修复同步到 develop 分支。
  3. 发布版本
    • 完成测试后,将 release 分支的代码合并到 main 分支,并打上版本标签:
      1
      2
      3
      4
      5
      git checkout main
      git pull origin main
      git merge release/1.0.0
      git tag -a v1.0.0 -m "Release version 1.0.0"
      git push origin main --tags
    • 同时,将 release 分支的代码合并回 develop 分支:
      1
      2
      3
      git checkout develop
      git merge release/1.0.0
      git push origin develop

(三)紧急修复

  1. 创建 hotfix 分支
    1
    2
    3
    git checkout main
    git pull origin main
    git checkout -b hotfix/fix-login-bug
  2. 修复问题
    • hotfix 分支上进行修复。
    • 提交代码到远程仓库:
      1
      2
      3
      git add .
      git commit -m "Fix login bug"
      git push origin hotfix/fix-login-bug
  3. 合并到 maindevelop 分支
    • 创建 PR 或 MR,将 hotfix 分支的代码合并到 main 分支,并打上版本标签:
      1
      2
      3
      4
      git checkout main
      git merge hotfix/fix-login-bug
      git tag -a v1.0.1 -m "Hotfix version 1.0.1"
      git push origin main --tags
    • 同时,将 hotfix 分支的代码合并回 develop 分支:
      1
      2
      3
      git checkout develop
      git merge hotfix/fix-login-bug
      git push origin develop

三、GitFlow 的优势

(一)清晰的分支结构

  • 每个分支都有明确的职责,便于团队成员理解和协作。

(二)稳定的发布流程

  • 通过 release 分支和 hotfix 分支,确保生产环境的代码始终是稳定的。

(三)支持多人协作

  • 开发人员可以在独立的 feature 分支上工作,避免相互干扰。

(四)版本管理

  • 通过版本标签,可以方便地管理不同版本的代码。

四、GitFlow 的挑战

(一)学习曲线

  • 对于不熟悉 GitFlow 的团队成员,可能需要一定的时间来适应这种工作方式。

(二)分支管理复杂性

  • 随着项目规模的增大,分支的数量可能会变得较多,需要一定的管理成本。

(三)合并冲突

  • 在合并分支时,可能会出现冲突,需要及时解决。

五、GitFlow 的适用场景

GitFlow 适用于以下场景:

  1. 多人协作项目:团队成员较多,需要清晰的分支结构和工作流程。
  2. 需要稳定发布的项目:对生产环境的稳定性要求较高,需要严格的发布流程。
  3. 有明确版本管理需求的项目:需要对不同版本的代码进行管理。

六、GitFlow 的替代方案

虽然 GitFlow 是一种非常流行的分支管理策略,但它并不适合所有项目。以下是一些替代方案:

  1. GitHub Flow:一种更简单的分支管理策略,适用于小型项目或快速迭代的团队。它主要使用 main 分支和 feature 分支,没有 developrelease 分支。
  2. GitLab Flow:结合了 GitFlow 和 GitHub Flow 的优点,支持多种分支管理策略,可以根据项目需求灵活选择。
    通过以上内容,你可以更好地理解 GitFlow 流程及其在项目中的应用。希望这些信息对你有所帮助!