现如今,前端开发的同学已经离不开 npm
这个包管理工具,其优秀的包版本管理机制承载了整个繁荣发展的NodeJS
社区,理解其内部机制非常有利于加深我们对模块开发的理解、各项前端工程化的配置以加快我们排查问题(相信不少同学收到过各种依赖问题的困扰)的速度。
本文从三个角度:package.json
、版本管理、依赖安装结合具体实例对 npm
的包管理机制进行了详细分析。
在 Node.js
中,模块是一个库或框架,也是一个 Node.js
项目。Node.js
项目遵循模块化的架构,当我们创建了一个 Node.js
项目,意味着创建了一个模块,这个模块必须有一个描述文件,即 package.json
。它是我们最常见的配置文件,但是它里面的配置你真的有详细了解过吗?配置一个合理的 package.json
文件直接决定着我们项目的质量,所以首先带大家分析下 package.json
的各项详细配置。
package.json
中有非常多的属性,其中必须填写的只有两个:name
和 version
,这两个属性组成一个 npm
模块的唯一标识。
name
即模块名称,其命名时需要遵循官方的一些规范和建议:
包名会成为模块url
、命令行中的一个参数或者一个文件夹名称,任何非url
安全的字符在包名中都不能使用,可以使用 validate-npm-package-name
包来检测包名是否合法。
语义化包名,可以帮助开发者更快的找到需要的包,并且避免意外获取错误的包。
若包名称中存在一些符号,将符号去除后不得与现有包名重复
例如:由于react-native
已经存在,react.native
、reactnative
都不可以再创建。
例如:用户名 conard
,那么作用域为 @conard
,发布的包可以是@conard/react
。
name
是一个包的唯一标识,不得和其他包名重复,我们可以执行 npm view packageName
查看包是否被占用,并可以查看它的一些基本信息:
若包名称从未被使用过,则会抛出 404
错误:
另外,你还可以去 https://www.npmjs.com/
查询更多更详细的包信息。
{
"description": "An enterprise-class UI design language and React components implementation",
"keywords": [
"ant",
"component",
"components",
"design",
"framework",
"frontend",
"react",
"react-component",
"ui"
]
}
description
用于添加模块的的描述信息,方便别人了解你的模块。
keywords
用于给你的模块添加关键字。
当然,他们的还有一个非常重要的作用,就是利于模块检索。当你使用 npm search
检索模块时,会到description
和 keywords
中进行匹配。写好 description
和 keywords
有利于你的模块获得更多更精准的曝光:
描述开发人员的字段有两个:author
和 contributors
, author
指包的主要作者,一个 author
对应一个人。 contributors
指贡献者信息,一个 contributors
对应多个贡献者,值为数组,对人的描述可以是一个字符串,也可以是下面的结构:
{
"name" : "ConardLi",
"email" : "[email protected]",
"url" : "https://github.com/ConardLi"
}
{
"homepage": "http://ant.design/",
"bugs": {
"url": "https://github.com/ant-design/ant-design/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/ant-design/ant-design"
},
}
homepage
用于指定该模块的主页。
repository
用于指定模块的代码仓库。
bugs
指定一个地址或者一个邮箱,对你的模块存在疑问的人可以到这里提出问题。
我们的项目可能依赖一个或多个外部依赖包,根据依赖包的不同用途,我们将他们配置在下面几个属性下:dependencies、devDependencies、peerDependencies、bundledDependencies、optionalDependencies
。
在介绍几种依赖配置之前,首先我们来看一下依赖的配置规则,你看到的依赖包配置可能是下面这样的:
"dependencies": {
"antd": "ant-design/ant-design#4.0.0-alpha.8",
"axios": "^1.2.0",
"test-js": "file:../test",
"test2-js": "http://cdn.com/test2-js.tar.gz",
"core-js": "^1.1.5",
}
依赖配置遵循下面几种配置规则:
依赖包名称:VERSION
VERSION
是一个遵循SemVer
规范的版本号配置,npm install
时将到npm服务器下载符合指定版本范围的包。依赖包名称:DWONLOAD_URL
DWONLOAD_URL
是一个可下载的tarball
压缩包地址,模块安装时会将这个.tar
下载并安装到本地。依赖包名称:LOCAL_PATH
LOCAL_PATH
是一个本地的依赖包路径,例如 file:../pacakges/pkgName
。适用于你在本地测试一个npm
包,不应该将这种方法应用于线上。依赖包名称:GITHUB_URL
GITHUB_URL
即 github
的 username/modulename
的写法,例如:ant-design/ant-design
,你还可以在后面指定 tag
和 commit id
。依赖包名称:GIT_URL
GIT_URL
即我们平时clone代码库的 git url
,其遵循以下形式:<protocol>://[<user>[:<password>]@]<hostname>[:<port>][:][/]<path>[#<commit-ish> | #semver:<semver>]
其中 protocal
可以是以下几种形式:
git://github.com/user/project.git#commit-ish
git+ssh://user@hostname:project.git#commit-ish
git+ssh://user@hostname/project.git#commit-ish
git+http://user@hostname/project/blah.git#commit-ish
git+https://user@hostname/project/blah.git#commit-ish
dependencies
指定了项目运行所依赖的模块,开发环境和生产环境的依赖模块都可以配置到这里,例如
"dependencies": {
"lodash": "^4.17.13",
"moment": "^2.24.0",
}
有一些包有可能你只是在开发环境中用到,例如你用于检测代码规范的 eslint
,用于进行测试的 jest
,用户使用你的包时即使不安装这些依赖也可以正常运行,反而安装他们会耗费更多的时间和资源,所以你可以把这些依赖添加到 devDependencies
中,这些依赖照样会在你本地进行 npm install
时被安装和管理,但是不会被安装到生产环境:
"devDependencies": {
"jest": "^24.3.1",
"eslint": "^6.1.0",
}
peerDependencies
用于指定你正在开发的模块所依赖的版本以及用户安装的依赖包版本的兼容性。
上面的说法可能有点太抽象,我们直接拿 ant-design
来举个例子,ant-design
的 package.json
中有如下配置:
"peerDependencies": {
"react": ">=16.0.0",
"react-dom": ">=16.0.0"
}
当你正在开发一个系统,使用了 ant-design
,所以也肯定需要依赖 React
。同时, ant-design
也是需要依赖 React
的,它要保持稳定运行所需要的 React
版本是16.0.0
,而你开发时依赖的 React
版本是 15.x
:
这时,ant-design
要使用 React
,并将其引入:
import * as React from 'react';
import