关于npm包管理工具的完全详解(超详细)

1,593 阅读11分钟

代码共享方案

我们可以通过模块化的方式来封装自己的代码,或者封装一个工具,这个工具可以让同事通过导入的方式来使用,甚至可以分享给全世界的程序员来使用。常见的代码分享方案有两种。

上传到github上,其他人通过git下载我们的代码手动引用

当然这么做缺点有很多。

  • 大家必须知道你项目的github地址,并从github上手动下载。
  • 需要在自己的项目中手动的引用,并且管理相关的依赖。
  • 不需要使用的时候,需要手动删除相关的依赖
  • 当遇到版本升级或者切换的时候,需要重复上面的操作。

使用一个专业的工具来管理我们的代码

  • 我们通过工具将代码发布到特定的位置
  • 其他程序员直接通过工具来安装、升级、删除我们的工具代码

很显然,第二种方式我们可以更好的管理自己的工具包,其他人也可以更好的使用我们的工具包。

包管理工具npm

npm全程是Node Package Manager,也就是Node包管理器。但是它目前已经不仅仅是Node包管理器了,在前端项目中我们也使用它来管理依赖的包,包括:vue,vue-router,koa,axios,webpack等等。

下载npm工具

  • 我们首先要先安装node。nodejs.org/en/ image.png 推荐安装这个LTS版本(稳定版),当然你也可以在nvm或者n工具上安装nodejs。由于我的电脑是mac系统,所以我就演示下如何安装n

安装n工具并使用

安装n

sudo npm install -g n

n工具常用命令

n <version>  // 下载某一版本号node    e.g:n 10.16.0
n latest     // 安装最新版本
n stable     // 安装最新稳定版
n lts        //安装最新长期维护版(lts)
n rm <version>  // 删除某个版本   e.g:n  rm 10.16.0
n   // 输入命令后直接使用上下箭头选择版本

nvm相较于n可能会复杂一些,后续我也会在文章中更新。

npmjs.org

我们还需要记得一个网站 www.npmjs.org/ 我们安装的所有依赖(包)的信息都可以在上面查到。 我们在后文会讲到如何发布一个包,其实我们发布自己的包其实就是发布到registry上面的,当我们安装一个包时其实是从registry上面下载包

npm的配置文件

那么对于一个项目来说,我们如何使用npm来管理这么多包呢?

  • 事实上,我们每一个项目都会有一个对应的配置文件,无论是前端项目(Vue、React)还是后端项目 (Node)
  • 这个配置文件会记录着你项目的名称、版本号、项目描述等,也会记录着你项目所依赖的其他库的信息依赖库的版本号

这个文件就是package.json

得到package.json

那么如何获得这个package.json呢?

当我们从零开始创建项目的时候,我们需要npm init -y

这里我必须补充一句,以防大家踩坑,npm init -y的文件必须要是英文的,如果是中文直接npm init -y 会报错,这个时候我们需要输入npm init 并在包名处设置为英文。

此外如果是通过脚手架创建项目,脚手架会帮助我们生成package.json,并且配置有相关信息。

常见的配置文件如图

image.png

package.json常见的属性

package.json里有很多属性。里面有两项必填的属性分别是nameversion。其他属性我会一一剖析。

  • name :必填,为项目的名称。
  • version: 当前项目的版本号。
  • description:描述信息,很多时候是作为项目的基本描述
  • author:作者的相关信息(发布时会用到)
  • license:开源协议(发布的时候用到)
  • private属性:private属性记录当前项目是否私有。当值为true时,npm无法发布,这是为了防止私有项目或者模块发布出去的方式。
  • main属性:main属性为文件的入口。这个非常重要,我们引入某个库require('xxxx')就是自动从main找找对应的入口文件。
  • script属性:script属性支持用户配置一些自定义的脚本命令(定制化操作)。上图:

image.png 比如这个地方,我就可以直接npm run start程序就是会帮我们执行nodemon ./src/main.js这个操作。此外,对于常见的一些命令,如start、test、stop、restart,可以通过省略到run方式直接通过npm xx来运行。

  • dependencies属性:dependencies属性是指无论开发环境还是生产环境都需要依赖的包,比如vuevue-routeraxios等,我们运行npm install xxx就是将依赖安装在这个地方。与之对应的是devDependencies。
  • devDependencies属性:概括一点说就是,发布的时候用不到这个东西,没它的代码,比如webpacknodemonbabel等。我们通过npm install xx --save-dev或者npm install xx -D将它安装到devDependencies属性中。
  • peerDenpendencies:项目依赖关系是对等依赖,也就是你依赖的一个包,它必须是另外一个宿主包围前提的,比如element plus需要基于Vue3,我们必须要先安装Vue3。
  • engines属性:这个基本已经无了,早期vuecli2的时候还有它。engines属性用于指定node和npm版本号。在安装的过程中,会先检查对应的引擎版本,如果不符合就会报错。
  • browserlist属性:用于配置打包后的javascript浏览器兼容情况。

依赖的版本管理

我们会经常看到,在依赖的版本前面,会有~和^这连个符号,通常都是^。 image.png 这些是什么意思呢?实际上npm的包通常都要遵从semever版本规范。semver.org/lang/zh-CN/

semver版本规范

semver版本的规范是X.Y.Z

  • X主版本号(major):当你做了不兼容的API修改(可能不兼容之前的版本)
  • Y次版本号(minor):当你做了向下兼容的功能性新增(新功能增加,但是兼容之前的版本)
  • Z修订号(patch):当你做了 向下兼容的问题修真(没有新功能,修复了之前版本的bug)

关于^和~ 连个符号

  • ^x.y.z:表示x是保持不变的,y和z永远安装最新的版本。 这种我们一般称之为大概的版本
  • ~x.y.z:表示x和y不变,z永远安装最新的版本。

举个例子:比如vue2.6.12 、 vue3.2.12

major主版本号 只有重大版本才会更新,比如vue从2到3经历了很长时间,这个是有可能不兼容之前的版本。minor 次版本号,做了比如向下兼容的功能性新增,或者新加了一些功能。path 补丁号 主要是修复了之前版本的有些bug。

npm install 命令

我们以安装webpack为例。

npm安装可以分为两种情况:

  • 全局安装 npm installl webpack -g 这个会把webpack添加到环境变量里,你在任何位置都能用
  • 项目(局部)安装 npm install webpack 我们会把包安装在对应的目录下,其他位置是用不了的

npm i 是 npm install的简写(语法糖)

npm install 原理

比如我是webpack的开发者,那么我通过npm publish(发布命令,后面我会讲到),其实是发布到regisry里面去了。而作为用户,npm i webpack -D 其实就是从registry里下载到电脑里。

大家思考一个问题,如果多个项目都需要npm i webpack ,是不是每次都要从registry来下?早期的npm就是这样的,不管你电脑有没有,直接下,这样安装速度就很慢,很占用服务器带宽,而且npm那会也没缓存,版本管理之类的。所以谷歌推出了yarn,npm感受到了压力,从5以后,体验跟yarn差不多了。

其实从registry下载下来的是个压缩包,里面记录着一堆的配置信息。当我们nm install的时候,它会先去查看缓存有没有这个东西,如果有那就从本地拿到压缩包,然后解压到对应的文件里。这样就可以节省带宽,提高安装速度。

关于npm install,可以用一幅图来解释。

image.png

关于npm原理这幅图的解释

我们以安装axios来举例。

当我安装npm install axios的时候,会检查项目有没有package-lock.json ,因为package.json里面的版本号不是真实的版本号。

这里我解释一下,为什么package.json里面的不是真实的版本号。其实package.json它只是做个记录。比如说我们下载某个依赖为1.0版本,这会儿regsitry里面是1.5版本,那下载下来肯定就是1.5版本。当我们把这个代码分享给同事,同事下载下来的版本可能就会有问题了,因为这个也不是最真实的版本。而只有package-lock.json里面才是npm规定的,保存最真实版本的地方。

如果没有package-lock.json,我们会生成这个文件。 我们可以看到这里,resolve里存的就是下载在本地的位置,integrivy里面就是存放位置的索引。(这里使用了sha512算法进行加密)。

我们在终端输入npm get cache就可以这些依赖存放的位置。 我们前往该文件夹。

通过integrity这个,找到对应的文件,在Index-v5里面解密,然后找到对应的配置信息,再根据配置信息里面的信息,在去刚刚的content-v2里面找到文件。

npm的一些其他命令

卸载

npm uninstall package
npm uninstall package -D

强制重新build

npm rebuild

清除缓存

npm cache clean

想查看其他命令

docs.npmjs.com/cli-documen…访问这个

yarn工具

yarn是由Facebook、Google、Exponent 和 Tilde 联合推出了一个新的 JS 包管理工具,yarn 是为了弥补 npm 的一些缺陷而出现的,早期的npm存在很多的缺陷,比如安装依赖速度很慢、版本依赖混乱等等一系列的问题,虽然从npm5版本开始,进行了很多的升级和改进,但是依然很多人喜欢使用yarn。

下图为npm与yarn命令对照表

image.png

这里注意两点

  • yarn用的是yarn-lock,而不是package-lock.json
  • yarn和npm千万不要混在一起使用,这样会导致项目出现问题

cnpm工具

registry是外网,由于一些特殊原因,某些情况下我们没办法很好的从npm.js.org上下载一些东西。我们可以查看npm镜像并对它进行设置

  • 查看npm镜像

npm config get registry

  • 我们可以直接设置npm的镜像:

npm config set registry registry.npm.taobao.org

当然,对于大多数人来说,并不希望将npm镜像去修改。

  • 第一,我们不太愿意随意修改npm原本从官方下来包的渠道(其他渠道会有一些延迟)。
  • 第二,担心某天比如淘宝的镜像不维护了,又要改来改去。

这个时候我们就可以使用cnpm工具了,并且将cnpm设置为淘宝的镜像

npm install -g cnpm --registry=https://registry.npm.taobao.org

cnpm config get registry  # https://r.npm.taobao.org/

npx工具

npx是npm5.2之后自带的一个命令。

  • npx作用非常多,但是比较常见的就是用它来调用项目中的某个模块指令。 我们以webpack为例: 比如你在终端敲击webpack,其实电脑是从环境变量里找webpack的,比方说你webpack --version 找到的都是全局的东西。

你想要找的是node/module/.bin/webpack这个命令(局部的),你要么手动cd过去,这个太蠢了。

或者你在工程开发中你在script里面加命令 比如 npm run xxx,这样它就会从node_module里找了。

不过有了npx以后,我们现在就会很方便的使用局部的webpack工具了。

npx webpack --version 这样就可以使用局部的webpack了

发布自己的包

我们需要先从官网注册一个账号。然后后面使用命令行登录。(注册账号我就不演示了)

npm login

然后按要求输入用户名,密码,邮箱就行了。

我们可以输入npm publish发布我们的包。

需要注意的是,一旦我们修改了代码,就需要改版本以后再publish,我们是不能覆盖老版本的,需要遵循semer规范。

其他的命令:

npm unpublish 删除发布的包

npm deprecate 让发布的包过期

注意事项: 不要发布重名的包,比如vue,react,你是不可能替换掉被人的包的(手动狗头)。

使用发布的包

npm install 自己发布的包就行了。