package.json
字段说明
- name 包的名称
- version 包的版本号
// 查看最新版本
npm view react version
// 查看所有版本
npm view react versions
- scripts
是package.json中内置的脚本入口
"scripts": {
"dev": "node index.js",
"predev": "node beforeIndex.js",
"postdev": "node afterIndex.js"
}
使用 npm run xxx 运行script 的命令
如: npm run dev
- config
config字段用来配置scripts运行时的配置参数
举例:
"config": {
"port": 3000
}
如果运行npm run start,则port字段会映射到`npm_package_config_port`环境变量中
用户可以通过`npm config set foo:port 3001` 命令来重写port的值。
5. main
main 字段是用来指定加载的入口文件。如果我们将项目发布为npm包,那么当使用 require 导入npm包时,返回的就是main
字段所列出的文件的module.exports 属性。如果不指定该字段,默认是项目根目录下的index.js
举例:
"main": "./src/index.js",
6. browser
browser字段可以定义 npm 包在 browser 环境下的入口文件。如果 npm 包只在 web 端使用,并且严禁在 server
端使用,使用 browser 来定义入口文件
"browser": "./src/index.js"
7. module
最早由 rollup 提出, 【在npm v9.2.0 版本中,还不是官方标准】,但是webpack 也已经支持
8. bin
bin字段用来指定各个内部命令对应的可执行文件的位置
"bin": {
"someTool": "./bin/someTool.js"
}
这里,someTool 命令对应的可执行文件为 bin 目录下的 someTool.js,someTool.js会建立符号链接node_modules/.bin/someTool。由于node_modules/.bin/目录会在运行时加入系统的PATH变量,因此在运行npm时,就可以不带路径,直接通过命令来调用这些脚本。因此,下面的写法可以简写:
scripts: {
start: './node_modules/bin/someTool.js build'
}
// 简写
scripts: {
start: 'someTool build'
}
- peerDependencies
从npm 3.0版开始, peerDependencies不再会默认安装了
用于放置当前package中使用的依赖,而且会在引用的项目中会存在的依赖。放在peerDependencies中的依赖不会再当前
package中下载,而会使用引用的项目中的依赖
如果package中放在peerDependencies的依赖,但是项目中不存在依赖,同样会报错
详细参考链接:juejin.cn/post/702353…
npm 依赖包说明
- ~ 会匹配最近的小版本依赖包,比如~1.2.3会匹配所有1.2.x版本,但是不包括1.3.0
- ^ 会匹配最新的大版本依赖包,比如^1.2.3会匹配所有1.x.x的包,包括1.3.0,但是不包括2.0.0
- ✱ 意味着安装最新版本的依赖包
.npmrc 配置
-
说明:.npmrc,可以理解成
npm running cnfiguration,在npm 运行命令时,都会读取这个配置文件的配置内容。配置选项将按优先级顺序解析。例如,userconfig文件中的设置将覆盖globalconfig文件中的设置 -
在电脑上存在多个 .npmrc 文件
1. 项目配置文件:在项目根目录下创建.npmrc
2. 用户配置文件:可通过 npm config get userconfig 获取路径,一般在 C:\Users\***\.npmrc
3. 全局配置:一台电脑可能有多个用户,在这些用户之上,你可以设置一个公共的.npmrc文件,供所有用户使用
通过 npm config get prefix 获取
4. 内置配置文件: path/to/npm/itself/npmrc, 这是一个不可更改的“内置”配置文件,npm在更新时保持一致。
使用npm附带的./configure脚本在这里设置字段。这主要是为了让发行版维护者以标准和一致的方式覆盖默认配置
- 配置是 以 key=value 的形式进行配置
1. registry=https://registry.npmjs.org // 配置安装包的下周路径,可以配置多个
2. @test:registry=https://npm.xxx.com // 以@test开头的包从 https://npm.xxx.com地址下载
3. _auth="用户名:密码"的base64编码
4. _authToken=xxxx // 配置认证信息
5. username=xxx
6. _password=xxx
7. email=xxx
8. certfile // 证书文件路径
9. keyfile // 密钥文件路径
- npm 常用命令
npm config set <key> <value> [-g | --global] // 给配置参数key 设置值value,更改的是【用户配置文件】
npm config get <key> // 获取配置参数key 的值,根据npmrc 优先级获取
npm config delete <key> [-g | --global] // 删除配置参数key 的值
npm config [list | ls] [-l] // 显示npm 所有配置参数的信息 L 代表全部的默认信息
npm config edit // 编辑用户配置文件
npm set <key> <value> [-g | --global] // 给配置参数key 设置值value
npm install 的原理
npm 在3.x 版本中做了更新,将早期的嵌套结构改为扁平结构,安装模块时,不管其是直接依赖还是直接依赖的子依赖,优先将其安装在node_modules 根目录。
- 如果package.json 中不存在install 的包,则会安装 包的最新版本
- 如果package.json 中存在,则NPM会安装满足package.json中声明的semver规则的最新版本
npm install 安装规则
- 当我项目中依赖如下时
1. 项目中的package.json
{
"dependencies": {
"testone": "^1.0.0",
}
}
2.testone的package.json
{
"dependencies": {
"testtwo": "^1.0.1",
}
}
node_module的结果
2.在 步骤1 的基础上 在根目录安装 testTwo@1.0.2 则node_modules 的结构不变
3.当我项目中依赖如下时
1. 项目中的package.json
{
"dependencies": {
"testone": "^1.0.0",
"testtwo": "^2.0.0"
}
}
2.testone的package.json
{
"dependencies": {
"testtwo": "^1.0.1",
}
}
node_modules结果
结论:
-
npm install安装依赖时,不管其是直接依赖还是直接依赖的子依赖,优先将其安装在 node_modules 根目录 -
当依赖A安装完成后,A依赖的子依赖 B 存在于node_modules 根目录下,此时项目再安装直接依赖B时,会进行判断,如果版本相兼容,则不处理。如果版本不兼容,那么则将直接依赖B 的版本安装在node_modules的根目录下,A依赖的B的版本则安装在 A->node_modules 下。( 就算是 A.B的版本 > B 依然如此 )
-
npm 5.x 版本后加入了 package-lock.json 后解决了package.json 内依赖顺序不同,根目录依赖版本不同的问题。
-
如果子依赖 A 版本升级后,且A依赖的B 版本 与 直接依赖B 版本相兼容,那么则删除 A -> node_modules -> B
node_modules 的依赖引用原则
1. 导入的模块不是nodejs的内置模块,也不是以/,…/ 或者./ 开头的本地模块,而是npm 的依赖包,那么nodejs会尝试从
当前模块所在目录开始加载
2. 如果当前模块所在目录找不到,则到当前目录的上一级目录的node_modules 文件夹中查找。直到文件系统的根目录
举例:
文件所在路径为 project/src/index.js
index.js 代码如下:
import lodash from 'lodash'
- ode 在引入时先查找 project/src/node_modules 是否存在lodash
- 在,则去查找 project/node_modules
试想如下一个问题:
1. 系如上图所示
2. 假如在A@1.0.0的依赖包中使用了 deep 的 deepFun 函数
3. 我们再项目中 也同样使用deep 的 deepFun 函数
4. 因为使用的版本不同,那么webpack打包时将 两个 deepFun 函数的打包吗?
结论:webpack 打包时是会打包两个函数进入打包文件的。这种情况是会造成代码冗余的。
npm link
创建两个工程
- npm 的依赖包myapp
- 需要使用 myapp 依赖包的工程
name如何在工程2 中使用 工程1 中要发布的npm 包呢?
- 首先在工程1 中运行
npm link, 运行后,会在nodejs/node_modules/下创建 myapp的文件夹,相当于是安装了 全局依赖
- 在工程2中 运行命令
npm link myapp, 则在当前工程的node_modules下创建了 myapp的文件夹 - 完成上面两步后,就可以在当前项目中使用了。通过
import引用或者npx运行相关命令
.bin 文件夹
官方解释: A lot of packages have one or more executable files that they'd like to install into the PATH. npm makes this pretty easy (in fact, it uses this feature to install the "npm" executable.)
翻译: 许多包都有一个或多个它们想要安装到PATH中的可执行文件。NPM让这变得非常简单(事实上,它使用这个特性来安装“NPM”可执行文件)。
示例
- 通过npm init 创建依赖工程,添加 bin 属性配置如下
{
"name": myapp,
"bin" : { "custemApp" : "./cli.js" }
}
当我们安装了 myapp 的依赖之后,它会创建一个从cli.js脚本到/usr/local/bin/myapp的符号链接。
(这个符号链接没有找到,有大神望告知)
- 在bin 关联的 cli.js 中编写代码如下,
#!/usr/bin/env node
console.log('my love!');
// 配置#!/usr/bin/env node, 就是解决了不同的用户node路径不同的问题,可以让系统动态的去查找node来
执行你的脚本文件
- 通过
npm publish或者npm link发布包 - 在新的工程中
npm install myapp或者npm link myapp引用。 - 在新的工程中使用
npx custemapp 运行,查看输出结果,如下所示
注释 如需开发一个复杂的工具,使用node.js 编写即可。
结果 我们可以看到在安装工程中的 node_modules/.bin 文件夹中会生成这样三个文件
- custemApp 内容是 shell 脚本 对应unix系的shell脚本
- custemApp.cmd 内容是 cmd 脚本 对应的是windows bat脚本
- custemApp.ps1 内容是 powershell脚本 对应的是windows powershell脚本
脚本最后都运行了 node "$basedir/../myapp/cli.js", 可以看出目的就是找到node_modules/myapp/cli.js 去执行,核心就是拼接实际的路径,以及判断是不是 Windows 环境、来决定运行 node 还是 node.exe。