发布 TypeScript 包到 NPM

一、背景

本次将 NPM 包 yt-comment-date-format 从 1.0.3 版本升级至 2.0.1,核心目标是为其添加 TypeScript 支持,让使用者获得完整的类型推断能力。本文完整记录从配置调整到发布上线的全流程,适用于所有 TS 包的 NPM 发布场景。

二、前置准备

1. 环境配置

  • 注册 NPM 账号:前往 NPM 官网 完成注册;
  • 安装 Node.js/NVM:推荐使用 NVM 管理 Node.js 版本(避免版本兼容问题);
  • 初始化项目:
    1
    2
    3
    4
    # 初始化 NPM 项目(生成 package.json)
    npm init -y
    # 初始化 TS 配置(生成 tsconfig.json)
    tsc --init

2. 核心依赖安装

1
2
3
4
# 安装 TypeScript(开发依赖)
npm install typescript --save-dev
# 若包有业务依赖(如示例中的 dayjs),直接安装生产依赖
npm install dayjs --save

三、关键配置调整

1. tsconfig.json:开启类型声明生成

修改 tsconfig.json,核心配置如下(其他配置可按需调整):

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"compilerOptions": {
"target": "es5", // 编译目标(兼容低版本环境)
"module": "commonjs", // 模块规范(NPM 包常用 commonjs)
"declaration": true, // 核心:自动生成 .d.ts 类型声明文件
"outDir": "dist", // 编译输出目录
"strict": true, // 开启严格类型检查
"esModuleInterop": true, // 兼容 ES 模块与 CommonJS
"skipLibCheck": true, // 跳过第三方声明文件检查
"forceConsistentCasingInFileNames": true // 强制文件名大小写一致
},
"exclude": ["node_modules", "dist"] // 排除无需编译的目录
}
  • 注意:若包内有私有类型但需对外暴露(如接口、类型别名),需为其添加 export,否则使用者无法获取类型推断。

2. package.json:指定入口与类型文件

package.json 中添加/修改以下配置,告诉 NPM 和 TS 编译器包的入口与类型文件位置:

1
2
3
4
5
6
7
8
9
10
{
"main": "dist/index.js", // 包的主入口(编译后的 JS 文件)
"types": "dist/index.d.ts", // 类型声明文件入口(与 main 对应)
"files": ["dist"], // 可选:指定发布到 NPM 的文件/目录(避免发布源码)
"scripts": {
"build": "tsc", // 编译 TS 为 JS
"test": "npm run build && node test.js", // 构建后执行测试
"release": "tsc && npm publish" // 构建+发布(公有包)
}
}

3. .gitignore:忽略编译产物

避免将编译后的 dist 目录提交到 Git 仓库(仅保留源码):

1
2
3
# .gitignore
node_modules/
dist/

四、构建与测试

1. 编写 TS 源码(示例)

入口文件 index.ts(评论时间格式化核心逻辑):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
'use strict';

import dayjs from 'dayjs';

/**
* 评论时间格式化
* @param time4server 服务器当前时间(时间戳)
* @param time4comment 评论时间(时间戳)
* @returns 格式化后的时间文本(如:刚刚、5分钟前、昨天 18:30)
*/
export function commentTimeFormat(time4server: number, time4comment: number): string {
const a = dayjs(time4server); // 服务器当前时间
const b = dayjs(time4comment); // 评论时间
const originDate = (fm: string) => a.format(fm);

// 时间起点(今天凌晨、今年元旦)
const c = dayjs(originDate('YYYY-MM-DD'));
const d = dayjs(originDate('YYYY-01-01'));

// 时间差计算
const diff = a.diff(b, 'seconds'); // 评论已过秒数
const diffMinute = a.diff(b, 'minutes'); // 评论已过分钟数
const diffHour = a.diff(b, 'hours'); // 评论已过小时数
const diffTodayHour = a.diff(c, 'hours'); // 今天已过小时数
const diffCurrent = a.diff(d, 'seconds'); // 今年已过秒数

// 格式化规则
const textConfig = ['刚刚', '分钟前', '小时前', '昨天 HH:mm', 'M月D日 HH:mm', 'YYYY年M月D日 HH:mm'];
let newTime = '';

if (diff > diffCurrent) {
// 往年
newTime = b.format(textConfig[5]);
} else {
// 今年
if (diffHour - diffTodayHour >= 24) {
// 前天及以前
newTime = b.format(textConfig[4]);
} else if (diffHour >= diffTodayHour) {
// 昨天
newTime = b.format(textConfig[3]);
} else {
// 今天
newTime = diffHour >= 1
? `${diffHour}${textConfig[2]}`
: diffMinute >= 1
? `${diffMinute}${textConfig[1]}`
: textConfig[0];
}
}
return newTime;
}

2. 编写测试脚本

测试文件 test.js(验证格式化逻辑):

1
2
3
4
5
6
7
8
9
10
const { commentTimeFormat } = require('./dist/index.js');
const now = 1560845869969; // 测试基准时间戳

// 测试不同时间场景
console.log(commentTimeFormat(now, now - 1000*59)); // 刚刚
console.log(commentTimeFormat(now, now - 1000*60*59)); // 59分钟前
console.log(commentTimeFormat(now, now - 1000*60*60*23)); // 23小时前
console.log(commentTimeFormat(now, now - 1000*60*60*24*1.9)); // 昨天 XX:XX
console.log(commentTimeFormat(now, now - 1000*60*60*24*17)); // X月X日 XX:XX
console.log(commentTimeFormat(now, now - 1000*60*60*24*500)); // XXXX年X月X日 XX:XX

3. 执行构建与测试

1
2
3
4
# 编译 TS 到 dist 目录
npm run build
# 执行测试
npm run test

五、发布流程

1. 版本管理

NPM 提供标准化版本更新命令,避免手动修改版本号:

1
2
3
4
5
6
# 小版本更新(修复 bug):v1.0.0 → v1.0.1
npm version patch
# 次版本更新(新增功能,兼容旧版):v1.0.0 → v1.1.0
npm version minor
# 主版本更新(不兼容旧版):v1.0.0 → v2.0.0
npm version major

2. 切换 NPM 官方源

发布前需将镜像切回 NPM 官方源(避免发布失败):

1
2
3
4
# 查看当前镜像源
npm config get registry
# 切回官方源
npm config set registry https://registry.npmjs.org

3. 登录 NPM 账号

1
2
3
4
# 方式1:交互式登录
npm login
# 方式2:添加用户(首次登录)
npm adduser

4. 发布包

1
2
3
4
# 直接发布(公有包)
npm publish --access public
# 或执行预定义脚本
npm run release
  • 注意:若包名已被占用,需修改 package.json 中的 name 字段。

5. 本地调试(发布前验证)

发布前可通过 npm link 本地调试包,避免发布后发现问题:

1
2
3
4
5
6
# 1. 在 TS 包根目录执行(将包链接到全局)
npm link
# 2. 在测试项目根目录执行(关联全局包)
npm link yt-comment-date-format
# 3. 测试项目中直接引入使用
import { commentTimeFormat } from 'yt-comment-date-format';

六、撤销/标记废弃发布

1. 推荐:标记包/版本为废弃

不建议直接删除已发布的包(可能影响依赖该包的项目),优先使用 deprecate 标记:

1
2
3
4
# 标记某个版本废弃
npm deprecate yt-comment-date-format@2.0.1 '该版本存在 bug,建议升级至 2.0.2'
# 标记整个包废弃
npm deprecate yt-comment-date-format '该包已不再维护,请使用 xxx 替代'
  • 效果:用户安装该包时会收到警告提示。

2. 撤销发布(谨慎使用)

1
2
3
4
# 删除指定版本(发布72小时内可操作)
npm unpublish yt-comment-date-format@2.0.1 --force
# 删除整个包(不推荐)
npm unpublish yt-comment-date-format --force

七、镜像配置(npmmirror 替代淘宝镜像)

淘宝 NPM 镜像已迁移至 npmmirror,推荐使用最新镜像地址:

1
2
3
4
5
6
# 切换为 npmmirror 镜像(日常开发使用)
npm config set registry https://registry.npmmirror.com
# 临时使用 npmmirror 安装包
npm --registry https://registry.npmmirror.com install 包名
# 安装 cnpm(基于 npmmirror)
npm install -g cnpm --registry=https://registry.npmmirror.com

八、完整配置示例

1. package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
"author": {
"name": "yhorz.cn/csorz"
},
"bundleDependencies": false,
"dependencies": {
"dayjs": "^1.10.4"
},
"deprecated": false,
"description": "评论时间格式化",
"devDependencies": {
"typescript": "^4.2.4"
},
"license": "ISC",
"main": "dist/index.js",
"name": "yt-comment-date-format",
"scripts": {
"build": "tsc",
"release": "tsc && npm publish --access public",
"test": "npm run build && node test.js"
},
"types": "dist/index.d.ts",
"version": "2.0.1",
"files": ["dist"]
}

2. tsconfig.json

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"declaration": true,
"outDir": "dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"exclude": ["node_modules", "dist"]
}

总结

关键点回顾

  1. TS 包发布核心:开启 declaration: true 生成 .d.ts 文件,并在 package.json 中指定 types 字段;
  2. 发布流程:配置调整 → 构建测试 → 版本更新 → 切换官方源 → 登录发布;
  3. 镜像配置:日常开发使用 npmmirror(https://registry.npmmirror.com),发布前切回 NPM 官方源;
  4. 最佳实践:发布前用 npm link 本地调试,废弃包优先用 deprecate 而非 unpublish

遵循以上流程可确保 TS 包发布后具备完整的类型支持,同时规避发布过程中的常见问题(如镜像错误、版本冲突、类型缺失)。


发布 TypeScript 包到 NPM
https://cszy.top/20210413-发布TypeScript包到NPM/
作者
csorz
发布于
2021年4月13日
许可协议