内容简介:在前端的日常工作中,经常会出现“当执行一种操作之前(之后)需要同时执行另一种操作”的情况,比如我们希望在每次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 版本,前端工作流客户端
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Modern PHP(中文版)
Josh Lockhart / 安道 / 中国电力出版社 / 2015-9 / 39
PHP正在重生,不过所有PHP在线教程都过时了,很难体现这一点。通过这本实用的指南,你会发现,借助面向对象、命名空间和不断增多的可重用的组件库,PHP已经成为一门功能完善的成熟语言。 本书作者Josh Lockhart是“PHP之道”的发起人,这是个受欢迎的新方案,鼓励开发者使用PHP最佳实践。Josh通过实践揭示了PHP语言的这些新特性。你会学到关于应用架构、规划、数据库、安全、测试、调试......一起来看看 《Modern PHP(中文版)》 这本书的介绍吧!