内容简介:在前端的日常工作中,经常会出现“当执行一种操作之前(之后)需要同时执行另一种操作”的情况,比如我们希望在每次git commit之前都运行eslint代码检查、npm install之前检查项目依赖等。作为经典的情况,各类工具都可以让我们在特定的动作发生时触发自定义脚本,这个功能就叫钩子日常经常用到的工具有其中
在前端的日常工作中,经常会出现“当执行一种操作之前(之后)需要同时执行另一种操作”的情况,比如我们希望在每次git commit之前都运行eslint代码检查、npm install之前检查项目依赖等。作为经典的情况,各类 工具 都可以让我们在特定的动作发生时触发自定义脚本,这个功能就叫钩子 hooks
。
日常经常用到的工具有 npm
、 git
、 webpack
,其中的 hooks
用法我们分别介绍一下。
其中 webpack
的hooks是 webpack
为开发者提供的运行时事件钩子,我们能利用它来编写 plugins
,这个就不在这里说了,将来会单独写一篇关于写 plugin
的文章(立个flag╮(╯▽╰)╭)。
npm hooks —— 监听npm操作 / 订阅npm源修改获取通知
目前提到npm hooks,有两个不同概念的操作。
通常意义下的监听npm各类操作的钩子是通过配置 package.json
文件中的 scripts
字段来实现的。
而 npm hooks
则是npm提供的 命令行操作
,目的是为了 订阅你需要的npm package发生的特定改动
,比如可以订阅尤大(误)的新动态等。当然,这项功能需要你自己提供一个域名,并且需要有npm账号且购买服务,所以就不多讨论了╮(╯▽╰)╭,具体参见 npm-hook官方文档
。
npm script hooks
使用方法很简单,在项目的 package.json
中的 scripts
字段加入 "hook": "script"
键值对即可。hook名称由npm提供,script就是能够运行的 shell 语句。下面列几个常用的hook:
npm install npm install npm start npm start
从以上的例子中可以看出,hooks的命名是 pre[op]
为操作之前的钩子, [op]
或 post[op]
为操作之后的钩子。还有很多其他的钩子,具体可以查阅 npm script官方文档
。
由于历史原因,publish相关的钩子会比较特殊,具体原因和修改后的样子都在文档里了,不多介绍。
e.g.
比如项目 npm install
之前依赖一个全局的npm包,用户需要先 npm install -g package
,这时就可以把该操作写到 preinstall
里:
package.json
... "scripts": { "preinstall": "npm install -g package" ... },
当然,shell的部分可以写所有的可以执行的shell语句。如果需要的操作比较多,也可以写shell脚本,然后执行该脚本。对很多前端来说,直接开搞shell脚本比较困难,也可以写node、 python 等脚本,然后用 node script.js
的方式执行也是ok的。
git hooks —— 监听git操作
介绍
git hooks基本跟上面介绍的npm script hooks差不多,也是配置相应的 pre-[op]
、 post-[op]
之类的钩子。
git通过项目根目录下的 .git
目录中的内容来标记一个git库并记录相关信息,这点应该是众所周知了。
git hooks的配置就在 .git/hooks
目录下,以无后缀的脚本文件的形式存在,文件名称即是钩子名称,文件内容是shell脚本,你可以自行添加可执行内容。
一般在刚 npm init
的hooks文件夹中全都是 [hook].sample
示例文件,需要复制并改名为该hook名称才可以正常使用
。
根据git版本不同,可用的hooks也不同,举下跟commit相关的hook例子:
git commit -s
还有很多基于其他操作的钩子,都因工作流程不同而有所不同,具体可以查阅 Git 钩子官方文档 。
钩子脚本可以按照指责不同接收不同的参数并进行修改。比如 commit-msg
钩子,钩子接收一个参数,是存有当前提交信息的临时文件的路径,参数可以在shell脚本中以 $1
的形式进行调用,有了这个我们就可以修改文件中的提交信息了。
举个例子,当你想在每次commit之前用检查代码规范与否,就可以直接在 pre-commit
脚本最后添加 npm run lint
(这里看自己相关配置,不一定是这句)。
但是,git hooks的设计思路是在每台终端以及服务器端提供不同的定制方案。说人话,就是因为git是一种分布式的系统,它保证了所有终端的版本都是相同的,但hooks在服务器端和私人终端的配置可能不一样,所以hooks的配置不能跟随git提交。
例如 gerrit
提供的用于修改commit message的 commit-msg
钩子就需要在 git clone
的同时从远程服务器下载到本地来替换,代码如下:
git clone ssh://kinice@gerrit.company.com:29418/All-Projects && scp -p -P 29418 kinice@gerrit.company.com:hooks/commit-msg All-Projects/.git/hooks/
这当然是一种好方式。但有一种情况,当我们没有其他的可以存储脚本的第三方服务器,又希望将hooks同步给所有终端,该怎么办呢?
用更简单的方式使用git hooks
为了解决上面的问题,有很多大神写了第三方工具来实现hooks同步。对于前端来说,可以在npm安装的第三方工具有很多,例如 husky
、 yorky
、 git-hooks
等。 yorkie
是Vue作者尤雨溪fork了 husky
并做了一些修改的工具,改善了一些使用体验,所这里我们介绍一下 yorkie
。
*注: git-hooks
跟前两种工具的思路不同,感兴趣可以了解一下: git-hooks
。
安装 yorkie
$ npm install yorkie --save-dev
// package.json { "gitHooks": { "pre-commit": "npm test", "commit-msg": "npm test", "...": "..." } }
简单到看完配置就懂了吧,直接在 package.json
中增加 gitHooks
这一项,并直接把想执行的shell语句写在里面即可。
探究 yorkie
的实现原理
在安装过yorkie之后,比对一下安装之前的hook文件,会发现yorkie直接重写了所有的hooks。所以我们把 /.git/hooks/pre-commit
的核心代码贴出来看看yorkie做了什么:
has_hook_script () { [ -f package.json ] && cat package.json | grep -q "\"$1\"[[:space:]]*:" } cd "." # Check if pre-commit is defined, skip if not has_hook_script pre-commit || exit 0 # Add common path where Node can be found # Brew standard installation path /usr/local/bin # Node standard installation path /usr/local export PATH="$PATH:/usr/local/bin:/usr/local" # Export Git hook params export GIT_PARAMS="$*" # Run hook node "./node_modules/yorkie/src/runner.js" pre-commit || { echo echo "pre-commit hook failed (add --no-verify to bypass)" exit 1 }
忽略上面那些检查是否存在hook脚本的代码,最后执行了 node ./node_modules/yorkie/src/runner.js
:
const fs = require('fs') const path = require('path') const execa = require('execa') const cwd = process.cwd() const pkg = fs.readFileSync(path.join(cwd, 'package.json')) const hooks = JSON.parse(pkg).gitHooks // 将package.json重的hooks字段取出来 if (!hooks) { // 没有hook则退出 process.exit(0) } const hook = process.argv[2] // 这里的process.argv[2]就是在hooks脚本里传过来的hook名称,如pre-commit const command = hooks[hook] if (!command) { // 不是当前hook则退出 process.exit(0) } console.log(` > running ${hook} hook: ${command}`) try { execa.shellSync(command, { stdio: 'inherit' }) // 使用execa.shellSync运行命令 } catch (e) { process.exit(1) }
关于对 runner.js
的解析,我写到了注释中,应该都能看得懂。即通过( npm install
时改写hooks --> 将hooks改为运行自己的runner --> runner依赖 package.json
)的方式,实现了将hooks信息保存在package.json中并可以通过git共享给所有项目成员。
END
俗话说,懒惰是人类进步的动力,希望可以用这些东西,做到一键完成所有手工重复任务,提高我们的工作效率,把时间用在更有意义的事情上。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 前端工程工作流规范
- gulp打造前端自动化工作流
- 使用webpack4打造自己的前端工作流
- Gulp4 前端自动化工作流配置
- 前端工程化:围绕Jenkins打造工作流的过程
- LegoFlow 开源 v2.0 版本,前端工作流客户端
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Powerful
Patty McCord / Missionday / 2018-1-25
Named by The Washington Post as one of the 11 Leadership Books to Read in 2018 When it comes to recruiting, motivating, and creating great teams, Patty McCord says most companies have it all wrong. Mc......一起来看看 《Powerful》 这本书的介绍吧!