git workflow 深入

只会 git clone``git pull``git commit``git push感觉有点 low 了,这里深入写 git workflow

[用💻emoji key代表贡献者贡献方面情况](https://allcontributors.org/docs/en/emoji-key)``[常用实践工作流](https://juejin.cn/post/6844903455933333517)

基本概念

工作区是你的文件系统的实际目录
暂存区是git暂存的相对于上个提交的修改,

  • .git/index目录下
  • git add可以把改动后的文件添加到暂存区
  • 提交是把暂存区的内容更改到版本库,所有工作区更改都应放到暂存区

版本库是git的当前提交的版本,在.git目录下

常用命令

一般在实际的企业级项目开发时,你需要去更新到一个特定的分支。
git reset <commit_id> --soft:撤销对应的提交(用HEAD无效),

  • soft工作区暂存区都不变,应当用这个选项
  • mixed工作区不变,但暂存区清空默认值
  • hard工作区暂存区都清空

    与远端交互

    git pull origin branchname:从origin远端拉取branchname分支的代码,一般本地分支和远端分支是一样的,或者直线的(?。
    git fetch origin branchname:从origin远端将branchname的代码拉下来。但是不会合并

    多分支开发

    git branch
    git branch branchname:新建一个分支名的分支
    git branch --set-upstream-to=origin/remoteBranchName localBranchName:可以将本地分支与远程分支关联,远程分支可以不存在,然后推上去

git branch -d branchname:删除该分支,不过要求该分支已经被合并
git checkout branchname:将当前分支切换到branchname分支
git checkout -b branchname:新建并切换到对应分支。
注意切换分支时,工作区文件会被另一分支的状态覆盖,需要提前保存
git merge source:将source分支合并到当前分支
比如,你在日常开发的时候,维护一个日常dev分支,你自己起了一个大的功能分支feat,你需要定期同步dev分支的代码,解决方案:

  1. 就是fetch+merge。
    但是请注意之前先stash一下,不然目前没有提交上的代码将会丢失
    不太行
  2. [git rebase](https://blog.csdn.net/weixin_42310154/article/details/119004977)
    你在你的分支mindmap下,使用git rebase master可以同步master分支的代码,且你的分支的提交都是在原有变更之后的,不会出现merge的提交顺序错乱的问题
  3. 提交操作

    git cherry-pick:可以将一个分支的某些提交移到当前分支前面,可以用来把之前的提交挪到最上面

撤销

可以通过git reflog,pick要撤销到的commitid,然后做撤销
git reset等有效。
但是对于git rebase等操作无效,这种情况使用git cherry-pick

修改暂存

git stash可以把当前代码相对git state的变动缓存,届时可以恢复
(什么时候可以恢复?什么时候又会冲突

会用到的工具

[一个总体的小说明文章](https://juejin.cn/post/6878592895499108365)

  1. npx husky-init
  2. npm install --save-dev @commitlint/config-conventional @commitlint/cli lint-staged
  1. "commitlint": {
  2. "extends": [
  3. "@commitlint/config-conventional"
  4. ]
  5. },
  6. "lint-staged": {
  7. "*.{less,md}": [
  8. "prettier --write"
  9. ],
  10. "*.js?(x)": [
  11. "prettier --write",
  12. "eslint --fix"
  13. ],
  14. "*.ts?(x)": [
  15. "prettier --parser=typescript --write",
  16. "eslint --fix"
  17. ]
  18. },

🐶husky

[源码分析](https://juejin.cn/post/7055294717335961608)

可以容易的在提交时执行命令

安装这个需要初始化一下.husky文件夹。用npx husky-init做一下就没问题
发现一个相关工具:yorkie yorkie https://juejin.cn/post/6844903816400207880

commitlint

规范提交信息,默认提交信息格式如下所示: type[scope][!]: description (空行) body (空行) footer

默认提交信息标准参照了[约定式提交规范](https://www.conventionalcommits.org/zh-hans/v1.0.0/#%e7%ba%a6%e5%ae%9a%e5%bc%8f%e6%8f%90%e4%ba%a4%e8%a7%84%e8%8c%83)``[Angular 提交约定](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines)。下面是具体说明:
type
build: 更改构建流程或者外部依赖 (example scopes: gulp, broccoli, npm)
chore: 对构建过程或辅助工具和库(如文档生成)的更改
ci: 对 CI 脚本和配置的改变 (example scopes: Travis, Circle, BrowserStack, SauceLabs)
docs: 仅文档变化
feat: 加入新特性
fix: A bug fix
perf: 性能提升
refactor: 代码重构,不修复 bug,不加入新特性
revert: 回退之前的提交。这时body应该是This reverts commit <hash>.,其中hash是被回退提交的 SHA
style: 对代码风格的改变,不影响
test: 加入新的测试或更正现有的测试
!:表示是一个breaking change需要大型提交
scope:可以用/``\``,隔开
如果相应npm包做了更变,用这个
此外还可以写自己项目的模块定义等别的。这个可以自定义
footer
#31, #34等自动关联到对应的issue


安装时,需要安装好包,然后在以下文件中写入配置:

  1. "commitlint": {
  2. "extends": [
  3. "@commitlint/config-conventional"
  4. ]
  5. },
  1. #!/bin/sh
  2. . "$(dirname "$0")/_/husky.sh"
  3. npx --no-install commitlint --edit ""

按照这样的设定,写提交会稍微麻烦一点。这改变了你在vscode上点一下按钮就🆗的习惯。所以应该这么做:
image.pngimage.png
提交时点击上图的编辑按钮填好表单,在save,然后提交

lint-staged

提交的时候用eslint等修一下代码

这个貌似只要安装好配置好就行了,不用管太多。
目前没在上面遇到坑。遇到了再说。

changelog

https://www.npmjs.com/package/standard-version
使用 np 来完成提交发布工作流,这里推荐使用conventional-changelog-cli自动生成changelog
首先安装包到 dev,然后填写npm version命令为

zsh

zsh默认有git插件,有很多git命令的简写:去上面链接里面查

vim

首先你要知道vim的状态机:
前端工程/相关工具 - 图3

npm

https://juejin.cn/post/6987179395714646024
package.json dependencies 的排列一定要按字母顺序排列(别问我怎么知道的)

node_modules

https://juejin.cn/post/6844903870578032647
通过 unpkg 后面输入包名和版本,可以查看这个 npm 包的文件信息,如 package.json

package.json

dependencies 的排列一定要按字母顺序排列(别问我怎么知道的)
如要重新安装 node_modules,请将node_modulespackage-lock.json一起删除后,再npm install
peerDependencies不知道是必须是直接安装依赖还是可以传递依赖。
目前找到的文章:
(可能比较老了)

npm scripts(shell)

https://juejin.cn/post/6883665888348733453
https://juejin.cn/post/6844903816987410439

生命周期脚本

prepublish:在打包和发布包之前运行,在npm install没有任何参数的本地运行。
prepare:在打包和发布包之前运行,在本地npm install:没有任何参数,以及安装git依赖项时运行。这是在之后运行prepublish,但是之前prepublishOnly
prepublishOnly:仅在准备和打包之前运行npm publish。
prepack:前运行压缩包(npm pack,npm publish并安装git的依赖时)
postpack:在生成压缩包并移动到其最终目的地之后运行。
publish postpublish:发布包后运行
preinstall:包安装之前运行
install``postinstall:包安装后运行。默认:node-gyp rebuild,如果binding.gyp包的根目录中有一个文件而您尚未定义自己的脚本install或preinstall脚本,npm将默认install使用node-gyp进行编译。
preuninstall``uninstall:在包卸载之前运行。
postuninstall:在包卸载之后运行。
preversion:在碰撞包版本之前运行。
version:碰撞包版本之后,但提交之前运行。
postversion:碰撞包版本之后,提交之后运行。

部署

纯前端原生html、css、js可以直接打开html运行。
如果是搞一个纯前端的项目,可以直接通过静态部署的方式,以index.html为入口部署单页应用。
但是一旦涉及到前后端联合,你就需要好好注意一下了。

与 node_modules

在项目中执行npm i安装时,会安装项目下dependencies``devDependencies依赖包
安装依赖包时,只会安装依赖包dependencies
对于三种dependencies的定位不再赘述。只是分情况讨论:

  1. 纯前端应用
    纯前端应用可以说完全不需要关心三种dependencies的区别。因为部署不涉及npm安装包,部署的是打包产物(index.html等)
  2. 前端组件/组件库
    这种情况下,尤其需要注意三种dependencies的配置问题,看后面的发布 npm 包部分
  3. 前后端联合
    这时后端就需要注意dependenciesdevDpendencies的区别了。具体部署在服务器上不需要安装

    发布 npm 包

    https://zhuanlan.zhihu.com/p/344951970
    https://juejin.cn/post/6844903870678695943
    发布时,一定记得使用官方源。尤其是你一般使用镜像的时候

    组件/组件库

    就现在来说(2022/4/12),做 react 组件库最优的解决方案是 dumi 可以看我的 react 笔记,上面有 umi/dumi 的详细踩坑记录

https://juejin.cn/post/6844903928316821517
[基于 antd 封装组件并发布](https://zhuanlan.zhihu.com/p/80754775)
一些需要注意的:

  1. 开发组件库不能使用cra。这个东西是做react单页应用的,不能应用于做组件库

    依赖原则

    最终构建产物一般是lib,里面是js和.d.ts文件
    如果只有一个组件,可以使用module指定直接引用所拿到的js,不指定默认是项目文件夹下index.js
    如果是react``antd这种非常知名且影响项目全局的库,写入peerDependenciesdevDependencies,千万不要写入dependencies

    这一点使用dumi额外注意,由于一些原因,不要在node_modules显式安装react``react-dom,否则可能会出现两个react实例的情况。 另外antd也不要装,装@umijs/preset-react就有默认引入依赖了

如果是不影响全局的不太知名的,而且不以以上库作为dependencies依赖的(组件库不应该把这些库作为dependencies依赖),可以写入dependencies,这种重复其实没事。
如果在生产模式下(组件库打包不打入依赖),用不着的,全放入devDependencies

webpack配置

首先,发布组件/组件库到npm不使用create-react-app!
不但项目目录不行,docs也不行,cra没法容易的改entry,除非你在docs下面新建package.json来配然后遇到别的问题

package.json

注意,

nodejs应用

配置注意事项

如果包在peerDependencies中,请把该包移到devDependencies

np

使用 np 来做 npm 包发布与更新。
具体执行命令时,直接在命令行输入np即可,会通过交互的方式完成所有需要的步骤。
注意事项:

  1. 默认会清空node_modules重装,加入--no-cleanup选项。
    毕竟umi的依赖和node_modules构成都是非常高危的存在。。。

    写一个 npm cli

    https://juejin.cn/post/6844903702453551111
  • 设置package.json中的bin,加入字段cli-name: entry.js
  • npm link之后,你就可以直接在你本机调用了
  • process.argv以数组的形式展示命令行参数,前两个分别是node程序的路径脚本存放的位置
  • 第三个参数开始就是你命令行输入的参数,但是只会以空格分隔,没有约定的参数规则

webpack

https://juejin.cn/post/6844904094281236487

loader

对于一个使用多个loader的规则,是从后往前执行
对于 css loader,style-loader,前者将css转为js,后者将js化的css转到html的style标签上去
raw-loader加载原始内容
file-loader把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件 (处理图片和字体)
url-loader:与 file-loader 类似,区别是用户可以设置一个阈值,大于阈值会交给 file-loader 处理,小于阈值时返回文件 base64 形式编码 (处理图片和字体)
Loader 本质就是一个函数,在该函数中对接收到的内容进行转换,返回转换后的结果。
在 module.rules 中配置,作为模块的解析规则,类型为数组。每一项都是一个 Object,内部包含了 test(类型文件)、loader、options (参数)等属性。

plugin

Plugin 就是插件,基于事件流框架 Tapable,插件可以扩展 Webpack 的功能,在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
在 plugins 中单独配置,类型为数组,每一项是一个 Plugin 的实例,参数都通过构造函数传入。

打包结果

默认打包结果是一个bundle.js和index.html文件。如果有一些别的loader和plugin,也会导出别的文件。
如果是多入口打包,出来的js文件会是多个。

webpack.config.js

外部依赖

防止将某些 import 的包(package)打包到 bundle 中,而是在运行时(runtime)再去从外部获取这些扩展依赖(external dependencies)
配置形式:

  1. module.exports = {
  2. //...
  3. externals: {
  4. // 字符串形式
  5. jquery: 'jQuery',
  6. },
  7. };

多配置合并

  1. const merge = require('webpack-merge');
  2. const baseConfig = require('./webpack.base.js')
  3. const prodConfig = {}
  4. module.exports = merge(baseConfig, prodConfig)

rollup

模块系统

https://juejin.cn/post/6935973925004247077
https://juejin.cn/post/7002031102390976525

ejs(ES 6 Module)

ES module 通过 import结构赋值其它js文件 export得到的对象。
其中 export default直接导出,其它的需要对象属性解构赋值的方式引入。
此外,如果 import引入的是一个文件夹,会默认引入文件夹下的 index.js文件。只能在文件开头引用。
可通过 import 引入 json 文件。
如果想要不通过 babel 等方式(create react app等是使用的这种方式)使用 ES module 的引入方式(一般是 nodejs 后端应用),需要在 package.json后加入type: "module"

import 非js文件

这一部分是 webpack 等打包工具的支持。
webpack 通过 loader 来读取这些文件。这些文件读取之后没有输出(不返回变量),虽然不知道之后会怎样。
详见 https://www.webpackjs.com/concepts/#loader

cjs(commonJS)

https://juejin.cn/post/6844903576309858318
这个是在 nodejs 项目中来引用。虽然这两种方式的底层实现不同,但是不交融的情况可以一起使用。
commonjs 通过 require('js-script')来引用js文件输出的 module.exports对象。可以在任意位置引用。

AMD

UMD

eslint/prettier

https://eslint.bootcss.com/
https://eslint.org/
[umi 4 解决方案](https://mp.weixin.qq.com/s/9dU9pC7SbTfuZOGhEaRT7w)
npm install babel-eslint eslint eslint-config-prettier eslint-loader eslint-plugin-vue eslint-plugin-prettier prettier —save-dev
eslint和prettier在一些地方还是有冲突的。比如switch case语句,他俩的格式风格。(这使得我取消了eslint indent 规则,暂时没找更好的解决方案)
最佳实践

  1. 对于代码风格:全部交给 prettier,eslint 不定义任何规则。
    eslint 只对代码质量进行约束。
  2. 不继承任何规则 Config

    uml

    https://zhuanlan.zhihu.com/p/76948461

    时序流程图

    前端工程/相关工具 - 图4前端工程/相关工具 - 图5前端工程/相关工具 - 图6前端工程/相关工具 - 图7前端工程/相关工具 - 图8前端工程/相关工具 - 图9前端工程/相关工具 - 图10前端工程/相关工具 - 图11前端工程/相关工具 - 图12前端工程/相关工具 - 图13前端工程/相关工具 - 图14