关于 npm 包和 nodebbs,你应该知道的一切

最后更新: 12/30/2025
作者: C 源跟踪
  • npm 既是一个庞大的软件包注册表,也是安装、更新、删除和审核 Node.js 依赖项的主要 CLI 工具。
  • 项目依赖 package.json 文件,通过 main、exports、imports 和 type 等字段来定义依赖项、脚本和入口点。
  • 本地安装与全局安装、语义版本范围和依赖类型(dependencies、devDependencies、optionalDependencies)控制着软件包的使用方式和使用位置。
  • 高级导出、条件导出和子路径导入可以对像 nodebbs 这样的软件包向不同环境公开的内容进行精细控制。

npm 包 nodebbs

如果你想了解如何 类似“nodebbs”的npm包 要融入 Node.js 生态系统,首先需要对以下方面有扎实的了解: npm是什么包的结构方式,以及 Node 如何解析和暴露模块。现代 Node.js 项目严重依赖 npm,不仅用于安装代码,还用于管理脚本、安全、版本控制以及包的对外使用方式。

本指南将带您了解…… 从零开始构建 npm — 什么是软件包,本地和全局软件包的工作原理,如何安装、更新和删除它们,以及如何 package.json 结构如何,以及诸如以下的高级功能: exportsimports 这些字段控制着你的软件包(例如,像 nodebbs 这样的论坛引擎)向用户提供哪些内容。所有内容都用通俗易懂的语言解释,并附有大量示例,因此你可以自信地发布和使用 npm 软件包。

npm 是什么?它对像 nodebbs 这样的软件包为什么如此重要?

npm(节点包管理器) npm 既是一个命令行工具,也是一个庞大的开源 Node.js 包在线注册表。当你在系统上安装 Node.js 时,npm 会自动安装,让你立即访问社区发布的数百万个可重用模块。 npmjs.com.

这个 npm 注册表 它实际上是全球最大的单语言代码库,拥有超过一百万个已发布的软件包,几乎涵盖了所有可以想象到的任务。这些软件包种类繁多,从小型实用程序(单个函数)到完整的框架、命令行界面 (CLI) 和应用程序框架,应有尽有,为日常生产应用程序提供支持。

本来, npm 的设计初衷 最初它仅用于管理后端 Node.js 项目的依赖项,但如今也已成为前端工作流程的核心工具。你可以安装 React、Webpack 或 Vite 等工具、CSS 框架、测试运行器等等——所有这些都以 npm 包的形式分发。

当使用特定软件包时,例如 nodebbs, npm 负责下载其代码npm 负责解决其依赖关系,确保团队内部版本一致,并配置它公开的任何脚本或 CLI。因此,如果您想评估、定制甚至发布自己的软件包,了解 npm 至关重要——请参阅…… npm供应链遭受广泛攻击.

Node.js、npm 以及如何安装它们

要使用任何 npm 包(包括 nodebbs),您需要 已安装 Node.js 和 npm。 在你的机器上。npm 已与 Node 捆绑在一起,所以你只需从官方网站安装 Node 即可。

推荐的方法是使用版本管理器安装 Node.js,例如 nvm它允许您在多个 Node 和 npm 版本之间切换。这使得使用不同的 Node 版本测试项目变得容易,并避免了系统级安装程序可能出现的权限问题。

您可以快速验证是否 Node 和 npm 已经存在。 打开终端并运行: node -v 检查Node版本和 npm -v 确认 npm 版本。

如果缺少 Node.js 或您的版本太旧,请下载。 长期支持(LTS)发布nodejs.org 适用于您的操作系统。在 Windows 和 macOS 上,安装程序会自动完成所有设置;在 Linux 上,您可以使用 NodeSource 或发行版推荐的方法,或者使用版​​本管理器,例如 nvm.

npm 的核心概念:包、模块和注册表

在Node.js世界中, “包裹” 包是一段打包好的代码,其中包含模块或应用程序所需的一切:JavaScript 文件、元数据、文档,有时还包括构建产物。包通常位于一个目录中。 package.json 文件描述了它们包含的内容。

A “模块” 是一个可以在 Node.js 中使用以下方式导入的代码单元 require() or importnpm 包通常会公开一个或多个模块供用户使用。例如,一个实用工具库可能只导出一个主模块,而像 nodebbs 这样复杂的包则可能为其服务器端和客户端提供多个入口点。

软件包会向公众发布。 npm 注册表 (或私有注册表)以便其他开发者可以通过简单的命令安装它们。在底层,npm 会下载文件,验证依赖关系树,并将所有内容存储在一个目录中。 node_modules 保存到您的应用程序可以导入的文件夹。

npm 包的常见示例包括框架,例如 Express、React 和 Vue例如 Lodash 和 Chalk 等实用工具,Mongoose 和 Socket.io 等后端辅助工具,以及 Jest、Webpack、Babel、Nodemon 和 Axios 等工具。像 nodebbs 这样的软件包可以作为另一个可安装的依赖项,与这些工具一起集成到你的应用程序栈中。

在命令行中使用 npm

这个 npm 命令行界面 (CLI) 它用于安装、移除、更新和检查软件包,以及运行项目脚本。在 Windows 系统中,通常会打开命令提示符或 PowerShell;在 macOS 和 Linux 系统中,则会使用终端。

一些最常用的 npm 命令包括: npm install, npm uninstall, npm update, npm init, npm start, npm testnpm publish这些命令几乎涵盖了管理 Node.js 项目依赖项和生命周期任务所需的一切。

要在本地项目中安装新软件包,通常需要运行以下命令: npm install <package-name> 从项目根目录下载软件包。 node_modules 而且,使用现代 npm 时,会自动在 下添加一个条目 dependencies in package.json.

全球安装,使用 npm install -g <package-name>这些工具专用于您希望在系统所有位置都能使用的工具,例如: nodemon, typescript或其他命令行界面。您的应用程序级库(包括 nodebbs)几乎总是位于本地。 dependencies 代替。

初始化 Node 项目以及 package.json 的作用

每个严肃的Node.js项目都是从……开始的。 package.json 该文件充当应用程序或库的清单。它存储元数据(名称、版本、描述)、脚本、依赖项以及有关如何加载软件包的信息。

您可以通过运行以下命令创建此文件。 npm init 在一个空文件夹中,然后回答一些关于项目的提示问题。如果您不想回答这些问题, npm init -y 生成最小值 package.json 默认设置合理,您可以稍后进行编辑。

一旦 package.json 存在,您安装的每个软件包都会记录在以下位置: dependencies, devDependencies或其他专用部分。这使得其他开发者可以克隆你的仓库并直接运行。 npm install 恢复完整的依赖关系树。

对于像nodebbs这样你可能想要发布的软件包, package.json 它还声明了包名称、入口点以及任何字段,例如 main, exportstype 它控制着Node如何解析其模块。这使得 package.json 对于 npm 包的消费和生产都至关重要。

npm 包的本地安装与全局安装

本地软件包已安装到当前项目中。 node_modules 目录,并且仅在该项目内可用。当您运行 npm install express or npm install nodebbs 在你的项目文件夹中,该包将成为该应用程序依赖关系图的一部分。

这种本地安装策略可以防止…… 项目间存在版本冲突 因为每个项目都维护着自己的依赖项副本。一个应用可以使用 Express 4,而另一个应用可以使用 Express 5,它们之间不会相互干扰。

全局软件包,使用以下方式安装 npm install -g它们被放置在系统级位置,通常会提供命令行工具。您可以将其用于 nodemon, typescript或者对于全局项目生成器来说,但你很少希望像 nodebbs 这样的应用程序代码是全局的。

npm 还允许你更改全局安装前缀。 npm config set prefix <path>如果您没有管理员权限,或者想避免在安装全局命令行工具时出现权限错误,这种方法就非常方便。这样,您的全局工具就可以放在用户可写的目录中。

管理依赖项:安装、更新和删除

在日常工作中,你会花费大量时间 添加、更新以及偶尔删除 npm 依赖项npm 为这些操作中的每一个都提供了简单的命令,无论是在本地还是全局范围内。

在现有项目中安装所有依赖项非常简单,只需运行以下命令即可。 npm install 在目录中 package.json npm 读取依赖项和开发依赖项列表,并重新创建依赖项。 node_modules 请按顺序放入文件夹。

要添加单个依赖项,请运行 npm install <package-name> (或 npm i <package-name> (简称),可选地使用如下标志: --save-dev, --save-optional--no-save这些标志控制软件包是被记录为常规依赖项、仅开发依赖项,还是根本不被记录。

可以通过以下方式在整个项目范围内更新依赖项: npm update它将软件包升级到仍然满足版本范围的更新版本。 package.json您还可以使用以下命令指定单个软件包: npm update <package-name>或添加 -g 如果您正在更新全局工具。

卸载软件包的过程是对称的: npm uninstall <package-name> 将其从 node_modules 并清理干净 package.json 输入。使用 npm uninstall -g 对全局安装的软件包执行相同的操作。

了解依赖项、开发依赖项和可选依赖项

In package.jsonnpm 会根据依赖项的使用时机和方式,区分不同类型的依赖项。正确区分这些依赖项,可以保持生产环境的精简和工具的灵活性。

dependencies 列出应用程序在生产环境中运行所需的软件包。对于 Web 应用程序,这可能包括 Express、Mongoose,甚至如果您将 nodebbs 嵌入到服务器堆栈中,也可能包括 nodebbs 本身。

devDependencies 包含仅在开发或构建时需要的软件包,例如 Jest、ESLint、Webpack、Babel 或 Nodemon。这些软件包在运行时不会被安装。 npm install --production这样可以减轻生产环境的负担。

optionalDependencies 包含一些可以增强应用功能但并非绝对必需的软件包。如果某个可选依赖项安装失败,npm 不会将其视为致命错误;您的代码需要能够优雅地处理其缺失的情况。

例如旗帜 --save-prod (默认), --save-dev (或 -D), --save-optional 控制新安装软件包的记录位置。历史上,曾有一个明确的…… --save 标志,但现代 npm 对待 npm install <name> 默认情况下作为保存到依赖项的操作。

语义化版本控制和安装特定软件包版本

npm 使用 语义化版本控制(semver) 管理软件包版本至关重要,尤其是在依赖复杂库或像 nodebbs 这样可能随时间演变的软件包时。语义化版本控制 (Semver) 使用以下模式: MAJOR.MINOR.PATCH (例如, 1.4.3).

在语义上, 主要数字 当存在重大变更时,增量更新。 微小 为了向后兼容地添加功能,以及 补丁 用于修复不应破坏现有代码的错误。这种模型允许软件包在不不断破坏下游应用程序的情况下进行演进。

您可以使用以下命令安装软件包的确切版本: npm install package@version, 例如 npm install express@4.17.1如果您想将项目锁定在已知可靠的版本上,同时单独测试新版本,这将非常有用。

package.json您可以使用诸如 `\n` 之类的字符来指定灵活的范围。 ^~ 或使用 "latest" or * 始终获取最新兼容版本。例如: "express": "^4.1.1" 告诉 npm 使用 4.1.1 以上任何兼容的 4.x 版本,但不能使用 5.x 版本。

全局软件包和 CLI 工具

全局 npm 包主要用于安装 命令行工具 无论你在哪个项目中工作,你都希望这些工具可用。这些工具会将可执行文件添加到你的 PATH 环境变量中,这样你就可以直接从终端调用它们。

有用的全局包示例包括 nodemon 用于在开发过程中自动重启Node服务器 typescript 用于在机器上的任何位置编译 TypeScript。安装过程如下: npm install -g <package-name>.

您可以通过运行以下命令来检查已安装哪些全局软件包。 npm list -g --depth=0它会打印出全局可用模块及其版本的列表。这有助于审核您的配置或调试 CLI 问题。

更新或删除全局工具与更新或删除本地工具的方式相同:使用 npm update -g <package-name> 更新和 npm uninstall -g <package-name> 移除它们。保持全局工具更新可确保您获得最新的修复程序和安全补丁。

列出、检查和审核已安装软件包

随着项目规模的增长,跟踪已安装的软件包及其版本变得越来越重要。npm 提供了相应的命令来执行此操作。 列出并检查 你的依赖关系树。

npm list 显示当前项目中本地安装软件包的层级结构,包括直接依赖项所依赖的嵌套依赖项。您可以查看最终安装了哪些版本以及它们之间的关联方式。

npm list -g 操作类似,但适用于全局安装的软件包,并添加 --depth=0 将输出限制为仅包含顶级条目。这样可以保持输出的可读性,尤其是在存在大量嵌套依赖关系时。

为了安全起见,npm 包含了一个 审计功能: 跑步 npm audit 它会扫描您的依赖关系树,并将其与漏洞数据库进行比对,然后输出已知问题的报告——请参阅 沙伊·胡鲁德蠕虫事件通常情况下,您可以使用以下方法自动修复其中许多问题: npm audit fix尽可能将依赖项版本升级到安全版本。

定期审核和更新可大幅降低应用程序暴露于隐藏在第三方模块中的已知漏洞的风险——例如,请参阅 恶意 npm 包冒充当您依赖大型软件包时,这一点尤其重要,例如 nodebbs 这可能会引发一系列复杂的依赖关系。

在 Node.js 代码中使用已安装的软件包

在本地安装软件包后,即可将其导入到 Node.js 应用程序中,并像使用其他模块一样使用。Node 历来都使用 CommonJS 模块 通过 require()但现代项目也经常依赖于 ECMAScript 模块。 import.

对于 CommonJS,您可以这样写 const express = require('express') or const nodebbs = require('nodebbs') 在文件顶部引入包的主要导出项。然后,您可以使用其文档中提供的 API 来配置路由、中间件或其他功能。 nodebbs 的案例,论坛功能.

对于 ECMAScript 模块(当你的 package.json 具有 "type": "module" 或者你使用 .mjs 文件),你反而会这样做 import express from 'express'现在很多现代软件包都发布 ESM 构建版本,而 Node 同时支持这两种格式。

请记住,大型软件包通常会暴露多个入口点,因此您可能会像这样导入子模块。 import { Router } from 'express' or import feature from 'nodebbs/feature.js'这取决于软件包作者如何组织他们的导出功能。这就是…… exports 软件包中的字段 package.json 变得很重要。

npm 脚本:使用 package.json 自动化任务

除了依赖管理之外,npm 还兼作一个简单的任务运行器。 scripts 部分 package.json脚本允许您为在开发或部署期间要运行的常用命令定义简短别名。

一个基本的例子是定义 "start": "node app.js"scripts然后你使用以下命令运行它 npm start. 这比冗长的命令行更容易记忆和分享,而且在各种环境下都能稳定运行。

您可以设置脚本来运行测试、构建前端资源、进行代码检查、启动开发服务器、填充数据库,甚至可以编排与软件包相关的任务。 nodebbs例如,您可能需要一个脚本在启动论坛服务器之前运行数据库迁移。

npm 保留了快捷方式 start, test, restartstop但任何其他自定义脚本都将以如下方式运行: npm run <script-name>在底层,npm 会设置环境变量,使本地安装的 CLI 工具位于 PATH 环境变量中,这就是为什么像 `npm run dev` 这样的命令会生效的原因。 webpack or jest 通常无需完整路径即可工作。

高级包入口点:main、exports 和 imports

对于你发布的软件包——例如假设的 nodebbs 模块——控制哪些文件对用户可见对于 API 的稳定性和安全性至关重要——例如,此类事件 npm 拼写错误抢注 说明风险。

年龄更大 main 该字段指向主条目文件,例如 "main": "./index.js"并且所有 Node 版本都支持。消费者正在这样做 require('your-package') 默认情况下会获取该文件。

较新的 exports 字段功能更加强大:它可以定义多个入口点,支持基于环境或模块系统的条件导出,并阻止访问您不希望用户依赖的内部路径。 exports 如果存在,则只有明确列出的路径才能通过裸导入访问,例如 require('pkg/subpath').

An exports 映射可能指定一个根条目 "."以及其他子路径,例如 "./feature"甚至明确地暴露 ./package.json 如有需要。这样,您可以在保护实现细节私密性的同时,精心设计您的公共 API 接口。

导出模式 * 允许您显示整个文件夹而无需列出每个文件;例如, "./lib/*": "./lib/*.js" 将映射所有匹配的子路径。您还可以通过将某些子文件夹映射到特定路径来显式阻止它们。 null这样就阻止了消费者导入这些路径。

条件导出和环境感知构建

有条件出口 允许您根据软件包的使用方式或使用地点提供不同的文件。您可以发布一个针对特定场景优化的版本。 import (ESM)和另一个用于 require() (CommonJS),甚至可以为 Node 和浏览器分别构建单独的版本。

条件如 "import", "require", "node", "node-addons", "module-sync""default" 可以出现在 exports 选择正确目标的对象。例如: "import": "./index-module.js""require": "./index-require.cjs" 提供 ESM/CommonJS 双重支持。

这些条件将按顺序进行评估,因此您应该按顺序列出它们。 从最具体到最不具体,最后以 "default" 针对未知环境的回退机制。这确保其他运行时环境(例如,使用导入映射的浏览器加载器)仍然可以使用您的包。

Node.js 还允许你嵌套条件,例如拥有一个 "node" 包含两者的分支 "import""require"加上一个单独的 "default" 它旨在实现通用构建。当你的软件包依赖于 Node 中的原生插件,但在其他地方使用 polyfill 时,这种灵活性尤其有用——参见 npm 安全性面临压力.

除了内置条件之外,Node 还支持通过以下方式传递的用户自定义条件: node --conditions=<name>更广泛的生态系统也已趋向于使用诸如此类的密钥。 "browser", "types", "development""production" 适用于更专业的场景。这些功能有助于协调打包器、类型检查器和运行时之间的行为。

子路径导入和内部模块别名

此外 exportsimports 场在 package.json 允许您定义仅在包内部有效的私有导入说明符。这些说明符始终以 `import` 开头。 # 避免与外部软件包冲突。

例如,你可以绘制地图。 "#dep" 在一个环境中,使用条件映射来依赖 Node 原生依赖项;在另一个环境中,使用 polyfill。 imports然后,你的包内的代码会执行以下操作 import '#dep' 并自动获得正确的实现方式。

子路径模式也可以在内部使用。 imports 用于映射内部文件组,例如 "#internal/*.js": "./src/internal/*.js"这样可以为内部模块创建清晰、稳定的导入路径,并保持重构的可管理性,而不会向用户泄露实现细节。

决议规则 imports 镜像 exports包括限制路径只能位于包根目录内,并且不允许向外遍历。 node_modules这样可以保持封装性,防止出现意外行为。

自引用是另一项高级功能,它允许包内的代码通过名称导入自身,只要…… exports 映射已定义。例如,如果您的包名为 "a-package" 和出口 ".""./foo.js"内部文件可以写入 import { something } from 'a-package' 并使用与消费者相同的入口点。

这种技术避免了深层相对路径,并确保内部导入始终反映由公共 API 定义的边界。 exports它还可以通过 CommonJS 工作。 require('a-package/foo.js') 当该子路径被导出时。

npm 和 Node 的模块解析功能 让您能够严格控制复杂软件包(包括像 nodebbs 这样的论坛引擎)的结构、分发和使用方式。通过掌握安装模式、依赖管理、语义化版本控制、安全审计和高级入口点配置, exportsimports您可以自信地构建、集成和维护复杂的 npm 包,随着代码库及其周围生态系统的不断发展,这些包将保持稳定和可预测性。

安全审计员 npm
相关文章:
深入探讨 npm 安全审计和供应链攻击
相关文章: