Back

配置 Node.js 项目的常见模式

配置 Node.js 项目的常见模式

每个 Node.js 项目都会积累配置文件。一些团队最终在根目录中拥有十几个点文件(dotfiles),却不理解每个文件存在的原因。另一些团队则继承了多年前做出配置选择且从未重新审视的项目。

本文探讨了已成为约定俗成的 Node.js 项目常见配置模式。我们不会规定单一的设置方案,而是探讨这些模式存在的原因及其代表的权衡取舍。

核心要点

  • Node.js 配置分为四个不同的层次:运行时、依赖项、语言和质量工具
  • 通过 .nvmrc.node-versionpackageManager 字段进行版本锁定,确保团队间环境一致
  • ESM 现在是新项目的默认模块系统,通过在 package.json 中设置 "type": "module" 启用
  • 应提交锁文件(lockfiles)并将其视为源代码,以实现可重现的构建和安全审计
  • 配置选择涉及权衡取舍,取决于团队的具体情况和项目需求

配置的层次结构

现代 Node.js 设置通常涉及四个不同的配置层次:运行时、依赖项、语言和质量工具。理解这些层次有助于你做出有意识的选择,而不是盲目复制样板代码。

每个层次解决不同的问题,随着 Node.js 的成熟,每个层次内的模式都发生了显著演变。

运行时配置:锁定 Node 版本

团队需要在开发机器、CI 流水线和生产服务器之间保持一致的 Node.js 版本。随着生态系统的成熟,版本锁定已变得越来越标准化。

.nvmrc.node-version 文件仍然是最简单的方法——一个包含版本字符串的单一文件,版本管理器如 nvm、fnm 或 Volta 可以读取。这对单包仓库效果很好。

package.json 中的 engines 字段有不同的用途:它声明兼容性而不是锁定确切版本。设置 "engines": { "node": ">=22" } 告诉使用者你的包支持什么版本,而不强制使用特定版本。

为了更严格的执行,packageManager 字段结合 Corepack 已成为标准方法。该字段指定包管理器及其确切版本,确保每个人使用相同的工具:

{
  "packageManager": "pnpm@10.x"
}

依赖管理和锁文件

Node.js 依赖项配置最佳实践的核心是锁文件的规范管理。无论你使用 npm 的 package-lock.json、pnpm 的 pnpm-lock.yaml 还是 Yarn 的 yarn.lock,原则都是一样的:提交你的锁文件并将其视为源代码。

锁文件有两个目的。它们确保跨环境的可重现安装,并提供安全审计跟踪,记录安装的确切版本。

工作区(workspaces) 的兴起使多包仓库成为常态。现在所有三个主要包管理器都原生支持工作区,允许你在单个仓库中管理相关包,共享依赖项提升到根目录。

工作区配置通常位于根目录的 package.json 中:

{
  "workspaces": ["packages/*", "apps/*"]
}

这种 Node.js 项目结构模式减少了重复并简化了跨包开发。

语言配置:ESM 和 TypeScript

ESM 与 CommonJS 的决策几乎影响所有其他配置选择。ESM 现在是新项目的默认选择,通过在 package.json 中设置 "type": "module" 启用。

TypeScript 配置变得更加细致。moduleResolution 设置比以前更重要——"bundler" 模式适用于使用构建工具的项目,而 "node16""nodenext" 适合直接 Node.js 执行。

Node 现在可以通过在运行时剥离类型注解来运行 TypeScript 文件。这种类型剥离行为在现代 Node 版本中是稳定的,但它不执行类型检查,也不支持所有 TypeScript 功能,因此大多数生产项目仍然依赖构建步骤。

通过 tsconfig.json 进行路径映射有助于大型项目避免深层相对导入,尽管这需要在构建工具或运行时中进行相应配置。

质量工具配置

Node.js 工具配置已围绕更少但更强大的工具进行整合。ESLint 的扁平配置格式(eslint.config.js)取代了传统的 .eslintrc 层次结构,提供显式组合而非隐式扩展。

Node.js 内置的测试运行器已经足够成熟,许多项目可以完全跳过外部测试框架。对于需要更多功能的项目,测试配置通常位于 package.json 脚本或专用配置文件中。

像 Prettier 这样的格式化工具使用自己的配置文件,尽管许多团队现在依赖编辑器设置或最小配置来减少根目录的混乱。

环境特定配置

Node 的原生 --env-file 标志减少了对 dotenv 等包的依赖。维护 .env.example 作为文档,同时将实际 .env 文件排除在版本控制之外的模式仍然是标准做法。

对于生产环境,环境变量通常来自部署平台而不是文件。配置层应该抽象这种差异——无论值如何获得,你的代码都从 process.env 读取。

结论

每个配置选择都涉及权衡取舍。原生功能减少了依赖,但可能缺乏生态系统成熟度。严格的工具可以捕获错误,但会减慢迭代速度。工作区简化了某些工作流程,但使其他工作流程复杂化。

最佳的 Node.js 配置实践不是通用规则——它们是适合团队具体情况的模式。独立开发者的最佳设置与企业团队不同。库的配置需求与应用程序不同。

重要的是理解每个配置存在的原因,这样你就可以做出有意识的选择,而不是积累盲目复制的点文件。

常见问题

这三个都是可用于生产的选择。npm 与 Node.js 捆绑在一起,无需额外设置。pnpm 通过符号链接提供更快的安装和严格的依赖隔离。Yarn 以不同的方法提供类似的性能优势。对于大多数项目,选择取决于团队熟悉度和特定工作流程需求,而不是技术优越性。

除非有特定原因,否则新项目应使用 ESM。ESM 是 JavaScript 标准,提供更好的静态分析,并支持顶层 await。在 package.json 中将 type 设置为 module 以启用它。只有在使用缺乏 ESM 支持的旧包或维护遗留代码库时,才需要使用 CommonJS。

内置标志在开发中效果很好,但你仍然可以从维护 .env.example 文件作为文档中受益。该文件向团队成员展示项目期望的环境变量,而不暴露实际值。将真实的 .env 文件排除在版本控制之外,并依赖部署平台提供生产环境的值。

工作区适合包之间共享大量代码、一起发布或受益于跨边界原子提交的项目。当包具有独立的发布周期、不同团队拥有它们或 CI 复杂性变得难以管理时,独立仓库效果更好。从更简单的方法开始,只有在出现痛点时才进行迁移。

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay