8

众所周知,npm是工程师们基于nodejs的开发中的核心内容。而大部分人在使用npm时,主要使用她的包管理系统。

但是,当我们稍微look look那些知名的开源项目,或者老牛们的代码时,常常都能在它们的package.json里看到一个写满了命令的scripts属性。这里面都隐藏了哪些秘密,牛牛们都用它做了什么,怎么做到的?这些疑问必定撕扯着你的好奇心,来,我们今天就聊聊神秘的scripts属性。

Hooks(钩子)

通常情况下,应用程序只能处理来自内部的消息,如果希望对外部发来的消息也能拦截处理,那就需要一种叫钩子(Hook)的技术。想象一下,npm test这个过程你是控制不了的,但如果就非常想在test之前自动处理点什么事儿,怎么办?没次都手动在test之前执行什么,烦不烦、烦不烦、烦不烦?就是不烦,也会忘啊!

这时候就用到我们的Hook了。下面这些指令都是Hook,它们都可以在package.jsonscripts属性里定义,并且会在生命周期的某个指定时刻被执行,这就是上面提到的“对外部发来的消息也能拦截处理”,这极大的方便了开发人员(或许你想做点坏事儿?)

  • prepublish: 在publish该包之前执行。(在包目录下执行npm install时也会执行)

  • postpublish: 在该包publish之后执行

  • preinstall: 在该包被install之前执行

  • postinstall: 在该包被install之后执行

  • preuninstall: 在该包被uninstall之前执行

  • postuninstall: 在该包被uninstall之后执行

  • preversion: 在修改该包的version之前执行

  • postversion: 在修改该包的version之后执行

  • pretest, posttest: 在该包内执行test时执行,其中pretest先于posttest

  • prestop, poststop: 在该包内执行stop时执行,其中prestop先于poststop

  • prestart,poststart: 在该包内执行start时执行,其中prestart先于poststart

  • prerestart, postrestart: 在该包内执行restart脚本时执行,其中prerestart先于postrestart。注意: 如果没有在scripts里显示指定restart脚本,则会自动调用stop,然后再start

上面这些Hooks都是npm预定义好的,也就是说,当你执行npm install时,如果你在scripts里定义了preinstallpostinstall,那它们分别会在npm install之前/后自动执行,不劳你操心!碉堡了,有木有?

还有,任何自定义脚本(通过npm run-script <脚本名>来执行)也可以前缀prepost为其制作钩子。比如:premyscriptmyscriptpostmyscript

注:也可以使用run作为run-script的简写使用。

说说常见的使用场景1

如果你写了一个类库,有些操作和操作系统无关,但却希望在该包被使用前执行,可以试试prepublish,意思是,在你执行npm publish的时候,自动先执行scripts里定义的prepublish里的脚本。

举个栗子:假设我用CoffeeScript写了一个类库,我有下面两个愿望:

  1. 我希望发布的是JavaScript版本,这样用户npm install <类库>之后无需搭建神马乱七八糟的环境,即可直接使用

  2. 我希望发布的是一个minified版本,即用户npm install <类库>之后,也可直接引入使用,而不必关心还要帮我压缩一次

OK,我们现在来聊聊这里我用prepublish的好处:

  1. 这事儿执行一次就够,就是我publish包的时候,不需要神马用户每次install的时候也做

  2. coffee-script可以作为devDependencies在我的项目里,这样的话,用户在install这个类库的时候,就不会下载coffee-script了。

  3. uglify-js也可以作为devDependencies在我的项目里,好处同上

说说常见的使用场景2

再比如,写了一个类库,其中有些操作是和操作系统相关的,可以使用postinstall看看。

那我之前写的一个movoto-cli举例,我有一个期望:
用户在install我的类库后,这个类库要将两个配置文件eslintrc_browser_legacy.jsoneslintrc_node.json里的LINEBREAK_OS字段根据用户的操作系统修改为正确的值。

于是我把这个操作写在了postinstall这个Hook里,问题解决,完美,没问题!

Environment

经常听到有朋友问到这样的问题,说看到有人的scripts里写了"test": "mocha --reporter nyan",觉得这个代码有漏洞,使用这个指令的人,必须得先npm install -g mocha(全局安装mocha),否则test命令找不到mocha,会报错的吧!

答案是这样的,一般这么写scripts的,通常会把mocha装在devDependencies或者dependencies里。scripts里的指令有这样一个特点,如果你的类库(或叫模块)依赖的其它模块提供了可执行脚本(譬如:mocha),那这些依赖会在你执行scripts指令时自动被注入到执行进程的PATH里。

这就是说,如果devDependencies或者dependencies里有mocha,那在npm test的时候,里面的mocha命令,是从注入的PATH里(即:node_modules/.bin/mocha)找了。

So,还需要全局安装mocha么?恐怕不需要了^^


leftstick
27.3k 声望1.5k 粉丝

沙滩一卧两年半,今日浪打我翻身