如何发布一个 TypeScript 编写的包到 NPM 官方仓库
该文章根据 CC-BY-4.0 协议发表,转载请遵循该协议。
本文地址:https://fenying.net/post/2018/01/16/how-to-publish-typescript-package-to-npmjs/
文章目录
本文介绍如何发布一个包到 npmjs.org,包括创建、发布、撤回、更新、使用分支等等,以及其中 包含的一些小技巧。
0. 创建
创建一个包很简单,就是手动或者用 npm init
命令直接生成一个 package.json 文件,一个
包就算是创建出来了。剩下的就是给它添加内容而已了。
如果使用
npm init
命令配合-y
或者--yes
参数,可以不使用命令行交互模式,而 快速地创建一个 package.json 文件。
1npm init -y
比如我这里创建出来的是:
name 字段默认是当前所在的目录名称。
1{
2 "name": "test",
3 "version": "0.1.0",
4 "description": "",
5 "main": "index.js",
6 "scripts": {
7 "test": "echo \"Error: no test specified\" && exit 1"
8 },
9 "keywords": [],
10 "author": "Angus.Fenying <[email protected]> (https://fenying.net/)",
11 "license": "Apache-2.0"
12}
什么,你说你创建出来是下面这样的?有些字段的初始值和我的不一样?
1{ 2 "name": "test", 3 "version": "1.0.0", 4 "description": "", 5 "main": "index.js", 6 "scripts": { 7 "test": "echo \"Error: no test specified\" && exit 1" 8 }, 9 "keywords": [], 10 "author": "", 11 "license": "ISC" 12}
别急,那是因为你没有设置 NPM 的一些默认配置。通过下面三条命令,可以设置创建新的 NPM 包时使用的默认属性。
1npm config set init-author-name "Angus.Fenying" # 你的名称 2npm config set init-author-email "[email protected]" # 你的邮箱 3npm config set init-author-url "https://fenying.net" # 你的个人网页 4npm config set init-license "Apache-2.0" # 开源授权协议名 5npm config set init-version "0.1.0" # 版本号
1. 准备
现在你可以为 package.json 添加内容了,比如修改如下:
1{
2 "name": "npm-tutorial-test-1",
3 "version": "0.1.0",
4 "description": "This is a test package for my NPM tutorial.",
5 "main": "index.js",
6 "scripts": {
7 "test": "echo hello"
8 },
9 "keywords": [
10 "test"
11 ],
12 "author": "NPM Learner <[email protected]> (https://sample.com/)",
13 "license": "MIT"
14}
然后添加一个 README.md 文件,内容如下:
1# NPM Tutorial Test 1
2
3This is a test package for my NPM tutorial.
4
5## License
6
7This package is published under [MIT license](./LICENSE).
添加你的 LICENSE 文件(开源协议),以及一个 index.js 文件。
现在,一个最基本的包就是准备好了,等待发布了。
2. 发布
既然包已经准备好了,那么就可以发布了。
2.0. 修正下载源
如果你曾经为了加速 NPM 下载速度而修改了它的下载源,那么请改回去,不然是无法发布的。
检查方式:
1npm config get registry
NPM 的官方源是 https://registry.npmjs.org/
,如果你看到控制台打印是这个,那么就没
问题了。而如果不是,那么请使用下面的命令修改回去:
1npm config set registry https://registry.npmjs.org/
2.1. 创建并登录 npmjs.org 账户
如果你没有 npmjs.org 账户,那么先要创建一个,方法很简单:
1npm adduser
根据提示创建即可。
记得验证邮箱,否则将无法发布包。
如果已经有 npmjs.org 账户了,请直接登录:
1npm login
3. 真正的开始
上面的教程只是一个最简单的 DEMO,远远不能满足我们的发布需要,下面以一个需要编译的 TypeScript 包为例,看看如何发布和管理。
3.1. 合理的 package.json
先来看一个 package.json 的内容:
1{
2 "name": "full-sample",
3 "version": "0.1.0",
4 "description": "A sample to learn NPM.",
5 "main": "./dist/index.js",
6 "scripts": {
7 "prepare": "npm run rebuild",
8 "build": "tsc -p .",
9 "rebuild": "npm run clean && npm run lint && npm run build",
10 "test": "echo See directory sources/tests",
11 "clean": "rm -rf dist",
12 "lint": "tslint --project tslint.json"
13 },
14 "keywords": [
15 "npm",
16 "sample"
17 ],
18 "author": "NPM Learner <[email protected]> (https://sample.com/)",
19 "license": "Apache-2.0",
20 "repository": {
21 "type": "git",
22 "url": "git+https://github.com/learn-npm/full-sample.git"
23 },
24 "bugs": {
25 "url": "https://github.com/learn-npm/full-sample/issues"
26 },
27 "homepage": "https://github.com/learn-npm/full-sample#readme",
28 "types": "./dist/index.d.ts",
29 "typings": "./dist/index.d.ts",
30 "dependencies": {
31 "sequelize": "^4.24.0"
32 },
33 "devDependencies": {
34 "@types/node": "^8.0.51",
35 "@types/sequelize": "^4.0.79",
36 "typescript": "^2.6.1"
37 },
38 "engines": {
39 "node": ">=8.0.0"
40 }
41}
假定项目的 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 依赖的包文件:
1/node_modules/
2/dist/
3*.log
3.4. NPM 包文件设置
NPM 打包发布的时候,会默认把当前目录下所有文件打包。但是 Git 仓库中,有些东西是不需要
发布到 NPM 的,因此我们需要使用一个文件 .npmignore
来忽略这些文件,常用配置如下:
1/.git/
2/.vscode/
3/docs/
4/node_modules/
5.gitignore
6.npmignore
7tslint.json
8tsconfig.json
9*.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 文件。
1npm install tslint -g
2tslint --init
TS Linter 的规则非常多,而且默认规则限制非常严格,可以适当根据提示解除一些限制。比如 作者就采用了如下配置,仅供参考:
1{
2 "defaultSeverity": "error",
3 "extends": [
4 "tslint:recommended"
5 ],
6 "jsRules": {
7 },
8 "rules": {
9 "interface-name": false,
10 "trailing-comma": false,
11 "max-classes-per-file": false,
12 "ordered-imports": false,
13 "variable-name": false,
14 "prefer-const": false,
15 "member-ordering": false,
16 "no-bitwise": false,
17 "forin": false,
18 "object-literal-sort-keys": false,
19 "one-line": [false],
20 "object-literal-key-quotes": [false],
21 "no-string-literal": false,
22 "no-angle-bracket-type-assertion": false,
23 "only-arrow-functions": false,
24 "no-namespace": false,
25 "no-internal-module": false,
26 "unified-signatures": false,
27 "ban-types": false,
28 "no-conditional-assignment": false,
29 "radix": false
30 },
31 "rulesDirectory": []
32}
如果想在 Visual Studio Code 里面实现 TS Linter 智能提示,则还需要安装 VSCode 的 TSLint 扩展。
现在,可以尽情地编写代码了。
4. 维护
4.1. 版本号维护
维护一个包,肯定是要进行包的版本升级的。如何进行呢?手动修改 package.json 的 version 字段是一个办法,但是显得有点 low。可以使用下面的命令:
1npm version v0.1.0 # 版本号变成 0.1.0,即显式设置版本号。
2npm version patch # 版本号从 0.1.0 变成 0.1.1,即修订版本号加一。
3npm version minor # 版本号从 0.1.1 变成 0.2.0,即子版本号加一。
4npm version major # 版本号从 0.2.0 变成 1.0.0,即主版本号加一。
但是,除此之外,还有四条命令,用于创建“预发布版本”,也就是非稳定版本。
1npm version v1.2.3
2
3# 版本号从 1.2.3 变成 1.2.4-0,就是 1.2.4 版本的第一个预发布版本。
4npm version prepatch
5
6# 版本号从 1.2.4-0 变成 1.3.0-0,就是 1.3.0 版本的第一个预发布版本。
7npm version preminor
8
9# 版本号从 1.2.3 变成 2.0.0-0,就是 2.0.0 版本的第一个预发布版本。
10npm version premajor
11
12# 版本号从 2.0.0-0 变成 2.0.0-1,就是使预发布版本号加一。
13npm version prerelease
注意: version 命令默认会给你的 git 仓库自动 commit 一把,并打一个 tag。如果不想它动你的 git 仓库,你应该使用
--no-git-tag-version
参数,例如:1npm --no-git-tag-version version patch
如果你想一劳永逸,那么可以使用如下 NPM 设置彻底禁止它:
1npm config set git-tag-version false # 不要自动打 tag 2npm 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
。
如果你要初始化一个带包前缀的包,则可以使用下面的命令。
1npm init --scope=abc # 当然你还可以加上个 `-y` 快速创建。
或者你想每次都使用
@abc/
包前缀?加个设置即可:1# 这样每次初始化新的 package.json,都将自动应用 @abc/ 包前缀。 2npm config set scope abc
现在,可以发布你的包到 npmjs.org
了。哦不,别忘了一点:
官方文档表示:所有带前缀的包,在发布的时候,默认都是发布为私有包。
这意味着你不能就这么发布,因为你(可能)不是付费用户,不能发布私有的包。那怎么办呢?别
担心,npm publish
命令还有一个参数 --access
,通过这个参数可以指定发布的是公共包
还是私有包。因此,只要用下面的命令就可以发布一个公共的,带包前缀的包了:
1npm publish --access=public
(完)