发布于 2026-01-06 6 阅读
0

使用 npm 发布 NestJS 包 注意事项

使用 npm 发布 NestJS 包

笔记

John 是 NestJS 核心团队的成员,主要负责文档编写。

这是关于为 NestJS 构建可重用 npm 包的系列文章的第一篇。本文重点介绍该过程的具体机制:

  • 构建一个简单的 npm 包
  • 在 NestJS 应用中本地使用和测试它
  • 发布到 NPM

本文为本系列后续文章奠定了基础,后续文章将深入探讨更复杂的 NestJS 包。

引言

我们每天都会与 npm 仓库交互。通常情况下,仓库本身及其工作原理都被巧妙地隐藏在后台——我们在运行命令时无需考虑细节npm install。但有时我们需要更直接地操作仓库——例如,我们可能正在发布一个核心基础设施/实用程序包供组织内各团队内部使用,或者我们可能正在发布一个开源包供公众使用。

第一次发布软件包,然后看到它安装成功,npm install真的很有趣。

npm 安装

而且它出乎意料地简单。虽然网上有很多通用的 npm 教程,但我还是创建了这个教程,并提供了一个软件包入门仓库,您可以快速克隆它,以标准方式进行设置,并跳过一些小障碍。虽然这并非 Nest 特有的问题,但 TypeScript 可能会带来一些其他 npm 教程通常不会涉及的复杂情况。结合 NestJS 环境,如果您遵循几个基本步骤,就可以享受高效的迭代开发/部署工作流程。这就是我将在本文中介绍的内容。跟着教程,您应该能够在 15 分钟左右发布一个基本的 NestJS 包。

至于你为什么要这样做,我想至少有两个很好的理由:
1)学习如何发布软件包可以揭开我们习以为常的事情的神秘面纱。这或许应该成为任何一个称职的全栈开发者的简历上的必备技能。😃
2)无论你发布到 npmjs.com 注册表还是私有注册表,发布 npm 软件包都是创建和共享可重用软件包的标准方法。

再次强调,虽然本教程中我们将构建的示例包非常简单,但本文为后续几篇文章奠定了基础,这些文章将详细介绍更复杂的模块。敬请期待!

先决条件

如果您计划按照本文中的步骤操作,请确保您拥有www.npmjs.com的帐户(您可以使用免费帐户进行本次练习,事实上,除非您想要发布私有包,否则免费帐户完全足够)。您也可以发布到像verdaccio这样的私有 npm 注册表,但设置过程超出了本文的范围。

为开发做准备

如果你正在边阅读本文边进行实时编码,我有几点简短的建议。

首先,请注意,我们实际上将要编写两段独立但相关的代码。一段用于 npm 包,另一段用于配套的 NestJS 应用程序,该应用程序将使用该包并执行相关操作。

为了保持名称同步,我建议使用下面列出的名称。如果您要构建自己的软件包并使用唯一的名称,请确保在所有出现该名称的地方(文件夹、package.json、npmjs、git 等)保持一致。

接下来,我建议您打开两个命令行窗口(以及两个编辑会话),同时处理两段代码。这将帮助您体会到迭代式构建软件包的有效开发模式。本教程的其余部分将以这两个命令行窗口为例进行说明。如果您更喜欢在单个命令行窗口中工作,只需在执行每个步骤时仔细注意您所在的文件夹即可!

设置文件夹

在终端窗口 1 中,创建一个新文件夹。这将是项目两部分的父文件夹:我们正在构建的软件包和我们的小型配套 NestJS 应用程序。



mkdir nestmod && cd nestmod


Enter fullscreen mode Exit fullscreen mode

克隆模块启动器仓库

在终端窗口 1 中,首先克隆nestjs-package-starter 仓库。这是一个初始仓库,它为你的 NestJS 相关 npm 包设置了许多默认细节。这些细节可能需要一些时间才能正确配置。



git clone https://github.com/nestjsplus/nestjs-package-starter.git


Enter fullscreen mode Exit fullscreen mode

nestjs-package-starter完成后,此步骤应在子文件夹中生成一个全新的软件包模板。

现在安装它的依赖项。仍在终端窗口 1 中:



cd nestjs-package-starter
npm install


Enter fullscreen mode Exit fullscreen mode

创建测试应用程序

在第二个终端窗口中,请确保您位于创建的顶层文件夹(我nestmod上面创建的文件夹就是我使用的文件夹;请使用您自己创建的文件夹来跟随教程操作)。搭建一个小型 NestJS 应用的框架,我们将用它来测试我们的软件包。



nest new test-app


Enter fullscreen mode Exit fullscreen mode

选择您喜欢的包管理器(npmyarn),然后稍等片刻,Nest CLI 将构建您的入门应用程序。

您的文件夹结构现在应该与此类似:



nestmod
└─── nestjs-package-starter
│   └───node_modules
│   └───src
│   ...
└─── test-app
│   └───node_modules
│   └───src
│   ...


Enter fullscreen mode Exit fullscreen mode

构建软件包

花点时间浏览一下这个nestjs-package-starter文件夹。以下几点需要注意:

1)该src文件夹包含两个文件:

  • test.ts这是我们软件包的全部功能;它导出一个简单的测试函数,我们将把它导入到我们的 Nest 测试应用程序中,以证明我们确实已经安装并正在使用该软件包。
  • index.tstest.ts从文件夹中导出函数(这是一个桶形文件)。

2) 该package.json文件包含许多有趣的部分。我们将在本教程中深入探讨其中的几个部分。现在需要注意的一点是,其中存在多种不同的包依赖关系:

  • 常规组件dependencies是指运行代码所必需的组件;这些组件应包含除NestJS 本身之外的所有内容。例如,如果我们dotenv在代码中使用某个包,那么该包并非 NestJS 本身提供的,因此它应该放在 `<command>` 中dependencies
  • peerDependencies由于这是一个基于 NestJS 的软件包,我们在此声明它与 Nest 版本 6(最低版本为 6.0.0)兼容@nestjs/common。这意味着我们假定使用该软件包的用户拥有一个可靠的、兼容的 NestJS 环境。仅提及软件包名称即可满足此要求。指定版本号^6.0.0则可确保与用户可能安装的任何 NestJS 小版本保持广泛的兼容性。
  • devDependencies这些是我们仅用于开发所需的软件包;由于我们计划构建一个基于 Nest 的应用,因此需要在开发环境中安装 Nest,以及测试工具、TypeScript 等。这些开发依赖项应该与devDependencies构建普通 Nest 应用时使用的依赖项基本相同。例如,您可以将它们与 ` devDependencies<configuration>` 中的条目进行比较test-app,它们应该完全一致。

在终端窗口 1 中,确保您仍在克隆 nestjs-package-starter 的文件夹中,并使用以下命令构建该软件包:



npm run build


Enter fullscreen mode Exit fullscreen mode

npmbuild脚本非常简单:它只是运行rootDir我们tsconfig.json文件中配置的文件夹下的 TypeScript 编译器。说到这,我们快速看一下tsconfig.json,它与 npm 协同工作,package.json控制着我们包的构建方式。

文件中最值得注意的tsconfig.json是:

  • declaration: true确保生成我们的类型文件,这有助于软件包的使用者受益于 TypeScript 类型检查和编辑器功能(如智能感知)。
  • 这两个Decorators标志确保 TypeScript 装饰器正常工作。
  • outDir控制编译后的代码发布到哪里。
  • rootdir以及顶层includeexclude条目,控制编译哪些源代码。

再快速看一下package.json,注意一下这个"main": "dist/test.js"条目。这是“打包拼图”的最后一块。build脚本会将我们的 TypeScript 代码编译成 JavaScript 并保存在dist文件夹中;桶形文件(index.ts)确保我们的函数被导出并公开可见;"main"我们的条目package.json告诉模块加载器,在导入包时,应该在哪里找到导出的符号。

现在我们已经编译了 TypeScript,并将其准备好打包部署。

将软件包安装到测试应用程序中

现在你已经拥有了一个功能齐全的 npm 包,不过它目前只能在本地使用。你可以使用test-app一个熟悉的命令来运行这个包npm

在终端窗口 2 中,切换到命令创建的文件夹nest new test-app,我们的测试应用程序就位于该文件夹中。



cd nestmod/test-app


Enter fullscreen mode Exit fullscreen mode

用于npm安装我们刚刚构建到测试应用程序中的软件包。



npm install ../nestjs-package-starter


Enter fullscreen mode Exit fullscreen mode

npm install与通常的 `<package_name>` 相比,您肯定已经注意到,主要区别在于您引用的是路径(`<path>`..部分)和名称(`<name>`nestjs-package-starter部分)的组合,而不是像从 npmjs.com 注册表拉取包时那样只使用包名。这说明了 npm 为开发包提供的简单流程:对于本地包和从 npmjs.com 下载的远程包,其npm install工作方式完全相同testapp/package.json。您可以通过观察 `<package_name>` 中的类似条目清楚地看到这一点:
"@nestjsplus/nestjs-package-starter": "file:../nestjs-package-starter"

在测试应用程序中使用该软件包

模板包导出了一个简单的测试函数。请nestjs-package-starter/src/test.ts查看以下代码:



// nestjs-package-starter/src/test.ts
export function getHello(): string {
  return 'Hello from the new package!';
}


Enter fullscreen mode Exit fullscreen mode

现在你已经安装了新的包test-app,它就像任何 npm 包一样可用,你可以像往常一样使用它。打开test-app/src/app.controller.ts并导入该函数;确保文件内容如下所示:



// test-app/src/app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { getHello } from '@nestjsplus/nestjs-package-starter';

@Controller()
export class AppController {
  @Get()
  getHello(): string {
    return getHello();
  }
}


Enter fullscreen mode Exit fullscreen mode

在终端窗口 2 中,开始test-appstart:dev建议使用 ,以便我们可以进行迭代更改):



npm run start:dev


Enter fullscreen mode Exit fullscreen mode

在浏览器中,访问http://localhost:3000,即可查看导入的包函数返回的消息。

如果你一直跟着做,我们再来做一件事,展示一下继续迭代是多么容易。getHello()对包导出的函数做一个简单的修改(我喜欢把它改成返回'Buon Giorno!'😄)。

现在,请确保测试应用程序仍在npm run start:dev终端窗口 2 中以开发模式运行(例如,),然后在终端窗口 1 中使用以下命令重新构建软件包:



npm run build


Enter fullscreen mode Exit fullscreen mode

请注意,在终端窗口 2 中,由于我们链接到了本地软件包,开发服务器会在软件包重新构建时自动重启(在重建过程中可能会显示几秒钟的错误)。这突出了一个需要牢记的关键点:每当您对软件包进行本地更改时,都必须先重新构建它,然后才能让软件包的使用者看到这些更改。显然,这意味着您必须在发布软件包之前重新构建它。

为了确保最后一步生效,请再次查看该package.json文件。该prepare脚本是命令识别的特殊脚本npm publish。每次发布时(我们稍后会执行),该prepare脚本都会在发布前运行。请注意,还有其他一些类似的 npm“钩子”可用,它们可以让你执行诸如运行命令lint、将源代码检入/标记到 Git 仓库等操作。详情请参见此处

当你刷新页面时localhost:3000,你应该会看到热情友好的意大利问候!

发布软件包

现在,我们准备把这个“新生儿包裹”推出网络(哎呀,不好意思,用了个不太恰当的双关语)。要完成这一步,您需要在www.npmjs.com注册一个免费账户。如果您还没有账户,请前往注册页面创建一个。

为该软件包指定一个唯一的、具有 npm 作用域的名称。

关于 npm 的一些说明
  • npm 包名称
    所有 npm 包都有一个名称。如果名称以 `.npm` 开头@,则它是一个作用域名称。作用域名称有助于为你的包创建唯一的命名空间。如果你和我同时发布nestjs-package-starter到 npmjs.org,就会发生冲突。谁先发布,谁就拥有该名称。但是,如果我发布一个作用域包名称,例如`npm_js_name` @johnbiundo/nestjs-package-starter,你可以在 `npm_js_name` 发布你自己的副本@yournpmjsname/nestjs-package-starter,它们可以和谐共存。任何想要我的包的人都可以使用 `npm_js_name` npm install @johnbiundo/nestjs-package-starter,任何想要你的包的人都可以使用 `npm_js_name` npm install @yournpmjsname/nestjs-package-starter。点击此处了解更多关于作用域的信息

  • npm 公共包:
    npm 允许您免费发布公开的包。如果您想发布私有包(例如仅供公司内部共享),则需要一个私有帐户。或者,您可以使用像verdaccio这样的注册表服务器设置内部私有注册表。


  • 除了以你的名义发布包之外,你还可以创建一个免费的 npm组织为你的包赋予更自定义的名称(作用域)。例如,我以 .org 的名义发布了几个包@nestjsplus。点击此处了解更多关于 npm 组织的信息

准备就绪后,打开package.json软件包文件并更改以下条目:

  • 名称:您的作用域包名称,例如@mynpmjsname/my-new-package
  • 版本:选择一个起始版本号;我在下面会对此做一些更详细的说明,但1.0.0目前类似这样的版本号就可以了。
  • 作者:您的姓名和电子邮件地址,格式如下John Biundo <john@email.com>

之后,您可能想要自定义其他内容,例如描述、许可证、关键字、存储库链接等。这些内容都不是 TypeScript 或 NestJS 特有的,因此我们不会在这里介绍它们,但稍加搜索即可找到许多相关的优秀文章和帮助。

准备就绪后,发布软件包

注意:每次重新发布软件包时,您都需要更改该version字段package.json(否则发布步骤将失败)。最佳实践是为 npm 软件包使用语义化版本控制(“semver”) 。

在终端窗口 1 中运行:



npm publish


Enter fullscreen mode Exit fullscreen mode

此步骤的输出会准确地显示哪些文件被打包并发送到 npmjs.org 以创建您的软件包,以及版本号和其他一些元数据。

请在www.npmjs.com上搜索您的软件包。

请访问https://www.npmjs.org,搜索您需要的软件包。


搜索-npmjs


在测试应用中安装已发布的 npm 包

现在该软件包已在 npm 上线,您可以像安装其他任何软件包一样安装它。

在终端窗口 2 中,首先卸载我们大约 10 分钟前创建和安装的本地版本。



npm uninstall @nestjsplus/nestjs-package-starter


Enter fullscreen mode Exit fullscreen mode

现在,从网上安装你新安装的 npm 包。请根据实际情况修改以下名称:



npm install @yournpmjsname/your-package


Enter fullscreen mode Exit fullscreen mode

最后,编辑你的测试应用,使其反映新的 npm 包名(如果你是通过这种方式发布的,请注意使用正确的“作用域”名称)。例如:



// src/app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { getHello } from '@yournpmjsname/your-new-package';

@Controller()
export class AppController {
  @Get()
  getHello(): string {
    return getHello();
  }
}


Enter fullscreen mode Exit fullscreen mode

启动应用程序,即可使用您的新套餐!

既然您已经了解了发布 npm 包是多么容易,请继续关注本系列的后续文章,我们将介绍如何构建更有趣的 NestJS 模块。

欢迎在下方评论区提问、评论或提出建议,或者只是打个招呼。也欢迎加入我们的Discord服务器,一起愉快地讨论 NestJS。我的 Discord 用户名是Y Prospect

文章来源:https://dev.to/nestjs/publishing-nestjs-packages-with-npm-21fm