是用nodejs写的包管理生态系统css
windows 安装完node一般会自动设置环境变量PATHnode
NODE_PATH = XXX\Node\nodejs
PATH = %NODE_PATH%\;%NODE_PATH%\node_modules;%NODE_PATH%\node_global;
复制代码
若是不配置呢?git
error:node不是内部或外部命令,也不是可运行的程序 或批处理文件。算法
查看npm配置数据库
npm config ls 或 npm config list
复制代码
上面一样列举了npmrc(npm用户配置文件)的地址npm
这里面核心的是三项json
npm config set prefix "F:\office_software\nodejs\xxx_global"
复制代码
npm config set registry "https://registry.npm.taobao.org"
复制代码
另一个配置就是npm缓存的目录windows
$ npm config get cache
C:\Users\Administrator\AppData\Roaming\npm-cache
复制代码
npm-cache存放下载包的缓存(对应sha1计算后的内容也在里面)缓存
npm config set cache "F:\office_software\nodejs\xxx_cache"
复制代码
这两个命令是同样的,一个全写一个简写bash
npm install 或 npm i
复制代码
npm会根据package.json配置文件中的依赖配置下载安装到项目下的node_modules目录
npm i -g XXX
复制代码
全局安装,安装后的包位于系统预设目录下
这样就安装在了C:\Users\Administrator\AppData\Roaming\npm\node_modules目录下
安装的包将写入package.json里面的dependencies,dependencies:生产环境须要依赖的库
好比:less和scss编译用的包,只有开发时才用获得,实际运行时并不用到,因此就不用放到生产环境依赖包中
安装的包将写入packege.json里面的devDependencies,devdependencies:只有开发环境下须要依赖的库
假如npm_pkg包已经写好(里面只要有个package.json就能够),如
npm install ../npm_pkg
复制代码
一般用来测试本地npm包
npm install ../npm_demo_cli -g
复制代码
npm install还有不少其余使用方式,不经常使用,就不一一介绍了。 具体请参照《官方文档》
主版本号[MAJOR].次版本号[MINOR].修订号[PATCH]
当主版本号升级后,次版本号和修订号须要重置为0,次版本号进行升级后,修订版本须要重置为0。
用到的语义化字符有: ~、>、<、=、>=、<=、-、||、x、X、*
'^2.1.1' // 2.x最新版本(主版本号锁定)
'~2.1.1' // 2.1.x最新版本好(主和次版本号锁定)
'>2.1' // 高于2.1版本的最新版本
'1.0.0 - 1.2.0' // 两个版本之间最新的版本(必需要有空格)
'*' // 最新的版本号
'3.x' // 对应x部分最新的版本号
复制代码
npm install默认安装 ^x.x.x类型的版本,用于兼容大版本下最新的版本
执行工程自身preinstall
肯定首层依赖模块
获取模块
若是npm-shrinkwrap.json和package-lock.json同时存在,则以npm-shrinkwrap.json为主,忽略另外一个
获取模块内容
查找该模块依赖
模块扁平化
遍历全部节点,逐个将模块放在根节点下面,也就是 node-modules 的第一层。当发现有重复模块时,则将其丢弃
这里须要对重复模块进行一个定义,它指的是模块名相同且 semver 兼容。每一个 semver 都对应一段版本容许范围,若是两个模块的版本容许范围存在交集,那么就能够获得一个兼容版本,而没必要版本号彻底一致,这可使更多冗余模块在 dedupe 过程当中被去掉。
好比
node-modules 下 foo 模块依赖 lodash@^1.0.0,bar 模块依赖 lodash@^1.1.0,则 ^1.1.0 为兼容版本。
而当 foo 依赖 lodash@^2.0.0,bar 依赖 lodash@^1.1.0,则依据 semver 的规则,两者不存在兼容版本。会将一个版本放在 node_modules 中,另外一个仍保留在依赖树里。
安装模块
执行工程自身生命周期
最后一步是生成或更新版本描述文件(package.json和package-lock.json),npm install 过程完成。
若是这个npm还有其余依赖包,会一并安装(只会安装dependencies部分)
devDependencies中的依赖并不会安装
A@1
|-B@1.1
|-C@1
D@1
|-B@1.2
E@1
|-B@1.3
复制代码
这个时候,由于解析的时候,B@1已经在根目录了 那么B@2就会成为D@1中私有模块,即
node_modules
|-A@1
|-B@1.3
|-C@1
|-D@1
|-E@1
复制代码
A@1
|-B@1
|-C@1
D@1
|-B@2
E@1
|-B@2
复制代码
这个时候,由于解析的时候,B@1已经在根目录了 那么B@2就会成为D@1中私有模块,即
node_modules
|-A@1
|-B@1
|-C@1
|-D@1
|-node_modules
|-B@2
|-E@1
|-node_modules
|-B@2
复制代码
后面版本的npm包,即便是以前在私有目录中安装过,也一样会重复安装
那一样版本的npm包会屡次安装么
npm 5版本引入了package.lock.json
即在npm install以后会在根目录下生成一个package.lock.json文件
举个例子
{
...
"babel-polyfill": {
"version": "6.26.0",
"resolved": "https://rcnpm.zhuanspirit.com/babel-polyfill/download/babel-polyfill-6.26.0.tgz",
"integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=",
"requires": {
"babel-runtime": "6.26.0",
"core-js": "2.6.5",
"regenerator-runtime": "0.10.5"
},
"dependencies": {
"regenerator-runtime": {
"version": "0.10.5",
"resolved": "https://rcnpm.zhuanspirit.com/regenerator-runtime/download/regenerator-runtime-0.10.5.tgz",
"integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg="
}
}
}
}
复制代码
结构很简单:
锁定安装时包的版本号,而且能够上传到git
保证每一个人安装的依赖是同样的
由于npm install -D xxx 以后,默认版本是向后兼容的
好比:
"dependencies": {
"core-js": "^3.2.0",
}
复制代码
^3.2.0 即表示3.x版本中最新的版本
也就是说package.json中锁定的实际上是大版本号,而小版本每次安装都是取最新的。
假如说后面又发布了3.x更高版本,那么后面执行npm install同窗安装的就是更高的版本了,好比3.5.0
固然,上面说的版本号规则都是所谓的“规则”,并无什么强制校验的措施,遵不遵照全凭自觉。因此颇有可能出现:
即便是小版本也会出现和以前版本不兼容的状况。
因此,锁定当前的npm包的版本号就颇有必要,package.lock.json 也就应运而生了。
那么package.lock.json做用就是:锁定npm包小版本号
问题:那npm install时,若是package.json和package-lock.json都存在,以哪一个为主?
其实只有一条规则:==若是package-lock中的版本,在package.json范围内,就以package-lock为主,不然以package.json为主==
好比:以core-js为例子
1)场景一
package.json 中是 "^3.2.0", package-lock.json 中是 "3.1.0"
兼容范围是3.2.0+版本,而3.1.0是在这范围以外(比这小),因此安装时以package.json的^3.2.0为主,就会安装3.x最新的版本(目前是3.5.0)
2)场景二
package.json 中是 "^3.1.0", package-lock.json 中是 "3.2.0"
兼容范围是3.1.0+版本,而3.2.0正符合这个范围,因此安装就按照package-lock.json中指定的3.2.0版本
node为script指令提供了生命周期钩子
举个例子,好比package.json中:
"scripts": {
"aaa": "echo \"Log: aaa specified\""
}
复制代码
当执行下面脚本时
npm run aaa
复制代码
实际上等价于际执行
if (preaaa) npm run preaaa
npm run aaa
if (postaaa) npm run postaaa
复制代码
因此,进一步实验
"scripts": {
"aaa": "echo \"Log: aaa specified\"",
"preaaa": "echo \"Log: preaaa specified\"",
"postaaa": "echo \"Log: postaaa specified\" & exit 1"
}
复制代码
结果为:
E:\work\npm_test>npm run aaa
> npm_test@1.0.0 preaaa E:\work\npm_test
> echo "Log: preaaa specified"
"Log: preaaa specified"
> npm_test@1.0.0 aaa E:\work\npm_test
> echo "Log: aaa specified"
"Log: aaa specified"
> npm_test@1.0.0 postaaa E:\work\npm_test
> echo "Log: postaaa specified"
"Log: postaaa specified"
复制代码
npm run执行时,会把./node_modules/.bin/ 目录添加到执行环境的 PATH 变量中
这样,即使只在当前项目里安装了某个包,npm run同样能够调用
执行 script 脚本若是须要传入参数,须要在命令后加 -- 标明, 如:
npm run dev -- -r main
复制代码
将自定义参数r=main传入dev命令中
在执行的script 脚本中,能够直接使用process.env对象,它会返回全部和执行环境相关的信息
注:获取属性时,若是是带有中划线的属性,须要改为下划线,如core-js须要改为core_js
删除npm_cache下全部缓存文件
删除后,package-lock.json文件中就找不到对应的sha1内容了,就会强制从新从服务器拉取npm包
从新计算npm_cache下全部缓存文件是否与sha1值匹配,若是不匹配可能删除
删除package.lock.json文件
npm cache clean --force强制删除缓存中的npm包