npm的简单介绍

  npm最开始是node的包管理工具,现在成了一个庞大的生态系统。 npm 仓库包含了成千上万的开源的npm包,程序开发中所用的包都是从上面获取。npm 网站,提供了包的使用说明,和包的搜索,想使用哪个包,就到上面搜索一下。npm cli 则和npm 仓库,npm 网站建立联系,如npm install从npm 仓库下载包,npm publish向npm 仓库,npm 网站发布包。当然 npm 用的最多的还是依赖管理。说到管理依赖,还要用到package.json文件。

  一个node 项目通常称为一个package. JSON则是一种描述内容的格式,可以用来描述这个package. package.json就是一个JSON文件,包含了对packgae的描述,也就是对一个node 项目的描述,如项目(pacakge)的名字和版本等。所以创建一个node项目时,都要创建pacakge.json文件。npm init 创建该文件,不过要回答问题,如果想使用默认的package.json, npm init -y 进行创建。

{
  "name": "npml",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

  "name": "npml",  项目名称, 你可能在项目中使用过 var express = require(‘express’), require 函数后面的参数,就是package.json 中的name字段,所以这个name一定要简短,且不能有大写,这是规定。

  "version": "1.0.0", 默认的初始版本。

  "main": "index.js", 当require 该package的时候,它会执行main 指定的函数,就是index.js函数。

  "script": 定义项目中需要执行的命令,然后用 npm run 去执行这个命令,它是从node_module中读取bin目录下定义的命令。比如

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "babel index.js -o server.js"  
  },

  npm run build, 就会执行  babel index.js -o server.js 命令,省得全局安装babel.

  重点说一个版本号,可以看到项目的版本号中有三个部分组成,这就是semantic version(SemVer) 语法,SemVer 使用三部分的数字schema 来定义一个版本,基本格式如下:

  Major.Minor.Patch

  Major: 表示大版本,通常是大的功能升级,比如某些过时的功能上删掉了,有可能和以前的版本不兼容,破坏性升级

  Minor: 表示小版本,通常是增加了一些新功能,不会破坏以前的功能

  Patch: 表示补丁版本。补丁版本通常是一些bug的修复,功能不会改变。

  当做项目升级的时候,一定要按照规范进行版本号的升级,比如修复bug, 就只增加patch 部分,版本号变成"1.0.1", 还要注意,要一个一个版本号加,不能跳跃, 不能从"1.0.1" 升级到"1.0.3". 当升级Minor 小版本的时候,patch 版本要重置为0,从"1.0.1" 升级到"1.1.0"。当升级大版本的时候,小版本和补丁版本都要重置为0,从"1.1.0" 升级到"2.0.0". Numbers  always   increase  within  any  subordinate version  component,  and  reset  to  zero  when  their  superior  changes.  For  example ,  a  feature release  of  version  1.2.3  becomes  1.3.0  where  Patch  resets  to zero.  A  breaking  change  from  2.9.11  becomes  3.0.0  and  resets  both  of  the  subordinate  Minor and Patch numbers.

  项目开发过程中,经常会用到一些第三方库和框架,比如React, Babel,Express. 使用它们,就要安装它们,比如npm install express ,这时打开package.json 文件,就会发现多了一个dependencies字段,包括了刚安装的express,同时还指定了相应的版本号。这就是package.json记录和管理项目的依赖,整个项目中用到了什么,一看package.json 就知道了。当然并不是所有的依赖都是dependencies, 比如jest, 当安装jest的时候,通常会加一个参数,--save-dev,  npm install jest --save–dev, 这时package.json中多了devDependencies,包含jest. devDependencies 和dependencies 有什么区别?

  最开始的时候,Node.js主要用作web服务器开发,所以dependencies 和devDependencies也主要是针对Node.js进行服务器开发而言的,只有web服务在运行的时候所需要的依赖,才会安装到dependencies 中,web服务上线运行后,不需要的依赖,而在开发web服务过程中所需要的依赖,就要安装到devDependencies 中。比如express和jest,express 就安装到dependencies中, 而jest则要安装到devDependencies 中。进行web开发时,程序中都会写  var express  = require(‘express’), 程序的运行直接依赖express,所以是dependencies. dependencies 就是在程序开发的过程中手动require的模块,程序的源代码中包含的模块。jest则是开发过程时进行的测试,保证程序上线后不出问题,而等到程序真正上线以后,不需要跑测试,所以是devDependecies。

  但随着Node.js的发展,它也用到了前端打包工具上来,比如webpack, 整个webpack项目,只是把代码进行打包,把多个文件打包成一个文件,完全没有服务器开发的概念,整个项目开发过程中,都不是开发服务器项目,也不存在web服务运行时的所需要的依赖,按照上面的说法,所有的依赖,都是开发时依赖,不管用的是react还是babel, 统统都是开发依赖,都放到devDependecies 中。只要webpack打包完成,拿到打包后的内容,整个项目都不需要了。我们只需要把打包后的内容部署到服务器上,而不是把webpack项目部署到服务器上。前端打包工具项目,真正起作用的是打包工具,它根本不在乎是dependencies 还是devDependecies。webpack 在进行打包的时候,它会从入口文件开始遍历,只要项目(源代码)中引入了一个依赖,它就会把这个依赖打包到最终的build文件中,而不管这个依赖在package.json中是dependencies 还是 devDependecies, webpack 在打包的过程中只要发现你在文件中引入了一个包,它就分把它打包到最终的输出文件中。 所以对webpack 而言,如果不想把一个包打包到最终的输出文件中,不是把这个包放到devDependecies 中,而是使用webpack的external 属性,当然,前提是这个包在项目(源代码)中用到,如果在项目中没有用到,webpack 也不会对这个包进行打包。

  无论devDependencies还是dependencies,安装时,都有版本号,并且版本号前面还有符号^。符号表示的是项目对依赖版本的升级的容忍程度。符合有几种情况,没有符号,~符号,^符合

  "express": "4.15.2",版本号前面什么符号都没有,它表示固定版本,项目只使用这一个特定版本,npm 安装express的时候,只能安装这一个版本。

  "express": "~4.15.2",版本号前面有符号~,它表示安装4.15.x 的版本,只要x>3 就可以。express是4.15.2 版本,npm install 可能安装4.15.5或者4.15.6 版本。

Accept a range of patches for a minor update only, accept bug fixes (patches) but don’t want npm to automatically upgrade to new feature releases.

  "express": "^4.15.2" , 版本号前面有符号^, 它表示可以安装4.x.x 的版本,只要中间的x 大于15就可以。 Accept  a  range  of  minor  feature  releases。  If  you  can  tolerate  bug fixes and minor feature releases within a major release, use the caret (^) character

  "express": ">=4.15.3"  版本号前面有符号>=, 安装大于等于指定的版本,就可以。

  有时还看到一个*, 表示安装最新版本。

  版本号一定要注意,因为有些框架和库在进行版本升级的时候,向后兼容性比较差,容易引起代码冲突。但npm install 进行安装的时候,它默认是^ 符号,如果不符合我们要求,我们可以对package.json 进行手动修改,如 把^号改成~, 或直接去掉符号, package.json文件,只是一个文件, 我们可以手动地进行任何修改。当然,从npm 5 之后,有了package-lock.json文件,它会锁定版本。

  使用npm install 默认安装方式带来的问题,就是两个开发者在各自的机器上安装的node_module 不一致,可能引发程序出问题。在package.json 中保存依赖,任何人拿到项目时,使用npm install 就可以安装整个项目的依赖包,npm 在安装依赖的时候,会按照依赖在package.json中的位置,从上到下依次安装。比如@babel/preset-env. 当我在开发项目的时候,版本号可能是7.7.0。 npm i @babel/preset-env --save-dev.那么在package.json文件夹中,就会被记录下来 “@babel/preset-env”: “^7.7.0”, 同时项目中真正安装的版本是7.7.0. 不久之后,项目上传到git. 同事开始合作开发,他git clone, npm install.  这时@babel/preset-env可能升级了几个版本,比如7.9.0. 他npm install, 真正安装的版本是7.9.0. 通常没有问题,但如果他在开发项目的过程中,使用了7.9.0 中的内容(option chaining )。当我git pull把代码拉取下来,本地编译 就会报错,因为我本地的node_module中的版本7.7.0 中没有这个功能。不同的机器上,不同的版本,导致的问题就是为什么在我的电脑上跑不起来。

  正是由于松散的依赖版本号规定,通过npm install,你的电脑上安装的node_module目录结构,可能和我创建项目时安装的node_module 结构不一致。都是npm install, 但结果却不致,这就带来的不确定性,我们并不能决定node_modules 长什么样子。因此,需要锁定依赖的版本号。package-lock.json 就是干这个活的。当开发过程中,  npm install时,package-lock.json会准确的记录下安装的哪一个版本,这个版本是固定版本,当别人拿到项目时进行npm install的时候,它是按照package-lock.json中规定的版本号进行安装。 

  

posted @ 2017-04-28 12:21  SamWeb  阅读(6791)  评论(1编辑  收藏  举报