本文介绍如何发布一个包到 npmjs.org,包括创建、发布、撤回、更新、使用分支等等,以及其中 包含的一些小技巧。
 0. 创建
 创建一个包很简单,就是手动或者用 npm init 命令直接生成一个 package.json 文件,一个 包就算是创建出来了。剩下的就是给它添加内容而已了。
  如果使用 npm init 命令配合 -y 或者 --yes 参数,可以不使用命令行交互模式,而 快速地创建一个 package.json 文件。
 
 npm init -y 
 比如我这里创建出来的是:
  name 字段默认是当前所在的目录名称。
 
 {   "name": "test",   "version": "0.1.0",   "description": "",   "main": "index.js",   "scripts": {     "test": "echo \"Error: no test specified\" && exit 1"   },   "keywords": [],   "author": "Angus.Fenying <i.am.x.fenying@gmail.com> (https://fenying.net/)",   "license": "Apache-2.0" } 
  什么,你说你创建出来是下面这样的?有些字段的初始值和我的不一样?
 {   "name": "test",   "version": "1.0.0",   "description": "",   "main": "index.js",   "scripts": {     "test": "echo \"Error: no test specified\" && exit 1"   },   "keywords": [],   "author": "",   "license": "ISC" } 
 别急,那是因为你没有设置 NPM 的一些默认配置。通过下面三条命令,可以设置创建新的 NPM 包时使用的默认属性。
 npm config set init-author-name "Angus.Fenying"             # 你的名称 npm config set init-author-email "i.am.x.fenying@gmail.com" # 你的邮箱 npm config set init-author-url "https://fenying.net"        # 你的个人网页 npm config set init-license "Apache-2.0"                    # 开源授权协议名 npm config set init-version "0.1.0"                         # 版本号 
 
 1. 准备
 现在你可以为 package.json 添加内容了,比如修改如下:
 {   "name": "npm-tutorial-test-1",   "version": "0.1.0",   "description": "This is a test package for my NPM tutorial.",   "main": "index.js",   "scripts": {     "test": "echo hello"   },   "keywords": [       "test"   ],   "author": "NPM Learner <me@sample.com> (https://sample.com/)",   "license": "MIT" } 
 然后添加一个 README.md 文件,内容如下:
 # NPM Tutorial Test 1  This is a test package for my NPM tutorial.  ## License  This package is published under [MIT license](./LICENSE). 
 添加你的 LICENSE 文件(开源协议),以及一个 index.js 文件。
 现在,一个最基本的包就是准备好了,等待发布了。
 2. 发布
 既然包已经准备好了,那么就可以发布了。
 2.0. 修正下载源
 如果你曾经为了加速 NPM 下载速度而修改了它的下载源,那么请改回去,不然是无法发布的。
 检查方式:
 npm config get registry 
 NPM 的官方源是 https://registry.npmjs.org/,如果你看到控制台打印是这个,那么就没 问题了。而如果不是,那么请使用下面的命令修改回去:
 npm config set registry https://registry.npmjs.org/ 
 2.1. 创建并登录 npmjs.org 账户
 如果你没有 npmjs.org 账户,那么先要创建一个,方法很简单:
 npm adduser 
 根据提示创建即可。
  记得验证邮箱,否则将无法发布包。
 
 如果已经有 npmjs.org 账户了,请直接登录:
 npm login 
 3. 真正的开始
 上面的教程只是一个最简单的 DEMO,远远不能满足我们的发布需要,下面以一个需要编译的 TypeScript 包为例,看看如何发布和管理。
 3.1. 合理的 package.json
 先来看一个 package.json 的内容:
 {   "name": "full-sample",   "version": "0.1.0",   "description": "A sample to learn NPM.",   "main": "./dist/index.js",   "scripts": {     "prepare": "npm run rebuild",     "build": "tsc -p .",     "rebuild": "npm run clean && npm run lint && npm run build",     "test": "echo See directory sources/tests",     "clean": "rm -rf dist",     "lint": "tslint --project tslint.json"   },   "keywords": [     "npm",     "sample"   ],   "author": "NPM Learner <me@sample.com> (https://sample.com/)",   "license": "Apache-2.0",   "repository": {     "type": "git",     "url": "git+https://github.com/learn-npm/full-sample.git"   },   "bugs": {     "url": "https://github.com/learn-npm/full-sample/issues"   },   "homepage": "https://github.com/learn-npm/full-sample#readme",   "types": "./dist/index.d.ts",   "typings": "./dist/index.d.ts",   "dependencies": {     "sequelize": "^4.24.0"   },   "devDependencies": {     "@types/node": "^8.0.51",     "@types/sequelize": "^4.0.79",     "typescript": "^2.6.1"   },   "engines": {     "node": ">=8.0.0"   } } 
  假定项目的 TypeScript 源代码都在 sources 目录,编译结果都在 dist 目录。
 
 上面与 DEMO 有什么区别呢?下面逐个字段解释:
  -  homepage
 指定项目的主页地址,如果没有一般可以使用项目的 GitHub 地址。 
-  bugs.url
 指定项目的 Bug 反馈地址,一般可以用项目的 GitHub Issue 地址。 
-  repository.url和repository.type
 指定项目的源码仓库地址,可以指定是 git/cvs/svn。 
-  main
 指定 Node.js 中 require("moduel-name") 导入的默认文件。 
-  keywords
 指定项目的关键词,合理设置有利于让他人发现你的项目。 
-  engines
 设置项目对引擎的版本要求,比如 node、electron、vscode 等。 
-  types和typings
 设置项目内置的 TypeScript 模块声明文件入口文件。 
3.2. scripts 字段
 scripts 字段作为单独一节解释,因为它是用于构建控制和发布控制的工具。
  -  scripts.build
 这个允许使用 npm run build命令直接编译 TS 代码。
 
-  scripts.lint
 这个允许使用 npm run lint命令调用 TSLinter 对代码进行格式检查。
 
-  scripts.clean
 这个允许使用 npm run clean命令清理编译结果。
 
-  scripts.rebuild
 这个允许使用 npm run rebuild命令清理编译结果然后重新生成。
 
-  scripts.prepare
 这个不是给我们用的,而是 NPM 提供的钩子,这个命令会在执行 npm publish的时候 被调用。因此可以用这个钩子进行发布前构建。
 
3.3. Git 设置
 Git 应当使用 .gitignore 文件忽略那些编译结果,以及 NPM 依赖的包文件:
 /node_modules/ /dist/ *.log 
 3.4. NPM 包文件设置
 NPM 打包发布的时候,会默认把当前目录下所有文件打包。但是 Git 仓库中,有些东西是不需要 发布到 NPM 的,因此我们需要使用一个文件 .npmignore 来忽略这些文件,常用配置如下:
 /.git/ /.vscode/ /docs/ /node_modules/ .gitignore .npmignore tslint.json tsconfig.json *.log 
 这些文件都不是发布需要的内容,因此可以忽略。
 3.5. 配置 tsconfig.json
 前面说了,假定 TypeScript 的代码在 sources 目录下,编译的输出目录则为 dist。那么需要 在 tsconfig.json 里面通过 rootDir 和 outDir 选项指定。
 其次,为了让其它 TypeScript 程序能正常使用你的包,你还应该设置 declaration 字段为 true,使之自动生成 *.d.ts 文件。此处我们假定模块的入口是 index.js ,因此你必须 实现一个 index.ts 文件,作为模块的入口。
 另外,如果要实现 TypeScript 源码调试,则需要开启 sourceMap 选项,以生成源码映射 文件。
 3.6. 使用 tslint.json
 现在,就可以愉快地编写代码了吗?不不不,为了规范代码,我们还需要配置下 TSLinter。通过 下面的命令初始化一个 tslint.json 文件。
 npm install tslint -g tslint --init 
 TS Linter 的规则非常多,而且默认规则限制非常严格,可以适当根据提示解除一些限制。比如 作者就采用了如下配置,仅供参考:
 {     "defaultSeverity": "error",     "extends": [         "tslint:recommended"     ],     "jsRules": {     },     "rules": {         "interface-name": false,         "trailing-comma": false,         "max-classes-per-file": false,         "ordered-imports": false,         "variable-name": false,         "prefer-const": false,         "member-ordering": false,         "no-bitwise": false,         "forin": false,         "object-literal-sort-keys": false,         "one-line": [false],         "object-literal-key-quotes": [false],         "no-string-literal": false,         "no-angle-bracket-type-assertion": false,         "only-arrow-functions": false,         "no-namespace": false,         "no-internal-module": false,         "unified-signatures": false,         "ban-types": false,         "no-conditional-assignment": false,         "radix": false     },     "rulesDirectory": [] } 
  如果想在 Visual Studio Code 里面实现 TS Linter 智能提示,则还需要安装 VSCode 的 TSLint 扩展。
 
 现在,可以尽情地编写代码了。
 4. 维护
 4.1. 版本号维护
 维护一个包,肯定是要进行包的版本升级的。如何进行呢?手动修改 package.json 的 version 字段是一个办法,但是显得有点 low。可以使用下面的命令:
 npm version v0.1.0      # 版本号变成 0.1.0,即显式设置版本号。 npm version patch       # 版本号从 0.1.0 变成 0.1.1,即修订版本号加一。 npm version minor       # 版本号从 0.1.1 变成 0.2.0,即子版本号加一。 npm version major       # 版本号从 0.2.0 变成 1.0.0,即主版本号加一。 
 但是,除此之外,还有四条命令,用于创建“预发布版本”,也就是非稳定版本。
 npm version v1.2.3  # 版本号从 1.2.3 变成 1.2.4-0,就是 1.2.4 版本的第一个预发布版本。 npm version prepatch  # 版本号从 1.2.4-0 变成 1.3.0-0,就是 1.3.0 版本的第一个预发布版本。 npm version preminor  # 版本号从 1.2.3 变成 2.0.0-0,就是 2.0.0 版本的第一个预发布版本。 npm version premajor  # 版本号从 2.0.0-0 变成 2.0.0-1,就是使预发布版本号加一。 npm version prerelease 
  注意: version 命令默认会给你的 git 仓库自动 commit 一把,并打一个 tag。如果不想它动你的 git 仓库,你应该使用 --no-git-tag-version 参数,例如:
 npm --no-git-tag-version version patch 
 如果你想一劳永逸,那么可以使用如下 NPM 设置彻底禁止它:
 npm config set git-tag-version false  # 不要自动打 tag npm config set commit-hooks false     # 不要自动 commit 
 
 4.2. 使用标签
 以 TypeScript 为例,通过 npm info typescript 可以看到 dist-tags 字段有着五个 值,分别是 latest, beta, rc, next, insiders,这些都是 dist-tag,可以 称之为标签——你可以把它理解为 git 里面的分支。
 有什么用呢?其实,我们平时用 npm install xxxxxx 的时候,是使用了一个潜在的选项 tag = latest,可以通过 npm config list -l | grep tag 看到。
 因此实际上是执行了 npm install xxxxxx@latest。也就是安装了 latest 这个标签 对应的最新版本。
 不同的标签可以有不同的版本,这就方便我们发表非稳定版本到 npm 上,与稳定版本分开。
  默认是发布到 latest 标签下的。
 
 例如 npm publish --tag dev 就可以发布一个版本到 dev 标签下。
 4.3. 使用前缀
 如果你使用过 AngularJS 或者 TypeScript,那么肯定知道有一些包的名字是这样的:
  - @types/node
- @types/jquery
- @angular/core
这里面的 @types/ 和 @angular/ 叫做包前缀(scope)。
  作者起初以为使用包前缀也是收费的,后来仔细阅读了文档才发现公开的包可以免费使用 包前缀。
 
 那我们怎么使用呢?很简单,首先在 package.json 里面把 name 字段加上一个前缀。
  前缀必须是你 NPM 账户的用户名,比如你注册了一个用户名为 abc 的账户,则你只能使用 @abc/ 为你的包前缀。
 
 举个例子,将你的包名设置为 @abc/test。
  如果你要初始化一个带包前缀的包,则可以使用下面的命令。
 npm init --scope=abc # 当然你还可以加上个 `-y` 快速创建。 
 或者你想每次都使用 @abc/ 包前缀?加个设置即可:
 # 这样每次初始化新的 package.json,都将自动应用 @abc/ 包前缀。 npm config set scope abc 
 
 现在,可以发布你的包到 npmjs.org 了。哦不,别忘了一点:
  官方文档表示:所有带前缀的包,在发布的时候,默认都是发布为私有包。
 
 这意味着你不能就这么发布,因为你(可能)不是付费用户,不能发布私有的包。那怎么办呢?别 担心,npm publish 命令还有一个参数 --access ,通过这个参数可以指定发布的是公共包 还是私有包。因此,只要用下面的命令就可以发布一个公共的,带包前缀的包了:
 npm publish --access=public 
 (完)