npm总结(一)

本文参考:


前言

随着前端工程的发展,npm已然成为每个前端开发者的必备技能,然而大多数人对它的使用也只是停留在使用npm安装一些依赖包而已。作为全世界最大规模的包管理器,每周大约有30亿次的下载量,npm的功能远不止安装依赖这么简单,本文的目的就是介绍npm更多的功能。

tips:本文 demo 仓库:npm-demo

1. 安装 npm 和管理 npm 版本

npm是NodeJS自带的一个包管理工具,在 NodeJS官网 安装NodeJS后即可使用npm

  • 查看npm版本
$ npm -v
  • 更新npm版本
$ npm install npm@latest -g

2. npm init

该命令的原理是调用脚本(init-package-json),输出一个初始化的package.json文件,package.json中记录了项目中的依赖包的信息(如名称、版本等)。

npm init
package.json

执行npm init每次都会输入如上信息,可以使用npm init --yes快速创建一个带有默认信息的package.json的文件。

3. 安装依赖包

安装依赖包是npm的核心功能,输入npm installnpm会自动从package.json文件中寻找dependenciesdevDependencies下的依赖包,并安装到项目的node-modules文件夹下。

3.1 关于 package

当手动安装一个依赖包时,使用npm install <package>命令即可安装,参数package即是要安装的依赖包名,一般npm会在 默认源仓库 中去查找对应的包名。然而,package不光是一个包名,还有更多的定义方式,参见:Understanding Packages and Modules,以下是package定义的规则:

  1. 包含package.json文件描述该程序的文件夹
custom local package
custom local package 安装
  1. 满足规则(1)的gzip压缩文件
gzip 压缩文件
  1. 可以下载到规则(2)资源的url链接
url 链接
  1. 格式为<name>@<version>,一般是已发布在npm源仓库上的可访问 url,且该url满足规则(3)
<name>@<version>
  1. 格式为<name>@<tag>,通过tag标记获取到version,且满足规则(4)
<name>@<tag>
  1. 格式为<name>,默认添加latest标记获取最新发布版,且满足规则(5)
<name>
  1. 满足规则(1)的git urlgit url 支持格式
git url

按照以上不同规则安装后的package.json文件如下:

package.json

注意:无论以何种方式安装依赖包,npm install时都会去根据package.json文件中的dependencies字段下载它所依赖的相关包

3.2 本地包应用场景

场景模拟如下所示:

  1. 创建一个公共模块common-package-test,存放项目中一些公共的配置或方法
公共模块
  1. src目录下创建一个轮播图列表组件
轮播图组件
  1. 利用webpack打包该文件,并进行测试
webpack 打包
  1. 打开index.html,查看控制台,正常输出
控制台输出

通过以上场景模拟,内容可以正常输出,但是问题在于引用路径一直往上层寻找,这种引用很不利于项目的维护。而且公共模块也确实需要单独分离出来给其他模块引用,为了更优雅的引用,可以利用npm本地包将公共模块封装到node_modules中。

解决方案:

  1. 在公共模块common-package-test下创建一个package.json文件
公共模块 package.json
  1. 利用npm安装本地包
安装本地包
  1. 在轮播图组件重新引入common-package-test模块
引入 common-package-test 模块
  1. 通过 webpack 打包进行测试
控制台输出

3.3 远程 git 仓库包应用场景

场景:使用一个npm包时发现它有bug,也找出了它的问题,并直接在node_modules中修复了它,这样并没有用。因为在.gitignore文件一般会忽略提交node_modules,即node_modules不在版本控制内,即使修复了它,下次下载依赖是还是会覆盖修复。

解决:先在git仓库中fork要修复的npm包,然后在自己的仓库中修复该问题,最后在package.json中引用自己的git url即可解决问题。

4. 工作原理

  • npm2采用的是递归安装的方法,当项目较复杂时,目录结构也会很深,会出现超出windows系统中路径超过260字符的错误;部分相同的依赖包也会被重复安装,造成大量冗余。
  • npm3采用扁平结构优化解决了以上问题,但也导致了npm依赖树不能和文件结构所对应了,可以通过npm ls来查看模块间的依赖关系。
  • npm5依然采用扁平结构,还引入了package-lock.json文件,它可以锁定依赖的安装结构和版本等信息。
package-lock.json

package-lock.json文件主要由versionresolvedintegrityrequiresdependencies几个字段组成。

  • version:包的准确版本号
  • resolved:安装源
  • integrity:完整哈希
  • requires:除最外层的requires属性为true, 其他的requires属性都对应着该依赖包中的package.json里记录的自己的依赖项
  • dependencies:与node_modules文件结构有着一一对应的关系。

使用package-lock.json的好处在于可以锁定安装的依赖包,在另外一台设备上下载依赖会按照锁定版本去下载,这样就不会因为依赖包版本不同而导致一些意外的问题。

5. 依赖包版本管理

5.1 semver

  1. npm采用语义化版本 (semver) 规范进行版本管理。

版本格式:主版本号.次版本号.修订号,版本号递增规则如下:

  • 主版本号:做了不兼容的 API 修改
  • 次版本号:做了向下兼容的功能性新增,
  • 修订号:做了向下兼容的问题修正。
  1. npm提供了网站 npm semver calculator ,可以方便地计算semver的匹配范围。下面列举一些规则示例:
  • ^4.1.3:指定的主版本号下,所有更新的版本
  • ~4.1.3:指定的次版本号下,所有更新的版本
  • >4.1.3:版本号大于4.1.3
  • <=4.3:版本号小于等于4.3
  • 3.1.0 - 4.2.1:版本号在3.1.04.2.1之间
  • >=3.3.1 <3.8.0:与逻辑,版本号大于等于3.3.1且小于3.8.0
  • >4.3.1 || <=2.3.1:或逻辑,版本号大于4.3.1或小于等于2.3.1
  • *:所有主版本
  • 22.*2.x:主版本号为2的所有版本
  • 3.33.3.*3.3.x:版本号为3.3开头的所有版本
  • 5.0.0-alpha:预发布版本
  • 7.0.0-beta.3:预发布版本
  • 1.0.0-rc.3:预发布版本

5.2 依赖包管理建议

  1. 使用npm5.2以上的版本,保留package-lock.json文件
  2. 不要手动修改package-lock.json
  3. 升级小版本依赖包:npm update <package>
  4. 升级大版本依赖包: npm install <package>@<version>
  5. 降级依赖包:npm install <package>@<version>
  6. 删除依赖包:npm uninstall <package>
  7. 当提交了package.jsonpackage-lock.json的更新后,应及时拉取更新,并重新npm install重新安装更新后的依赖

6. npm 脚本

6.1 npm scripts

  1. 使用npm scripts可以在package.json文件中自定义脚本
{
  "script": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}

以上代码片段是create-react-app脚手架生成的React项目中的scripts,可以使用npm run命令来执行上面的scripts,执行npm run build就等同于执行对应的npm脚本:react-scripts build

  1. npm脚本原理

当执行npm run命令时,会自动新建一个shell去执行里面的脚本,shell会将./node_modules./bin目录添加到PATH变量中。也就是说,如果./node_modules./.bin目录中的脚本,可以直接调用脚本名,不用去写完整的脚本路径或是全局安装脚本了。

  1. 简写
  • npm startnpm run start的简写
  • npm stopnpm run stop的简写
  • npm testnpm run test的简写
  • npm restartnpm run stop && npm run restart && npm run start的简写
  1. 变量

npm脚本可以通过环境变量process.env的方式获取到运行时的相关变量:

{
  "name": "webpack",
  "version": "3.8.1",
  "repository": {
    "type": "git",
    "url": "https://github.com/webpack/webpack.git"
  }
}

上面的代码片段是webpackpackage.json文件中的部分内容,可以通过process.env对象获取其中的变量。
例如:process.env.npm_package_name返回webpackprocess.env.npm_package_version返回3.8.1process.env.npm_package_repository_type返回git

6.2 npx

  1. 先举个例子,在npm5.2版本以前,如果只是在项目中安装了webpack,打包的时候就需要用./node_modules./.bin/webpack来调用webpack命令来进行打包。调用命令时每次都要输入这么长的路径,会觉得很麻烦,所以一般会在全局安装webpackwebpack-cli,然后直接用webpack命令来打包,这是因为在webpackpackage.json文件中有对bin字段的定义:
"bin": {
  "webpack": "./bin/webpack.js"
}

但是全局安装的webpack命令可能会与项目使用的weboack命令版本不同,也会导致不能成功构建。上一节讲到了npm scripts,这时我们就可以将webpack命令写到npm scripts中,而不需要全局安装了,因为npm run命令能够在执行时把./node_modules/.bin加入到PATH变量中,进而直接调用webpack命令了

npm5.2版本以后,npx很方便地解决了上述问题,直接使用npx webpack就可以去自动寻找项目中安装好的webpack依赖包,然后进行打包

  1. 执行远程npm远的二进制包

npm5.2版本以前,初始化React脚手架项目,需要现在全局安装create-react-app,然后再创建初始化的项目:

npm install -g create-react-app
create-react-app my-app

npm5.2版本后,直接使用npx即可安装并创建初始化项目,这样也就不必全局安装create-react-app了,也不必去检查全局安装的依赖包版本是否过低:

npx create-react-app my-app

6.3 切换不同的Node版本

在以前都是用 nvmn 这样的Node版本管理工具来切换Node版本,而有了npx同样可以在不手动切换Node的前提下,使用不同的Node版本环境:

npx 切换 Node 版本

7. npm 配置

7.1 npm-config

通过npm config ls -l可以查看npm的所有配置,详细的配置说明可在官方文档查看:config | npm Documentation

npm comfig

修改配置命令:npm config set <key> <value>
修改npm仓库源为淘宝镜像源:npm config set registry https://registry.npmjs.org/

7.2 .npmrc文件

上面的修改npm配置是借助命令行来完成的,除了命令还可以通过.npmrc文件来修改配置。

npm读取config配置的优先级:

  • 工程目录下的.npmrc文件(/path/to/my/project/.npmrc
  • 用户配置文件(~/.npmrc
  • 全局配置文件($PREFIX/etc/npmrc
  • npm内置的配置文件(/path/to/npm/npmrc

8. 总结

  • 为了统一配置,项目中的npm config添加到.npmrc文件中
  • 统一node运行环境,package.jsonpackage-lock.json文件
  • 合理使用安装依赖包:npm install <package>|<local file>|<git url>
  • 使用npm5.2以上版本
  • 合理使用npm scriptsnpx管理应用相关脚本

npm的一些基础使用和介绍先到此为止,关于更加详细的使用和其他高级用法请看下一篇文章:npm总结(二)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350