Mosh的Node.js教程(四)

作者:大志前端
链接:https://juejin.cn/post/6844903470797946887
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
前言


本系列文章是根据Mosh大佬的视频教程全方位Node开发 - Mosh整理而成,个人觉得视频非常不错,所以计划边学习边整理成文章方便后期回顾。该视频教程是英文的,但是有中文字幕,感谢marking1212提供的中文字幕翻译。

本篇文章大纲

  • NPM介绍
  • package.json
  • 安装一个包
  • 使用一个包
  • 包的依赖
  • NPM的包与源代码管理
  • 语义化版本控制
  • 列出已安装的包

NPM介绍

NPM全称Node Package Manager,即包管理工具。它基本是一个命令行工具,也是第三方库注册到Node的注册机。

无论你想向Node添加什么功能,很可能在注册库中已经第三方的免费模块或包了。

我们打开NPM官网npmjs.com,NPM中的所有模块都是免费并且可复用的。你可以很简单的向你的应用添加这些功能模块,同样的,如果你在Node上有个好点子的实现,并希望分享给大家,你可以创建自己的模块,并在NPM上发布。向我们的应用添加NPM的方法,是借助一个也叫npm的命令行工具,也就是node packets manager

所以第一件事就是打开控制台,运行npm -v,查看我们电脑安装的npm是什么版本,npm是伴随着Node而来的,如果你安装了Node也同时安装了npm。有趣的是如果你运行node -v,你会发现npm的版本和node的版本是不一样的,因为这两个应用程序是各自独立开发的。

有可能我们安装的npm版本跟作者的不一样,可以使用npm i -g [email protected]来安装指定的版本号。如果你使用的是Mac,需要前置sudo关键字,即sudo npm i -g [email protected],因为有可能你没有设置好用户权限,当你运行时可能得到一个权限错误,因为你要全局安装,所以解决办法就是前置sudo关键字,这只是针对Mac用户。如果你在Window下得到权限报错,你只能在用户管理的地方添加用户权限。

package.json

我们创建一个新的文件夹叫npm-demo,然后进入这个文件夹,在你添加任何包之前,你需要创建一个文件,就是package.json,这个文件本质上是一个JSON文件,它包含了你的应用或程序最基本的信息,比如名字、版本、作者、反馈的地址、依赖的关系等等,所有的Node的应用都有这个JSON文件。

为了创建这个文件,我们运行

npm init
复制代码

这是一个向导式的一步步创建的过程,它会问你一些问题,比如第一个就是包的名称,根据提示来按enter一直下一步即可。

我们来看下最后生成的package.json文件

{
  "name": "npm-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}
复制代码

还有一个更快的创建的方式,之前我们用的npm init,然后你需要回答它提出的所有问题,如果你不想回答,可以立一个flag,就是--yes,这样就能使用所有的默认值创建该文件。

npm init --yes
复制代码

安装一个包

我们先试试安装一个很有名的包underscore,先打开npmjs.com,搜索underscore,在搜索结果中找到underscore,点击进去,可以看到当前最新的版本和其他的一些基本信息,比如作者、Github仓库的地址等等。

安装方式

npm i underscore
复制代码

回到控制台,我们输入npm i underscore,当运行完这行命令,发生了两件事,首先在package.json可以看到一个新的dependencies属性,在它下面就是underscore,在应用的package.json文件中标识了每个依赖库的名字和版本。

看下现在的package.json文件

{
  "name": "npm-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "underscore": "^1.9.2"
  }
}
复制代码

当我们运行了npm inpm会从注册库中下载给定名称的库的最新版,然后会将它保存在一个叫node_modules的文件夹中,在里面你可以看到一个叫underscore的文件夹,里面有一些文件,其中一个就是package.json,每个node模块都有的自己的package.json,就像node应用本身。

如果你打开underscorepackage.json文件你就可以看见它的版本号和其他很多的基本信息,比如主页、关键字等等。

在之前版本的npm,安装包的方法是这样的,输入npm i underscore,后面还要附加--save的flag,没有这个参数,node的package.json中的依赖关键字就不会添加underscore,这个行为特征在新版的npm中改变了,不用在刻意添加--save参数了,只需要运行安装命令npm i,安装给定名称的包,npm就会下载最新的版本,并且修改package.json文件,最终保存于node_modules文件夹中。

使用一个包

我们已经安装了underscore的第三方库,现在我们来使用看看。

回到VSC,我们新建一个文件,命名为index.js,我们使用require函数来导入这个模块。

var _ = require('underscore')
复制代码

这就是require函数的用法,当你这里传入了模块名,首先它认为你需要一个核心模块,在node中没有一个叫underscore的核心模块,然后require函数就会认为,也许有叫这个名字的文件或文件夹,但是之前我们说过,当你要引用文件夹中的文件,需要使用./,所以如果参数是./underscore,这样require函数就会认为,在同一个文件夹中有一个叫underscore.js的文件,如果不是,它就会认为有一个叫underscore的文件夹,里面有一个index.js的文件,但是在我们的项目中,并没有一个underscore的文件夹,这样require函数就会假设第三种可能,它会认为在node_modules文件夹中有个叫underscore的库,这就是require函数查找一个模块的过程。

现在我们已经导入underscore模块了,我们来开始使用它,首先我们打开它的官网underscorejs.org,你就能看到underscore库的文档,这个库包含了非常多的工具函数,这里我们演示一下contains函数。

点击文档左侧菜单的contains函数,可以看到它的用法underscorejs.org/#contains。它需要两个参数,第一个参数是一个数组,第二个参数是需要在数组中搜索的特定值,结果返回的是一个布尔值。

var _ = require('underscore');

var result = _.contains([1, 2, 3], 2);

console.log(result); // true
复制代码

我们得到的结果为true,这就是在node中使用第三方库的方法。

包的依赖

这里我们先来做一个小练习,我们安装一个node模块名为mongoose,我们用它来向MangoDB保存数据,这个会在后面的课程介绍。

我们先来安装一下

npm i mongoose
复制代码

安装完,打开package.json,可以看到这个文件已经更新了,dependencies中多了一个mongoose的属性,现在我们再来看下node_modules文件夹有什么变化。

回到VSC,点开node_modules文件夹,发现多出了很多文件夹,这些是从哪里来的,我们只是安装了一个mongoose模块而已,如下图:

image

这里你看到的这些库,是其他的node模块包,并且是mongoose模块依赖的库,在之前版本的npm中,这个过程是不同的,所有第三方库依赖的库是安装在自身文件夹中的。

例如这里的underscore文件夹,我假设它依赖一些其他库,在之前版本的npm中,这些库将存储在这个文件夹中,在另一个叫node_modules文件夹中,这样node模块和它的依赖模块是高度耦合的,这样就一团糟了,一个库可能被多次安装,这样你可能会得到一个非常深度嵌套的文件结构,特别在Window中,是限制了文件夹包含对象的数量的,所以现在的npm这个实现过程已经不同了。

现在所有应用的依赖以及它们的依赖,都保存在最外层的node_modules文件夹中,也有例外,比如两个模块依赖同样库但所依赖的版本不同,这样它们的依赖将各自保存于它们自身的文件夹中。

NPM的包与源代码管理

我们可以看到在node_modules中有不少的文件夹,这还是非常简单的应用,在真实的开发中,会有更多的文件夹,node_modules文件夹的大小增长的非常迅速,在实际的开发中,node_modules文件夹的大小可能有几百兆,当在源码控制仓库中检查源码时,你不会想要包含这些文件夹的,因为每次当别人检查你的源代码时,都需要等待几百兆数据的下载。

事实上当你想将代码从一处拷到另一处,比如说你想通过email或者网盘发给朋友,你不想发送所有node_modules的内容,这时候你可能会问,那这些依赖怎么办,没有又不行,好消息是所有依赖的信息都保存在package.json文件中,比如现在我们有两个依赖库underscoremongoose,这样可以轻松的将依赖库在任何地方任何机器上恢复回来。

为了演示,我们先把node_modules文件夹删掉,回到控制台,我们通过npm i来恢复所有的依赖库,npm会检查package.json,然后会从npm注册库中下载所有的依赖,如你所见,node_modules文件夹又回来了,并且恢复了所有的依赖。这就是为什么我们在源码版本控制的时候不用包含依赖库。

如果我们使用的是Git,我们来看一下如何在Git下排除这个文件夹,回到控制台,我们要在文件夹中生成一个Git仓库,执行命令

git init
复制代码

这样就生成了一个Git本地仓库(前提需要你电脑已经安装了Git,没有安装的自行安装一下)。

如果你运行git status,如你所见,下面这些是需要添加到Git仓库的文件

image

我们这里需要排除node_modules文件夹,回到VSC,在文件夹的根目录创建一个新文件,只需要设置扩展名是.gitignore,这个文件没有文件名,这里面可以列出所有排除在Git仓库之外的文件和文件夹,我们打开这个文件写上

node_modules/
复制代码

这里要注意加上/,表示它是一个文件夹,保存修改。

现在回到控制台,再次运行git status,可以看到这里已经不再包含node_modules文件夹了,之前还有的,现在已经没有了,取而代之的是.gitignore文件,这就是如何在Git仓库中排除node_modules文件夹的方法。

image

最后我们运行git add .,并在git commit提交时留下日志信息“我的第一次提交”

git add .
git commit -m "我的第一次提交"
复制代码

语义化版本控制

在之前的章节中,我们有提到一个幂符号^,就是package.json文件中的dependencies属性中出现的版本号前面的那个符号。

"dependencies": {
    "mongoose": "^5.9.0",
    "underscore": "^1.9.2"
}
复制代码

在计算机里这是插入符号,但是这里是什么意思呢?为了理解这个符号,首先要理解语义版本控制,也就是SemVer,下面简称SV

SV

SV中,node包的版本号有3个部分,比如我们看到mongoose的版本号是5.9.0,第一个数字5我们叫主要版本号,第二个9我们叫次要版本号,第三个0我们叫补丁号:它是用来表示修复的bug。

补丁号

比方说某一天,mongoose的开发者找到一个在当前版本下的bug,他们修复了错误并发布了新版本,那新的版本号应该是5.9.1,所以当他们修复了错误,他们就增加补丁号的数字。

次要版本号

次要版本号是表示添加了新特性,不会破坏现有的api,同样如果是mongoose团队添加了一个新特性,没有破坏现有的接口设置,他们就会增加次要版本号的数字值,那么这个版本号应该是5.10.0,补丁号是0,是因为发布时在这个版本中还没找到bug,所以也意味着不稳定,当他们发现了bug时并且修复了错误,他们就会增加补丁版本号的值。

主要版本号

最后一点如果他们添加了新特性,很可能破坏了现有应用与mongoose的依赖关系,他们那就会增加主要版本号的数字值,这样下一个主要版本就应该是6.0.0,这就是我们所说的语义化版本控制。

这边的^符号

我们这边看到的^符号,是告诉npm你关心mongoose的任何版本更新,只要主要版本号是5,如果有更新的次要版本或者补丁版本可以下载,我们就关注这个包并下载。

比如说今天当我们新建一个工程,我们使用的这个版本是5.9.0,6个月之后有人从Git仓库中检查代码的时候,然后,他使用npm i来恢复源码仓库,就在这时正好有新版本的mongoose已经发布了,只要它的版本是5,也就是说没有主要更新或者重大更新,那这个新版本就会被npm i工具下载到本地的node_modules文件夹中。

另一种情况不使用^插入符号是这样的,5.x这两种写法是一样的,有时候在现实的开发中,有可能看到的不是插入符号^而是看到波浪线~,比如下面这样

"dependencies": {
    "mongoose": "~5.9.0"
}
复制代码

这个意思是你对任何版本只要主要版本号是5并且次要版本号是9,另一种特别指定版本号的语法就是5.9.x,如果有新的补丁版发布,我们就下载那个新版本。

如你所见,插入符号和波浪线符号是帮助我们保持应用为最新,伴随最新发布的依赖库,但是有时这会造成问题,特别在现实开发中,例如underscore发布了一个新版本号为1.9.3,它修复了一些bug,但是也破坏了一些其他的东西,这可能意味着你应用接口出现故障,这种情况下你需要确保你使用的是相同的版本,如果有人在几个月之后检查仓库中的代码你需要确保它使用和第一天完全一致的underscore版本,为了做到这点,你可以简单的删除这个波浪线或者插入符号,这样下一次你运行npm i就会安装特定的版本。

"dependencies": {
    "underscore": "1.9.3"
}
复制代码

以上这些就是如何进行版本的语义化并使用正确的版本。

列出已安装的包

现在你知道插入符号^的意义了,意思是你可以在本应用中使用只要主要版本号是5的任何最新版的mongoose,现实中当你重置你的依赖库,有可能在node_modules中的mongoose已经高于这个版本了。我怎么知道我已经安装了什么版本的库,有两种方法:

1、一个是查看mongoose库下的package.json文件

打开node_modules文件夹,找到mongoose文件夹,找到package.json,滚动到最底下,可以看到有个version属性,这就是现在已经安装的版本号,如下图

image

但是这有点复杂了,如果你要查看很多个依赖,你肯定不想一个个找出package.json来查看,如果你想查看和列出所有依赖库的版本,你可以简单运行

npm list
复制代码

控制台输出如下图

image

这棵树表示了所有的依赖和它们的依赖,例如我们正使用的underscore1.9.2版本,同时看到mongoose和它的所有依赖,可以在名字后面看到它们对应的版本号,这棵树有太多细节可能有点乱,也许你只对自己应用的依赖感兴趣,而不是这些包自己的依赖,如果是这种情况,当运行npm list的时候,我们可以添加一个参数--depth=0,这样可以只看到你的应用所需的依赖,这里就是mongooseunderscore,如下图所示

image

好了,本篇文章先到这里。

最后

感谢您的阅读,希望对你有所帮助。由于本人水平有限,如果文中有描述不当的地方,烦请指正,非常感谢。


作者:大志前端
链接:https://juejin.cn/post/6844903470797946887
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:(Mosh的Node.js教程(四))