npm (node package manager)是 JavaScript 世界的包管理工具,并且是 node.js 平台的默认包管理工具。 通过 npm 可以 安装、共享、分发代码,管理项目依赖关系。
(npm(“Node 包管理器”)是 JavaScript 运行时 Node.js 的默认程序包管理器。)。也是世界上最大的软件注册表,每星期大约有 30 亿次的下载量,里面包含超过600000个包(代码模块)的结构,来自各大洲的开源软件开发者使用npm互相分享和借鉴,能够使您轻松跟踪依赖项和版本。
(由三个独立的部分“网站、注册表、命令行工具”组成)
网站 :是开发者查找包、设置参数以及管理 npm 使用体验的主要途径
注册表(registry):是一个巨大的数据库,保存了每个包(package)的信息。
命令行工具 (CLI):通过命令行或终端运行。开发者通过 CLI 与 npm 打交道
为了更直观地解释,我们可以将数据库 npmjs.com 视为一个物流集散中心,该中心从卖方(npm 包裹的作者)那里接收货物的包裹,并将这些货物分发给买方(npm 包裹的用户)。
为了促进此过程,npmjs.com 物流集散中心雇用了一群勤劳的袋熊(npm CLI),他们将被分配给每个 npmjs.com 用户作为私人助理。 因此,“dependencies(依赖项)(npm包裹)”会如下传递给 JavaScript 开发人员:
发布 JS 软件包的过程如下:
将软件包调整到应用程序中,或按原样合并它们
下载可立即使用的独立工具
无需使用npx下载即可运行包
与任何npm用户共享代码
将代码限制为特定开发人员
组建虚拟团队
管理多个版本的代码和代码依赖项
更新基础代码时,轻松更新应用程序
发现解决同一难题的多种方法
每个 JavaScript 项目(无论是 Node.js 还是浏览器应用程序)都可以被当作 npm 软件包,并且通过 package.json 来描述项目和软件包信息。
我们可以将 package.json 视为快递盒子上的运输信息。
当运行 npm init 初始化 JavaScript/Node.js 项目时,将生成 package.json 文件,文件内的内容(基本元数据)由开发人员提供:
✸name: JavaScript 项目或库的名称。
✸version: 项目的版本。通常,在应用程序开发中,由于没有必要对开源库进行版本控制,因此经常忽略这一块。但是,仍可以用它来定义版本。
✸description: 项目的描述。
✸license: 项目的许可证。
该文件描述了 npm JavaScript 项目中使用的“依赖项(npm包裹)”的确切版本。(如果 package.json 是通用的描述性标签,则 package-lock.json 是成分表。)
就像我们通常不会读取食品包装袋上的成分表(除非你太无聊或需要知道)一样,package-lock.json 并不会被开发人员一行一行进行读取。
package-lock.json 通常是由 npm install 命令生成 的,也可以**由我们的 NPM CLI 工具读取**,以确保使用 npm ci 复制项目的构建环境。
npm 已帮助发布了 130 万个软件包,每周下载量超过 160 亿次! 这些数字对于任何软件工具来说都非常厉害。由此可以推断出,大多数 npm 用户都朝这个方向使用 npm。所以,了解如何使用这个强大的工具会很有帮助。
NPM中可以只运行一个命令来 安装多个模块、获取包的信息、安装特定版本的软件包、列出依赖项 等等有用的提示和技巧
这是现在我们开发 JavaScript/Node.js 应用程序时最常用的命令。
默认情况下,npm install 将安装带有 ^ 版本号的软件包的最新版本。npm 项目上下文中的 npm install 将根据package.json规范将软件包下载到项目的 node_modules 文件夹中,从而升级软件包的版本(并重新生成package-lock.json )。 npm install 可以基于 ^ 和 〜 版本匹配。
如果要在全局上下文中安装程序包,可以在机器的任何地方使用它,则可以指定全局标志 -g (例如 live-server)。
使安装 JavaScript 软件包非常容易,以至于经常错误地使用此命令。
包太大、太深这样的问题可以通过 --production 标志来拯救!在上一节中,(分别用于生产和开发/测试环境的 dependencies 和 devDependencies ) 。 这个 --production 标志是如何在 node_modules 中进行区别的。
通过将此标志附加到 npm install 命令,我们将仅从 dependencies 安装软件包,从而将 node_modules 的大小大大减小到应用程序正常运行所必需的大小。——不应该将 devDependencies 引入生产环境!
如果 npm install --production 对于生产环境是最佳选项,那么是否必须有一个对本地环境,测试环境最合适的选项?
答案是 npm ci 。
就像如果 package_lock.json 尚不存在于项目中一样,无论何时调用 npm install 都会生成它, npm ci 会消耗该文件( package_lock.json ),来下载项目所依赖的每个软件包的确切版本。
这样,无论是用于本地开发的笔记本电脑还是 Github Actions 等 CI(持续集成)构建环境,我们都可以确保项目上下文在不同机器上保持完全相同。
随着越来越多的软件包发布,并且易于安装,因此 npm 软件包容易受到恶意作者的恶意攻击,例如这些。
意识到生态系统存在问题,npm.js 组织提出了 npm audit 的主意。 他们维护了一个安全漏洞列表,开发人员可以使用 npm audit 命令来审核项目中的依赖项。
npm audit 为开发人员提供了有关漏洞以及是否有要修复的版本的信息,例如:
如果补救措施在下一个不间断的版本升级中可用,则可以使用 npm audit fix 来自动升级受影响的依赖项的版本。
将软件包发送到 npmjs.com (地址可改) 非常容易,因为我们只需要运行 npm publish 。
棘手的部分(并非专门针对 npm 软件包作者)是确定软件包的版本。
根据 semver.org 的经验法则:
1.当你进行不兼容的 API 更改时使用 MAJOR 版本
2.以向后兼容的方式添加功能时使用 MINOR 版本
3.进行向后兼容的 bug 修复时使用 PATCH 版本
发布软件包时,遵循上述规则尤为重要,可以确保你不会破坏任何人的代码,因为 npm 中匹配的默认版本是^(又称下一个次版本)。
我们通常执行 npm init,然后开始添加 npm 请求的信息。
但是,如果我们不关心所有这些信息,并且希望保留默认值,那么对于 npm 请求的每一条数据,我们都按 enter 键。为了避免这种情况,你可以输入 npm init -y。这样就可以跳过问题询问了。
注:你也可以使用 npm init --yes 作用是一样的。
你可以使用更加简单的npm i 来代替 npm install;
你不需要为每个模块键入一个 npm install 命令,例如:
bash 代码: npm i gulp-pugnpm i gulp-debugnpm i gulp-sass
你可以只运行一个命令,一次性安装所有这些模块:
bash 代码: npm i gulp-pug gulp-debug gulp-sass
还有更加简单的方法,如果所有名称都以相同前缀开头,你不需要键入整个名称:
bash 代码: npm i gulp{-debug,-sass,-pug}
如果要安装软件包并将其另存为生产依赖项,则通常会这样做
bash 代码: npm i gulp --save-prod
你可以使用 -P 快捷方式,像这样:
bash 代码: npm i gulp -P
对于开发依赖项也是一样,不需要键入完整的 --save-dev 标志,你可以使用 -D 快捷方式,像这样:
bash 代码: npm i gulp -D
默认情况下,当你运行不带任何 flags(参数) 的 npm install 时,npm 会将包作为依赖项添加到 package.json 文件中。 如果要防止这种情况,请使用 --no-save flags(参数) 安装,如下所示:
bash 代码: npm i gulp --no-save
下面的命令将显示 vue 包 的相关信息:
npm view vue 或 npm v vue
如果你只想获得最新版本的软件包,可以试试下面这个命令:
bash 代码: > npm v vue version> 2.5.17
如果你想获得 npm 包完整的版本列表,请尝试复数形式
bash 代码: > npm v vue versions>
[ ‘0.0.0’, ‘0.6.0’, ‘0.7.0’, … ‘2.5.15’, ‘2.5.16’, ‘2.5.17-beta.0’, ‘2.5.17’ ]
如果要安装版本,而不是最新版本的软件包,可以键入:
bash 代码: npm i [email protected]
鉴于记忆名称比数字更容易(至少对我来说),你可以使用 dist-tag 列表中名称,运行 npm v 命令即可得到该列表 ,如下所示:
bash 代码: npm i vue@beta
有时你可能记不住你前一段时间或你朋友推荐的某个 package(包) 的确切名称。 在这种情况下,你可以使用 npm 搜索,直接在终端中执行搜索:
bash 代码: npm search gulp debug
或者
bash 代码: npm s gulp debug
如果你不想打开 package.json 文件并从那里手动删除依赖项,则可以使用以下命令将其删除:删除vue包
bash 代码: npm uninstall vue
这将从 node_modules 文件夹和 package.json 文件中删除该包。 当然,你可以使用 rm , un 或 r 来实现相同的效果,例如:
bash 代码: npm rm vue
如果由于某种原因你只想从 node_modules 文件夹中删除包文件,但仍然将其作为依赖项保存在 package.json 文件中,则可以使用 --no-save 参数:
bash 代码: npm rm vue --no-save
先抛几个常见疑惑:
1.什么是全局安装、什么是本地安装(或叫局部安装,下文统一叫本地安装) ?
2.为什么要全局安装?为什么要本地安装?全局安装和本地安装有什么区别?
3.什么叫开发依赖、生产依赖?什么又是开发环境、生产环境?
npm install -g //(这里-g是-global的简写)
通过上面的命令行(带-g修饰符)安装某个包,就叫全局安装。通常全局包安装在node目录下的node_modules文件夹。可以通过执行下面几条命令查看node、npm的安装目录和全局包的安装目录。
1.which node // 查看node的安装目录
2.which npm // 查看npm的安装目录
3.npm root -g // 查看全局包的安装目录
4.npm list -g --depth 0 //查看全局安装过的包
npm install (后面可以加几种修饰符,主要有两种–save-dev和–save)
通过上面的命令行安装某个包,就叫本地安装。包安装在你当前项目文件夹下的node_modules文件夹中。
全局安装的包可提供直接执行的命令(例:gulp -h可以查看gulp定义了什么命令)。 比如gulp全局安装后,可以在命令行上直接执行gulp -v、gulp -h等 (原理:全局安装的gulp会将其package.json中的bin命令注入到了全局环境,使得你可以全局执行:gulp xxx命令,这另一个话题了,不深入) 。倘若只在本地安装了gulp,未在全局安装gulp,直接执行这些命令会报错。你想要执行相应的命令则可能需要例如:node ./node_modules/gulp/bin/gulp.js -v(查看版本) 这样用一大串命令来执行。因此全局安装就发挥到他的好处了呀,一个gulp -v就搞定
当然,不是每个包都必须要全局安装的,一般在项目中需要用到该包定义的命令才需要全局安装。比如gulp 执行gulp任务…等,所以是否需要全局安装取决于我们如何使用这个包。全局安装的就像全局变量有点粗糙,但在某些情况下也是必要的,全局包很重要,但如果不需要,最好避免使用。
如果只是全局安装了而没本地安装,就得require(’’) 例:引入一个全局的包可能就是requirt(’/usr/local/…’)通过全局包的路径引入,这样显然十分的不灵活。如果安装了本地包,那么 就可以直接require(’’)引入使用。
一个包通常会在不同的项目上会重复用到,如果只全局安装,那么当某个项目需要该包更新版本时,更新后可能就会影响到其他同样引用该包的项目,
因此本地安装可以更灵活地在不同的项目使用不同版本的包,并避免全局包污染的问题。
一个经验法则:要用到该包的命令执行任务的就需要全局安装,要通过require引入使用的就需要本地安装( 但实际开发过程中,我们也不怎么需要考虑某个包是全局安装还是本地安装,因为这一点在该包的官网上一般会明确指出,以上是为了理解全局安装和本地安装)
顺着上面讲到的本地安装,本地安装有两种主要的安装方式:
保存到开发依赖(devDependencies):
npm install < pageName> --save-dev
等同 npm install < pageName>
保存到生产依赖(dependencies):
npm install < pageName> --save
"开发依赖"顾名思义在开发环境中用到的依赖,"生产依赖"在生产环境中用到的依赖。那么这里又延伸出个问题什么是开发环境、什么是生产环境?
【开发环境】:指的是你的项目尚且在编码阶段时的环境。你在代码可能还有各种console.log()、注释、格式化等。
【生产环境】:指的是你的项目已经完成编码,并发布上线可供用户浏览的阶段时的环境。代码可能经过了压缩、优化等处理。
这些概念其实并没有一个很明确的定义,接下来我们举例个场景,将"开发环境"、“生产环境"和上面的"开发依赖”、"生产依赖"联系起来就会比较容易理解的了。假如我们在开发过程中使用jQuery。在以往,可能就是把jQuery这个插件下载的本地,再通< script>引入html中。但这有个不方便的地方,我们每次进行一个项目的时候就得手动复制这个jQuery文件到我们的项目中,如果想要换个版本又得官网上下载、随着项目越来越多。用到的插件、库也随之越繁杂…这样会造成自家用的插件管理繁琐的问题。因此就出现了npm(包管理工具) 你需要用到什么,直接通过一条命令行就可以将想要的插件下载下来,并直接引入到项目中,目前几乎所有的js插件都能在npm上直接下载。
回到环境和依赖话题,我们下载的jQuery,在开发时参与源码编写,在发布上线的生产环境中也是需要它的。不仅在开发环境编写代码时要依赖它、线上环境也要依赖它,因此将它归类为"生产依赖",安装时执行npm install jquery --save,它就会被记录在package.json的dependencies。当进行代码打包时,会将这里的jQuery打包入我们的项目代码中。
接着,假如我们用gulp对html进行压缩,我们通常会用到一个插件gulp-htmlmin。我们只希望它把html压缩完就ok了,并不希望它融入我们的项目代码中,即只存在于开发环境,因此把他归类为"开发依赖"。安装时执行npm install gulp-htmlmin --save-dev它就会被记录在package.json的devependencies下,当进行代码打包时,不会将这里的gulp-htmlmin插件源码打包入我们的项目代码中
devDependencies只会在开发环境下使用,生产环境不会被打入包内;而dependencies不仅在开发环境中要使用,生产环境也需要使用到。根据以上规则,我们就很容易区分哪些插件是用–save-dev模式安装,哪些用–save模式安装。