到目前为止,您已经对 npm 有了一定的了解!到目前为止,我们已经将“npm”中的三个字母分解,以更好地了解 Node 和包管理器。在 上一章 中,我们甚至安装了 Node 和 npm,同时熟悉了 Node 版本管理器或 nvm。在本 npm 入门指南的下一部分中,很可能是您来这里的原因:**安装 npm 包**。
指南章节
- 本指南适用于谁?
- “npm”到底是什么意思?
- 命令行到底是什么?
- Node 到底是什么?
- 包管理器到底是什么?
- 到底如何安装 npm?
- 到底如何安装 npm 包? (您现在就在这里!)
- 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
文件(称为“锁定文件”); - 安装实际的包文件——以及原始包可能依赖的任何其他包(在
node_modules
文件夹内);以及 - 对已安装的包进行审核。
让我们一一介绍它们。
package.json
和 package-lock.json
这两个 JSON 文件协同工作以确保项目中所有依赖项的准确记录(以及所有它们的依赖项、所有依赖项的依赖项等等)。区别有点技术性,但简单来说:锁定文件是项目依赖项树的深入、精确的快照,而 package.json
是一个高级概述,它还可以包含其他内容。您安装的主要包可能列在 package.json
中,但 package-lock.json
是跟踪整个依赖项树的地方。
锁定文件也不应该手动更新;只能由 npm 更新。因此,请务必避免将锁定文件与 package.json
文件混淆。
当您与他人共享或合作项目时,npm 会通过这两个文件知道项目来自哪里以及您在项目中安装了哪些内容。它可以精确地在任何其他人的机器上复制该环境,这要归功于其信息。这两个文件都应该提交到您的 Git 存储库,并用作项目的依赖项蓝图。这样,当您的团队中的另一位开发人员克隆存储库并运行 npm install
命令时,npm 就会知道确切要安装哪些包,让您和您的同事保持同步。
如果您打开 package.json
,您不会看到太多内容,但值得一看,只是为了看看发生了什么。
{
"dependencies": {
"sass": "^1.43.4"
}
}
您可能不会看到确切的版本号(因为该包已在撰写本文时进行了更新),但您应该在 JSON dependencies
对象中看到 sass
的列出。数字本身(在本例中为 1.43.4
)表示已安装的 Sass 的特定版本。
作为简短但重要的旁注:版本号开头的脱字符号 (^
) 让 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
),它已经至少两年没有运行了。让我们看看它表现如何
npm audit
会找出具有已知漏洞的包,它会在你每次安装包时自动运行。如果你看到这样的消息,不要太担心;许多漏洞,尤其是“中等”类别中的漏洞,在现实世界中带来的风险很低,而且可能只在非常具体的情况下才会出现。(例如,可能只有一个包中的方法,在以特定方式使用时,才会使其变得脆弱。)
尽管如此,最好还是解决我们能解决的问题,这就是 npm audit fix
命令的作用。在命令末尾添加 fix
会告诉 npm 前去更新任何具有已知漏洞的包的次要版本。 “次要版本”部分很重要;次要版本不应该包含重大变更,而只包含更新。这意味着应该通过这种方式运行更新是安全的,不会有任何破坏项目的风险。
如果将包版本号提升一个次要版本号不起作用,你可以在原始命令中添加 --force
标志
npm audit fix --force
但是,这是一种冒险的操作。 允许 npm “使用强制”意味着它现在可以安装主要版本更新来解决漏洞,这意味着它可能会进行重大更改或引入不兼容性。除非存在 npm audit fix
无法解决的严重漏洞,并且你愿意并且能够在之后花费大量时间进行故障排除(如果有必要),否则我不建议这样做。
关于此主题的最后一点说明:了解到有时可以通过删除 node_modules
并重新运行 npm install
来解决 npm 项目中的一些意外问题会有所帮助。 这就是 npm 解决问题的“关闭并重新打开”的方式,我自己也做过很多次。
接下来是什么
既然我们已经彻底探索了 npm 在幕后运行的迷宫,那么让我们回到实际做事,好吗?
我已经知道这一切是如何运作的,但我偶然发现了这个系列,并决定还是读一读。对于初学者来说,这是一个很棒的概述!几年前,我自己也希望有这样的资料。
两个小小的挑剔
根据 npm 品牌常见问题解答,“npm”并不代表“Node 包管理器”。
Sass 应该使用
npm install --dev sass
安装。 这是因为它是一个“开发依赖项”,并且实际上永远不会被发送到浏览器或其他任何地方。 在本指南中,这可能并不十分重要,但会产生影响,了解不同的依赖项类型(实际上有三种:主依赖项、开发依赖项和对等依赖项)是很有帮助的。大多数人不需要处理对等依赖项。
一般来说,主依赖项用于实际项目代码使用的代码,例如 jQuery、lodash 等;开发依赖项用于格式化、代码风格检查和打包等。作为一个经验法则,普通依赖项被你的代码使用,而开发依赖项用于你对你的代码所做的事情或用你的代码所做的事情。
普通依赖项使用
npm install <package name>
安装,开发依赖项使用npm install --dev <package name>
安装 (--dev
可以缩写为-D
)。这也适用于所有与 npm 兼容的包管理器,例如 Yarn。
啊,我看到你在下一篇文章中解释了不同类型的依赖项。
我提前没有阅读,是我的错。:)
我认为语义化版本是
major.minor.patch
,所以我本来以为fix
只会将补丁号提升,如果可以的话(否则是次要号)。我错了吗?我认为你说得对;那是一种措辞错误。当我提到“次要版本”时,我的意思是“非主要版本”,但我没有意识到这在技术上并不是正确的表达方式。
我一直以为语义化版本是
major.minor.patch
,所以我本来以为fix
只会将补丁号提升,如果可以的话(否则是次要号)。我错了吗?