前端开发工具 - npm
Posted 百果科技研发团队
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端开发工具 - npm相关的知识,希望对你有一定的参考价值。
前端开发工具 - npm
什么是 npm
npm 是 Node.js 官方提供的包管理工具,他已经成了 Node.js 包的标准发布平台,用于 Node.js 包的发布、传播、依赖控制。npm 提供了命令行工具,使你可以方便地下载、安装、升级、删除包,也可以让你作为开发者发布并维护包。
package.json 文件
package.json 应该是前端应用里最重要的一个文件了,它管理着应用所有的基本信息,比如名称,版本,作者等等。更重要的是它记录了应用中所有的依赖。你也可以自定义 npm 执行脚本,这个后面讲。npm 提供了一个简单的命令 npm init 来创建 package.json 文件。
1. 管理应用信息
2. 记录了应用依赖项
3. 创建 npm scripts
4. npm init
npm init
在命令行输入 npm init,首先会要求回答一系列的问题。括号里是默认的答案,版本号后面会详细讲,entry point 这里规定主要的 js 文件,在引用依赖的时候就是根据依赖包里 package.json 的 entry point 来指定入口的。
确认以后就可以看到目录里多了一个 package.json 文件,里面是刚刚输入的内容。我先删了这个文件。如果我们想跳过这些问题的话,可以使用
npm init -y / npm init --yes 命令
如果想要修改 init 的默认项的话,可以通过 npm config set/ npm set 命令
实现 npm config set init-author-name "gaolg" npm set init-license "MIT" 删除之前的设置对应的命令
npm config delete
npm install/i lodash --save/-S npm install lodash 会下载相应的依赖并将其加入到 package.json 的 dependencies 字段里。或者在 npm5 版本以后即使不加标识也会安装依赖并写入 package.json npm install
查询 package.json 文件中记录的依赖并安装 npm install webpack --save-dev/-D 同时我们观察 node_modules 目录,会发现不止安装了我们需要的依赖包,这是因为我们安装的依赖,比如 css-loader,里面还依赖了其他的模块,npm install 会同时安装这些模块。
semver
npm 依赖管理的一个重要特性是采用了语义化版本 (semver) 规范,作为依赖版本管理方案。semver 约定一个包的版本号必须包含 3 个数字,格式必须为 MAJOR.MINOR.PATCH。
意为:主版本号.小版本号.修订版本号。
MAJOR 对应大的版本号迭代,大版本的升级很可能意味着与低版本不兼容的 API 或者用法,是一次颠覆性的升级(想想 webpack 3 -> 4)。 MINOR 对应小版本迭代,发生兼容旧版API的修改或功能更新时,更新 MINOR 版本号 PATCH 对应修订版本号,一般用于修复 bug 或者很细微的变更,也需要保持向前兼容。
常用的规则示例如下表:
range |
含义 |
例子 |
||
^2.2.1 |
指定 MAJOR.MINOR 版本号下,所有更新的版本 |
匹配 2.2.3, 2.3.0; 不匹配 1.0.3, 3.0.1 |
||
~2.2.1 |
指定 MAJOR.MINOR 版本号下,所有更新的版本 |
匹配 2.2.3, 2.2.9 ; 不匹配 2.3.0, 2.4.5 |
||
>=2.1 |
版本号大于或等于 2.1.0 |
匹配 2.1.2, 3.1 |
||
<=2.2 |
版本号小于或等于 2.2 |
匹配 1.0.0, 2.2.1, 2.2.11 |
||
1.0.0 - 2.0.0 |
版本号从 1.0.0 (含) 到 2.0.0 (含) |
匹配 1.0.0, 1.3.4, 2.0.0 |
在常规仅包含数字的版本号之外,semver 还允许在 MAJOR.MINOR.PATCH 后追加 - 后跟点号分隔的标签,作为预发布版本标签 - Prerelese Tags,通常被视为不稳定、不建议生产使用的版本。
例如:
1.0.0-alpha 1.0.0-beta.1 1.0.0-rc.3
package-lock.json
从 npm 5.x 开始,在执行 npm i 之后,会在根目录额外生成一个 package-lock.json,用以记录当前状态下实际安装的各个npm package的具体来源和版本号。
"5.0.3",
"~5.0.3",
"^5.0.3"
“5.0.3” 表示安装指定的 5.0.3 版本,“~5.0.3” 表示安装 5.0.X 中最新的版本,“^5.0.3” 表示安装 5.X.X 中最新的版本。一般来说,npm 会安装最新的版本的依赖,并且在版本号前面加上^符号,比如 ^1.2.12。这表示,至少要安装 1.2.12 的版本,但更高的版本也可以,只要主版本号也为 1 就行。
假设我们创建了一个新项目,它将使用 express。在运行 npm init 之后,在撰写本项目时,最新的 express 版本是 4.15.4。(默认情况下,npm 将安装最新版本)
因此在 package.json中,"express":"^ 4.15.4" 被添加作为依赖项。 假设明天,express 的维护者会发布一个 bug 修复,所以最新版本变成了 4.15.5。 然后,如果有人想要为我的项目做贡献,他们会克隆它,然后运行 npm install, 因为 4.15.5 是一个更高版本的主要版本,这是为他们安装的。 我们都有 express 依赖,但我们有两个不同的版本。理论上,它们应该还是兼容的,但是也许这个 bug 会影响我们正在使用的功能,而我们的应用程序在使用 Express 版本 4.15.4 与 4.15.5 进行比较时会产生不同的结果.
package-lock.json 诞生的目的是为了防止出现我们上述的情况。同一个 package.json 却产生了不同的运行结果。package-lock.json 在 npm 5 时添加进来,所以如果你使用 5 以上的版本,你就会看到这个文件,除非你手动禁用掉它。
格式
"express": {
"version": "4.15.4",
"resolved": "https://registry.npmjs.org/express/-/express-4.15.4.tgz",
"integrity": "sha1-Ay4iU0ic+PzgJma+yj0R7XotrtE=",
"requires": {
"accepts": "1.3.3",
"array-flatten": "1.1.1",
"content-disposition": "0.5.2",
"content-type": "1.0.2",
"cookie": "0.3.1",
"cookie-signature": "1.0.6",
"debug": "2.6.8",
"depd": "1.1.1",
"encodeurl": "1.0.1",
"escape-html": "1.0.3",
"etag": "1.8.0",
"finalhandler": "1.0.4",
"fresh": "0.5.0",
"merge-descriptors": "1.0.1",
"methods": "1.1.2",
"on-finished": "2.3.0",
"parseurl": "1.3.1",
"path-to-regexp": "0.1.7",
"proxy-addr": "1.1.5",
"qs": "6.5.0",
"range-parser": "1.2.0",
"send": "0.15.4",
"serve-static": "1.12.4",
"setprototypeof": "1.0.3",
"statuses": "1.3.1",
"type-is": "1.6.15",
"utils-merge": "1.0.0",
"vary": "1.1.1"
}
}
它存在的意义主要有 4 点:
1. 在团队开发中,确保每个团队成员安装的依赖版本是一致的。否则因为依赖版本不一致导致的效果差异,一般很难查出来。
2. 通常 node_modules 目录都不会提交到代码库,因此要回溯到某一天的状态是不可能的。但现在 node_modules 目录和 package.json 以及 package-lock.json 是一一对应的。所以如果开发者想回退到之前某一天的目录状态,只要把这两个文件回退到那一天的状态,再 npm i 就行了。
3. 因为 package-lock.json 已经足以描述 node_modules 的大概信息(尤其是深层嵌套依赖),所以通过这个文件就可以查阅某个依赖包是被谁依赖进来的,而不用去翻 node_modules 目录(事实上现在目录结构打平而非嵌套,翻也翻不出来了)
4. 在安装过程中,npm 内部会检查 node_modules 目录中已有的依赖包,并和 package-lock.json 进行比较。如果重复,则跳过安装,能大大优化安装时间。
Yarn 是什么
Yarn是由Facebook、Google、Exponent 和 Tilde 联合推出了一个新的 JS 包管理工具 ,正如官方文档中写的,Yarn 是为了弥补 npm 的一些缺陷而出现的。
yarn 的推出主要是针对 npm 早期版本的很多问题:
1. npm install 的时候巨慢。特别是新的项目拉下来要等半天,删除node_modules,重新 install 的时候依旧如此。
2. 同一个项目,安装的时候无法保持一致性。
Yarn 的特点
1. 版本锁定这个在 package-lock.json 已经讨论过了,不再赘述。 在这个功能点上,两者都已具备。
2. 多个包的管理 (monorepositories) 一个包在 npm 中可以被称为 repositories。通常我们发布某个功能,其实就是发布一个包,由它提供各种 API 来提供功能。但随着功能越来越复杂以及按需加载,把所有东西全部放到一个包中发布已经不够优秀,因此出现了多个包管理的需求。 通常一个类库会把自己的功能分拆为核心部分和其他部分,然后每个部分是一个 npm repositories,可以单独发布。而使用者通常在使用核心之后,可以自己选择要使用哪些额外的部分。这种方式比较常见的如 babel 和它的插件,express 和它的中间件等。 作为一个多个包的项目的开发者/维护者,安装依赖和发布都会是一件很麻烦的事情。因为 npm 只认根目录的 package.json,那么就必须进入每个包进行 npm install。而发布时,也必须逐个修改每个包的版本号,并到每个目录中进行 npm publish。 为了解决这个问题,社区一个叫做 lerna 的库通过增加 lerna.json 来帮助我们管理所有的包。而在 yarn 这边,引入了一个叫做工作区(workspace)的概念。因此这点上来说,应该是 yarn 胜出了,不过 npm 配合 lerna 也能够实现这个需求。
3. 安装速度 npm 被诟病最多的问题之一就是其安装速度。有些依赖很多的项目,安装 npm 需要耗费 5-10 分钟甚至更久。造成这个问题的本质是 npm 采用串行的安装方式,一个装完再装下一个。针对这一点,yarn 改为并行安装,因此本质上提升了安装速度。
4. 离线可用 yarn 默认支持离线安装,即安装过一次的包,会在电脑中保留一份(缓存位置可以通过 yarn config set yarn-offline-mirror 进行指定)。之后再次安装,直接复制过来就可以。npm 早先是全部通过网络请求的(为了保持其时效性),但后期也借鉴了 yarn 创建了缓存。从 npm 5.x 开始我们可以使用 npm install xxx --prefer-offline 来优先使用缓存(意思是缓存没有再发送网络请求),或者 npm install xxx --offline 来完全使用缓存(意思是缓存没有就安装失败)。
5. 控制台信息常年使用 npm 的同学知道,安装完依赖后,npm 会列出一颗依赖树。这颗树通常会很长很复杂,我们不会过多关注。因此 yarn 精简了这部分信息,直接输出安装结果。这样万一安装过程中有报错日志也不至于被刷掉。 不过 npm 5.x 也把这颗树给去掉了。这又是一个互相借鉴提高的例子。
更好的语义化:yarn 改变了一些 npm 命令的名称,比如 yarn add/remove,感觉上比 npm 原本的 install/uninstall 要更清晰。
npm |
yarn |
||
npm install |
yarn |
||
npm install react --save |
yarn add react |
||
npm uninstall react --save |
yarn remove react |
||
npm install react --save-dev |
yarn add react --dev |
||
npm update --save |
yarn upgrade |
以上是关于前端开发工具 - npm的主要内容,如果未能解决你的问题,请参考以下文章