🗒️使用 npm
来自官网 https://docs.npmjs.com/
npm 是一个 software registry(软件注册中心)。
npm 有三个组件:
- website:发现 packages,设置 profiles(配置文件),管理 npm 的其它方面 
- command-line interface, CLI, 命令行界面:大多数开发者和 npm 的交互方式 
- registry:一个大型公共 database,关于 JavaScript 软件及其元信息 
npm 可以:
- 管理代码所需要的 packages 
- 下载可以立即使用的独立工具 
- 运行 package 而不用下载它,使用 npx 
- 管理代码及其依赖的多个版本 
- 管理代码的开发权限、创建组织和虚拟团队 
- ... 
1. 入门
1.1 创建 account
创建一个 npm user account,以便在 public registry(公共注册表)上共享和下载 Javascript packages。
- npm login:在网页上注册成功之后,可以使用该命令测试登录下- 此时需要输入 username, password, email address 
- 若启用了 two-factor authentication,则还需要再输入一次性密码 
 
- npm whoami:测试是否登录成功
1.2 安装 npm
使用 CLI 安装 npm。
安装 Node.js 时,会自动安装 npm。
然而考虑到 npm 的发布频率要高于 Node.js,所以建议安装 npm 的最新稳定版本,命令如下:
npm install npm@latest -g  # 最新的稳定版本1.3 故障排除
详见 Getting started / Troubleshooting
2. packages 和 modules
public npm registry(注册表)是一个关于 JavaScript packages(包括软件和元数据)的 database。开发人员可以使用 npm registry 贡献 packages,这样其他人就能在自己的项目中下载和使用这些 packages 了。
npm registry 包含 packages,其中很多 packages 也是 Node modules 或包含 Node modules。
为了解析 package 的 name 和 version,npm 和一个 registry website(注册网站)进行对话,该网站实现了 CommonJS Package Registry 规范以读取 package 的信息。详见 npm CLI / Using npm / Registry:JavaScript Package Registry(注册表)。
2.1 packages
package 就是一个由 package.json 描述的文件或文件夹。package 必须包含 package.json 文件才能被发布到 npm registry(注册表)。
packages 可以是 unscoped(不限定范围的)也可以是 scoped(限定范围的)。scoped packages 可以是 private 也可以是 public。
package formats 可以是以下之一:
- 一个包含代码的文件夹,由 - package.json文件描述
- 包含 (1) 的 gzipped tarball(压缩包) 
- 解析为 (2) 的 URL 
- 使用 (3) 在 registry 上发布的 - <name>@<version>
- 指向 (4) 的 - <name>@<tag>
- 满足 (5) 的 - <name>@latest
- 一个 git url,被 cloned 了之后就是 (1) - git URL 的格式可以是: - git://github.com/user/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
 
- commit-ish可以是任何能作为参数提供给- git checkout的 tag, sha 或 branch。- commit-ish默认是- master
 
npm install
npm install <folder>
npm install <tarball file>
npm install <tarball url>
npm install [<@scope>/]<name>
npm install <alias>@npm:<name>
npm install [<@scope>/]<name>@<tag>
npm install [<@scope>/]<name>@<version>
npm install [<@scope>/]<name>@<version range>
npm install <git remote url>
npm install <githubname>/<githubrepo>[#<commit-ish>]
npm install github:<githubname>/<githubrepo>[#<commit-ish>]
npm install gist:[<githubname>/]<gistID>[#<commit-ish>|#semver:<semver>]
npm install bitbucket:<bitbucketname>/<bitbucketrepo>[#<commit-ish>]
npm install gitlab:<gitlabname>/<gitlabrepo>[#<commit-ish>]# package name
npm
@npmcli/arborist         # @scope
@npmcli/arborist@latest  # @<tag>
npm@6.13.1               # @<version>
npm@^4.0.0
# alias
semver:@npm:@npmcli/semver-with-patch
semver:@npm:semver@7.2.2
semver:@npm:semver@legacy
# folder: local directory
./my-package
/opt/npm/my-package
# tarball
./my-package.tgz
https://registry.npmjs.org/semver/-/semver-1.0.0.tgz
# git urls
https://github.com/npm/cli.git   # full git url
git@github.com:npm/cli.git       # git shorthand
git+ssh://git@github.com/npm/cli#v6.0.0 
github:npm/cli#HEAD              # username/package
npm/cli#c12ea072.2 modules
module 是 node_modules 目录下的任何文件或目录,能通过 Node.js 的 require() 函数加载。
module 必须是以下之一:
- 一个文件夹,它包含 - package.json文件且里面有- main字段
- 一个 JavaScript 文件 
包含 package.json 文件的 modules 也是 packages。
在 Node 程序的上下文中,module 也是从文件加载的内容,比如以下代码,我们也会说变量 req 指向 request module。
var req = require('request')2.3 scope
当注册一个 npm user account 或创建一个组织时,我们将被授予一个与之匹配的 scope。不同 scope 里的两个 package 可以重名。
在 package.json 文件中列出的依赖,scope 名就是 @ 和 / 之间的内容。比如:
- @npm/package-name
- @npmcorp/package-name
npm packages 的可见性取决于它所在的 scope(namespace)以及为它设置的访问级别(private 或 public)。
org
✔️
✔️ 默认
user
✔️
✔️ 默认
unscoped
✔️ 始终
--
相关说明:
- 关于 private packages - private packages 始终是 scoped 
- scoped packages 默认是 private,如果想变 public 则在发布时要传一个命令行标识 
 
- 关于 public packages(任何人都可以下载并使用) - unscoped packages 始终是 public 
- unscoped public packages 存在于 global public registry namespace 
- scoped public packages 属于某个用户或组织。当作为依赖包含在 - package.json里时必须以用户名或组织名开头- @username/package-name
- @org-name/package-name
 
 
2.4 创建 package.json
package.json详见《贡献 package》。
3. 指定依赖项
在 package.json 文件中指定 dependencies 和 devDependencies,当运行 npm install 时 npm 会下载它们。
- dependencies应用程序在 production 环境中需要的 packages
- devDependencies仅在 local development 和 testing 时需要的 packages
# 通过 CLI 添加
npm install <package-name> --save-prod # 默认选项
npm install <package-name> --save-dev4. 版本和 tag
4.1 语义版本
semantic versioning,语义版本控制。
首次发布
New product
从 1.0.0 开始
1.0.0
向后兼容的 bug fixes
Patch release
增加第三位
1.0.1
向后兼容的 new features
Minor release
增加中间数字
并将最后的数字置零
1.1.0
破坏向后兼容的更改
Major release
增加第一个数字
并将中间+最后的数字置零
2.0.0
4.2 分发标签
dist-tags, distribution tags, 分发标签
dist-tags 是对语义版本控制的补充:更易于人类阅读,也能更有效地分发 packages。
由于 dist-tags 和语义版本共享一个命名空间,因此需要避免和现有版本号冲突,所以尽量不要使用以数字或者字母“v”开头的 dist-tags。
npm publish # 默认会打名为 latest 的 dist-tag
npm publish --tag <tag>
npm publish --tag beta
# 给特定 version 添加 dist-tag
npm dist-tag add <package-name>@<version> [<tag>]
npm dist-tag add example-package@1.4.0 stable5. 从 registry 获取 packages
5.1 安装和下载
# locally 安装和下载
npm install <package_name>      # 默认是 locally 安装,默认会使用 'latest' tag
npm install <package_name>@beta # 指定 dist-tag
npm install @scope/package-name
npm install @scope/private-package-name
# globally 安装和下载
npm install -g <package_name>npm install 命令会在当前目录中创建 node_modules 目录(如果尚不存在),并将 package 下载到该目录。如果本地(local)目录没有 package.json 文件,则 npm 会安装最新版本的 package,否则就会安装满足声明的 semantic versioning rule 的最新版本。
如果使用的是 npm 5.2+,推荐使用 npx 来 globally 运行 packages。全局安装 package 是让我们将 package code 作为本地计算机上的一组工具来使用。 Introducing npx: an npm package runner
相关阅读:全局安装时的 EACCES permissions errors
5.2 update
# 看哪些 packages 要更新
npm outdated
npm outdated -g --depth=0
# 更新
npm update                   # 更新 all 本地包
npm update -g                # 更新 all 全局包
npm update -g <package_name> # 更新 single 全局包5.3 uninstall
uninstall 一个 package,npm 会完全删除和它相关的所有东西。
npm uninstall <package_name>
npm uninstall <@scope/package_name>
npm uninstall -g <package_name>
npm uninstall -g <@scope/package_name>6. 依赖的安全漏洞
当使用 npm install 安装 package 时,npm audit 会自动运行。也可以手动运行 npm audit。
npm audit  # npm 6.x.xnpm audit 会生成一份 audit reports(审计报告),里面包含了项目 dependencies 相关的 security vulnerabilities(安全漏洞),能帮我们修复漏洞或进一步排除故障。审计报告包含以下字段:
- severity:漏洞的严重程度 - critical 立即解决 
- high 尽快解决 
- moderate 时间允许地解决 
- low 自己定 
 
- description:关于漏洞的描述 
- package:存在漏洞的包名 
- patched in:漏洞被修复的版本 
- dependency of:存在漏洞的包的依赖 module 
- path:包含漏洞的代码路径 
- more info:关于 security report 的链接 
npm audit 会检查 direct dependencies, devDependencies, bundledDependencies 和 optionalDependencies,但不检查 peerDependencies
7. scripts
npm 如何处理 scripts 字段。
package.json 文件里的 scripts 属性支持多种 built-in scripts 及其 preset life cycle events,也支持任意 scripts。这些脚本可以通过 npm run-script <stage> 或简写的 npm run <stage> 来执行。来自 dependencies 的 scripts 可以通过 npm explore <pkg> -- npm run <stage> 来运行。
7.1 pre 和 post 脚本
名字以 pre 或 post 开头即可。
{
  "scripts": {
    "precompress": "{{ executes BEFORE the `compress` script }}",
    "compress": "{{ run command to compress files }}",
    "postcompress": "{{ executes AFTER `compress` script }}"
  }
}当运行命令 npm run compress 时会执行上面的那三个脚本。
7.2 life cycle 脚本
一些特殊的 life cycle scripts 只在特定的情况下发生。
- prepare
- prepublish
- prepublishOnly
- prepack
- postpack
- dependencies:只要- npm命令导致- node_modules目录发生更改,该脚本就会执行,它运行在更改(changes 以及- package.json和- package-lock.json的文件更新)之后。
7.3 最佳实践
- 不要以 non-zero error code 退出 
- 尽量不要使用 scripts 来做 npm 可以为我们做的事情 - npm 可以做的事情,详见(npm CLI / Configuring npm / package.json) 
 
- 检查 env 以确定把东西放哪 
- 不要在脚本命令前加上 - "sudo"- 如果失败了,要用 root permissions,那就 sudo 有问题的 npm command 
 
- 不要使用 - install
- scripts 从 package folder 的 root 运行,不管当调用 - npm时的 current working directory 在哪里- 如果想让 script 基于某个子目录运行,可以使用 - INIT_CWD环境变量
 
Last updated