编写-测试-发布-更新npm包详细教程

作为前端开发者,npm包是我们日常开发中不可或缺的工具,我们的项目通常依赖了许多npm包,本文将介绍一个npm包从编写、测试到发布、更新的完整教程。

一、环境准备

  1. 安装Node.js
  2. 在npm官网注册账号,发布npm包要用

二、创建项目

1.创建项目(示例项目:hbr-utils)

powershell 复制代码
mkdir hbr-utils #创建文件夹
cd hbr-utils #进入文件夹
  1. npm项目初始化
powershell 复制代码
npm init

执行命令后,根据问题填入对应的值后,目录会生成一个package.json文件,也可以直接修改里面的值。

3.下载依赖,分别用于管理版本、打包、测试

powershell 复制代码
npm i -D bumpp tsup typescript vitest
  • bumpp:用于自动管理项目版本号(遵循语义化版本规范)并生成 CHANGELOG 的工具,可简化版本发布流程。
  • tsup:基于 esbuild 的快速 TS/JS 打包工具,支持零配置输出多种格式,以速度快、配置简单为特点。
  • typescript:TypeScript 语言的核心包,为 JS 添加静态类型系统并将 TS 编译为可执行 JS,是 TS 开发的基础。
  • vitest:基于 Vite 的极速单元测试框架,支持 Jest 风格 API,利用 HMR 特性提升测试效率,适配现代语法。

下载好后,我们分别创建配置文件

typescript 复制代码
// bump.config.ts
import { defineConfig } from 'bumpp'

export default defineConfig({
  commit: true, // 是否自动提交
  tag: true, // 是否生成标签
  push: true, // 是否推送
  recursive: false, // 是否递归升级子包
  files: ['package.json'] // 指定需升级的文件
})
typescript 复制代码
// tsup.config.ts
export default {
  entry: ['./src/index.ts'], // 入口文件
  format: ['cjs', 'esm'], // 输出格式
  outDir: 'dist', // 输出目录
  minify: true, // 压缩代码(生产环境推荐)
  sourcemap: true // 生成 sourcemap
}
typescript 复制代码
// tsconfig.json
{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ES2022",
    "moduleResolution": "node",
    "strict": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "esModuleInterop": true,
    "outDir": "dist",
    "resolveJsonModule": true
  },
  "include": ["*.ts"],
  "exclude": ["node_modules"]
}
typescript 复制代码
// vitest.config.ts
import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    // 测试文件匹配模式
    include: ['**/*.{test,spec}.{js,ts}'],
    // 是否开启浏览器环境模拟(默认是 Node 环境)
    environment: 'node' // 可选 'jsdom'(浏览器模拟)
  }
})

三、编写代码并测试

  1. 新增src目录和test目录,分别存放功能代码和测试代码,目录文件如下
  1. 编写功能代码,本文以两个工具函数为例
typescript 复制代码
// /src/mathUtils.ts
export function add(a: number, b: number) {
  return a + b
}
typescript 复制代码
// /src/stringUtils.ts
/**
 * 将下划线命名的字符串转换为驼峰命名法
 * @param str 下划线命名的字符串
 * @returns 驼峰命名的字符串
 * @example toCamelCase('user_name') => 'userName'
 */
export function toCamelCase(str: string) {
  return str.replace(/_([a-z])/g, (match, char) => char.toUpperCase())
}
typescript 复制代码
// 在入口文件导出所有函数
// /src/index.ts
export * from './mathUtils'
export * from './stringUtils'
  1. 编写测试代码
typescript 复制代码
// /test/mathUtils.test.ts
import { test, expect } from 'vitest'
import { add } from '../src/mathUtils.ts'

test('add function', () => {
  expect(add(1, 2)).toBe(3)
  expect(add(5, -1)).toBe(4)
})
typescript 复制代码
// /test/stringUtils.test.ts
import { test, expect } from 'vitest'
import { toCamelCase } from '../src/stringUtils.ts'

test('toCamelCase function', () => {
  expect(toCamelCase('hello_world')).toBe('helloWorld')
  expect(toCamelCase('my_user_name')).toBe('myUserName')
})
  1. 在package.json中加入测试命令
json 复制代码
  "scripts": {
    "test": "vitest",
    "test:run": "vitest run"
  },
  1. 运行测试命令
powershell 复制代码
npm run test

从图中可以看到,测试用例全部通过了。

四、项目打包、版本管理以及发布到npm

  1. 在package.json中加入bumpp和build相关命令,完整的文件如下
json 复制代码
{
  "name": "hbr-utils",
  "version": "1.0.0",
  "description": "Utility functions",
  "main": "./dist/index.js",
  "bin": {
    "hello": "bin/hello.js"
  },
  "scripts": {
    "test": "vitest",
    "test:run": "vitest run",
    "bumpp": "bumpp",
    "build": "tsup",
    "test:build": "npm run test:run && npm run build",
    "build:bumpp": "npm run test:build && bumpp",
    "build:publish": "npm run build:bumpp && npm publish"
  },
  "files": [
    "bin",
    "dist"
  ],
  "exports": {
    ".": {
      "require": "./dist/index.js",
      "import": "./dist/index.mjs"
    }
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/TianZongNanBei/hbr-utils.git"
  },
  "keywords": [
    "string",
    "array",
    "typescript",
    "utils"
  ],
  "author": "TianZongNanBei",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/TianZongNanBei/hbr-utils/issues"
  },
  "homepage": "https://github.com/TianZongNanBei/hbr-utils#readme",
  "devDependencies": {
    "bumpp": "^10.2.2",
    "tsup": "^8.5.0",
    "typescript": "^5.9.2",
    "vitest": "^3.2.4"
  }
}

}
  • main :包的默认入口文件,供 require/import 引入时默认加载
  • bin :定义包中的可执行脚本,用于将脚本注册为命令行工具。安装包后,这些脚本会被链接到系统的可执行目录(如 node_modules/.bin),允许用户直接通过命令名调用。"hello": "bin/hello.js" 表示注册一个名为 hello 的命令,执行该命令时实际运行的是 bin/hello.js 脚本(需确保该脚本顶部有 #!/usr/bin/env node 声明)。
  • files :指定发布到 npm 的文件或目录,这样发布到npm后只会保留bindist目录,而不会上传其它源代码。
  • exports :精细化控制入口,支持按 require/import 方式返回不同文件(示例区分 CJS/ESM 入口)

我新建了bin目录并在目录中新增了hello.js,用于测试命令行的功能,我们所熟知的vue-cli、create-react-app也是通过这样的方式来的执行的。

javascript 复制代码
// /bin/hello.js
#!/usr/bin/env node
console.log('Hello Bin!')

#!/usr/bin/env node 作用是告诉系统这个脚本需要用 Node.js 环境来执行

  1. 项目打包
powershell 复制代码
npm run build

可以看到tsup已经打包成功了

  1. 管理版本并提交
powershell 复制代码
npm run bumpp

打开github可以看到已经打上了tag

  1. 发布到npm
powershell 复制代码
npm publish

可以看到已经发布成功了,这一步需要先登录,如果之前没有登录过npm需要先执行npm login进行登录。如果之前npm设置了淘宝镜像源的小伙伴,需要把它改回npm官网,否则会发布不上去。

  1. 下载并测试npm包 新建一个新项目并下载包
powershell 复制代码
npm i hbr-utils

可以看到,无论是用require还是import导入都是可以兼容的,说明已经同时支持CommonJ和ESM。但是也发现一个问题,就是没有ts的类型提示。那我们就加入ts类型,更新为1.0.1版本。

修改:

typescript 复制代码
// tsup.config.ts 加入dts配置
export default {
  entry: ['./src/index.ts'], // 入口文件
  format: ['cjs', 'esm'], // 输出格式
  outDir: 'dist', // 输出目录
  dts: true, // 生成 .d.ts 文件
  minify: true, // 压缩代码(生产环境推荐)
  sourcemap: true // 生成 sourcemap
}
json 复制代码
// package.json修改exports配置
{
  "name": "hbr-utils",
  "version": "1.0.0",
  "description": "Utility functions",
  "main": "./dist/index.js",
  "bin": {
    "hello": "bin/hello.js"
  },
  "scripts": {
    "test": "vitest",
    "test:run": "vitest run",
    "bumpp": "bumpp",
    "build": "tsup",
    "test:build": "npm run test:run && npm run build",
    "build:bumpp": "npm run test:build && bumpp",
    "build:publish": "npm run build:bumpp && npm publish"
  },
  "files": [
    "bin",
    "dist"
  ],
  "exports": {
    ".": {
      "require": {
        "types": "./dist/index.d.ts",
        "default": "./dist/index.js"
      },
      "import": {
        "types": "./dist/index.d.mts",
        "default": "./dist/index.mjs"
      }
    }
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/TianZongNanBei/hbr-utils.git"
  },
  "keywords": [
    "string",
    "array",
    "typescript",
    "utils"
  ],
  "author": "TianZongNanBei",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/TianZongNanBei/hbr-utils/issues"
  },
  "homepage": "https://github.com/TianZongNanBei/hbr-utils#readme",
  "devDependencies": {
    "bumpp": "^10.2.2",
    "tsup": "^8.5.0",
    "typescript": "^5.9.2",
    "vitest": "^3.2.4"
  }
}
  1. 一键测试打包更新版本并发布到npm
powershell 复制代码
npm run build:publish

发布成功!

再次测试:

可以看到函数功能和bin命令都执行成功了,而且写代码时也有ts类型提示了,大功告成!

相关推荐
漂流瓶jz3 小时前
解锁Babel核心功能:从转义语法到插件开发
前端·javascript·typescript
周小码3 小时前
shadcn-table:构建高性能服务端表格的终极解决方案 | 2025最新实践
前端·react.js
大怪v3 小时前
老乡,别走!Javascript隐藏功能你知道吗?
前端·javascript·代码规范
webYin4 小时前
vue2 打包生成的js文件过大优化
前端·vue.js·webpack
gnip4 小时前
结合Worker通知应用更新
前端·javascript
叶玳言5 小时前
【LVGL】从HTML到LVGL:嵌入式UI的设计迁移与落地实践
前端·ui·html·移植
高级测试工程师欧阳5 小时前
HTML 基本结构
前端
Gazer_S5 小时前
【Element Plus 表单组件样式统一 & CSS 文字特效实现指南】
前端·css·vue.js
一只小阿乐5 小时前
Html重绘和重排
前端·html
_Rookie._5 小时前
vue3 使用css变量
前端·javascript·html