到现在为止,你对npm已经有了相当的了解了到目前为止,我们已经分解了 "npm "中的三个字母,以获得对Node和包管理器的更好理解。在上一章中,我们甚至安装了Node和npm,同时熟悉了Node版本管理器,即nvm。在这个npm的初学者指南中,接下来很可能是你首先在这里的原因:安装npm包。
指南的各个章节
- 这本指南到底是为谁准备的?
- npm "到底是什么意思?
- 命令行是什么东西?
- Node是什么?
- 软件包管理器是什么?
- 如何安装npm?
- 你是如何安装npm包的? (You are here!)
- npm命令到底是什么?
- 你如何安装一个现有的npm项目?
一个简单的例子
我们可以用npm install 命令(简称npm i )来安装我们的第一个包,然后再加上我们想添加到项目中的包的名字。例如,Sass的Node包被简单地称为 "sass",这意味着我们可以像这样添加到一个项目中(只要确保你在一个你为这个小项目创建的新文件夹中)。
npm install sass
这就是你所需要的!输入这些,npm就直接开始工作了。

幕后发生的事情是,npm试图在npm包注册表中找到一个名为sass 的包。如果它找到了这个包(它确实找到了),npm就把它安装到项目的根目录下自动生成的node_modules 文件夹中(这个问题稍后再讲),包括该包运行所需的一切。(这就是为什么你看到npm添加了16个包,并且总共审核了17个npm包,而不是仅仅是Sass包--它也有依赖关系!)
一旦我们运行了install 命令,你可能会注意到,在项目文件夹中没有看到任何你所期望的名为 "sass "的东西。然而,奇怪的是,我们确实在项目文件夹中看到了三个新项目:两个名为package.json 和package-lock.json 的JSON文件,以及一个全新的node_modules 文件夹。

这些是什么!?我们要求npm安装Sass,而不是所有这些东西。这不是Sass的一部分...对吗?嗯,这是正确的,但有一个非常好的解释,为什么这些新项目会在项目文件夹中产生。让我们来看看刚刚发生了什么。
当你安装一个包时会发生什么
当你安装(或卸载,或更新)一个软件包时,npm会做以下四件事中的大部分(如果不是全部)。
- 如果需要的话,更新你项目中的
package.json文件。 - 更新包含所有技术细节的
package-lock.json文件(称为 "lockfile")。 - 安装实际的软件包文件--以及原始软件包可能依赖的任何其他软件包(在
node_modules文件夹内);和 - 对已安装的软件包进行审计。
让我们逐一来看看这些。
package.json 和package-lock.json
这两个JSON文件一起工作,以确保准确记录你的项目中的所有依赖关系(以及他们所有的依赖关系,以及他们所有的依赖关系的依赖关系,等等)。这个区别有点技术性,但可以松散地解释:lockfile是项目的依赖树的深入、精确的快照,而package.json 是一个高层次的概述,也可以包含其他东西。你安装的主要软件包可能列在package.json ,但package-lock.json 是跟踪整个依赖树的地方。
Lockfile也不应该被手工更新,只能由npm来更新。所以一定要避免把lockfile和package.json 文件搞错。
当你在一个项目上与他人分享或合作时,npm知道这个项目来自哪里,以及你通过这两个文件在项目中确切地安装了什么。它可以在其他人的机器上精确地复制那个环境,这要感谢他们的信息。这两个文件都要提交到你的Git repo中,并作为你项目的依赖蓝图。这样一来,当你团队中的另一个开发者克隆这个 repo 并运行npm install 命令时,npm准确地知道要安装哪些软件包,使你和你的同事保持同步。
如果你打开package.json ,你不会看到太多的东西,但它值得一窥,只是为了看看正在发生什么。
{
"dependencies": {
"sass": "^1.43.4"
}
}
你可能不会看到确切的版本号(因为该软件包在写完后已经被更新了),但你应该看到sass 列在一个JSONdependencies 对象中。数字本身(本例中为1.43.4 )表示所安装的Sass的具体版本。
作为一个简短但重要的切入点:版本号开头的carat字符(^ )让npm知道它被允许安装软件包的小更新。换句话说,它告诉npm,所安装的Sass包必须至少是1.43.4 ,但可以是任何更高的1.x.x ,只要它仍然在2.0.0 。npm通常在安装包时选择最新的稳定版本,但添加这个以允许非破坏性更新。这一点被称为"语义版本",它本身就是一篇博文,但不是npm独有的。
总之,这涵盖了两个JSON文件。接下来我们来谈谈node_modules 文件夹。
node_modules
node_modules 是所有实际的软件包代码所在的地方;它是你安装的Node包和所有使它们运行的东西实际安装的地方。如果你现在打开这个文件夹,你会发现一个 文件夹,但同时还有其他几个文件夹。sass
额外文件夹的原因是,当你安装一个包时,它可能需要其他包才能正常运行(如Sass显然是这样)。因此,npm会自动完成寻找和安装所有这些依赖项的艰苦工作。正如你可能已经猜到的,这些依赖也可能有自己的其他依赖,所以这个过程不断重复,如此反复,直到我们完成了对依赖树最远分支的爬行,并且我们所需要的一切都被安装了(或者直到我们遇到了某种错误,尽管希望不是)。
由于这个原因,一个项目有数百个或更多的node_modules 子文件夹是很常见的,这些子文件夹的磁盘空间很快就会增加。node_modules ,往往会变得相当大。
如果你想知道如何将像node_modules 这样的超级大文件夹提交到项目的仓库中,这里有一个重要的说明:与 JSON 文件不同, node_modules 文件夹并不是要提交到 Git 中,甚至不是要共享。事实上,几乎每一个.gitignore 文件的例子(该文件告诉Git在追踪文件时应该跳过哪些文件)都包括node_modules ,以确保Git永远不会触及或追踪它。
那么,你团队中的其他人是如何获得这些软件包的呢?他们从命令行中运行npm install (或简称npm i ),直接从源代码中下载依赖。这样,就不需要提交(或拉动)大量的数据到源码库,也不需要从源码库中拉动。
安装依赖项时要谨慎
这个庞大的依赖关系网和它们的曾曾依赖关系可能导致这样的情况:一个提供有用服务的小型实用程序库可能被许多其他软件包采用,而这些软件包又被许多其他软件包采用,直到最后原始代码悄悄地安装在相当大比例的网站和应用程序上。
这听起来很疯狂(如果不是完全可怕的话),在安装你的一个软件包的过程中,你可能实际上让一大堆其他的东西通过门。这可能感觉就像邀请一个新朋友参加你的家庭聚会,然后他带着20个不请自来的陌生人出现。但这并不像它看起来那么奇怪或可怕,有几个原因。
- 大多数npm包都是开源的。你和其他任何人都可以很容易地偷看引擎盖下的包,并看到该包到底在做什么。你还可以在注册表(npmjs.com)上查找该包,看看它被安装了多少次,最后一次更新是什么时候,以及其他相关信息。如果一个软件包相当流行,你可以合理地确定它是安全的。
- 有一个广阔的世界,许多项目将需要这些功能。考虑一下日期格式化、处理HTTP请求和响应、节流、解压或动画,只是作为快速的例子。每次在一个新项目中使用这些东西时,不断地重新发明轮子和手工编码是没有意义的。
- 安装一个软件包与在你的手机上安装一个应用程序,或在WordPress网站上安装一个插件并没有什么不同。不同的是,我们不能像安装软件包那样看到这些应用和插件的内部运作,也不能看到这些应用和插件可能依赖的其他东西。有可能他们也会以某种方式拉入许多小的软件包。
当然,在任何可以安装和执行任意代码的环境中,一定程度的谨慎是个好主意。不要误会我的意思。如果我说坏人从未成功地利用过这个系统,那是在撒谎。但要知道,有许多程序可以保证事情不出错。如果有疑问,坚持使用最流行的软件包,你就会没事。
还知道npm为你运行自动安全审计,这使我们来到本节的最后一点。
什么是npm audit ?
当我们之前安装sass ,一旦完成,我们在终端看到以下信息。
found 0 vulnerabilities
然而,你可能会看到一些警告,而不是像下图中我的这个旧项目一样。我决定启动它,并在它至少坐了几年后运行npm install (npm i)。让我们看看它的表现。

YIKES!
**有已知漏洞的软件包被npm audit,**它在你安装一个软件包时自动运行。如果你看到这样的信息,不要太惊慌;许多漏洞,尤其是 "中度 "类别的漏洞,在现实世界中的风险非常低,可能只在非常特殊的情况下才有意义。(例如,可能只是一个软件包中的一个方法,当以特定的方式使用时,会使其受到攻击)。
尽管如此,最好还是解决我们能解决的问题,这就是npm audit fix 命令的作用。在结尾处添加fix ,告诉npm继续前进,并更新到任何具有某种已知漏洞的软件包的新次版本。次要版本 "的部分很重要;次要版本不应该包含破坏性的变化,只是更新。这意味着以这种方式运行更新应该是安全的,没有任何破坏项目的风险。
如果将软件包提高到一个次要版本号还不能解决问题,你可以在原始命令中添加--force 标志。
npm audit fix --force
**然而,这是一个有风险的操作。**给予npm "使用武力 "的权限意味着它现在可以安装主要的版本更新来解决漏洞--这意味着它可能会做出破坏性的改变或引入不兼容的情况。我不建议这样做,除非有关键的漏洞是npm audit fix 无法解决的,而且你愿意并能够在事后花大量时间进行故障排除,如果有必要的话。
关于这个话题的最后一个说明:你可以知道,有时你可以通过删除node_modules ,然后重新运行npm install ,来修复npm项目的一些意外问题。这是npm "把东西关掉再打开 "的方法,我自己也做过很多很多次。
下一步是什么
现在我们已经彻底探索了npm在引擎盖下如何工作的兔子洞,让我们回到实际工作中去,好吗?