Node.js 环境搭建与工具链

要点

Node 运行 JavaScript,包管理器安装依赖,TypeScript 工具提供类型检查或转换。运行 ts 文件与检查类型是不同能力。

核心概念

版本管理器:为什么不用官网安装包

Node.js 生态版本迭代快,不同项目可能锁定不同版本。版本管理器让你按项目切换 Node 版本,是当前社区的标准做法。

  • fnm(Fast Node Manager):Rust 编写,启动快,单一二进制,推荐首选
  • nvm:老牌 Bash 脚本方案,生态文档最多,配置略繁琐
  • 二者都可使用版本文件;fnm 的 --use-on-cd 会在配置的 shell 钩子中切换,nvm 则需要额外的 shell 钩子或手动执行 nvm use

本模块以 Node 24 LTS 为基准。LTS 分支、补丁版本和维护阶段会变化;新建项目或升级运行时前,先查看 Node.js 发布页,再以项目声明的版本和框架兼容性为准。已有项目仍在 Node 22 时,先评估依赖、测试和发布环境,不要只因为看到新主版本就直接切换。

实践步骤

步骤一:安装版本管理器与 Node 24

# macOS / Linux 安装 fnm(也可用 brew install fnm)
curl -fsSL https://fnm.vercel.app/install | bash

1. 在 ~/.bashrc 或 ~/.zshrc 中追加初始化钩子(安装脚本通常已自动添加)
eval "$(fnm env --use-on-cd)"

1. 安装并使用 Node 24 LTS
fnm install 24
fnm use 24
fnm default 24

1. 验证
node -v   # v24.x.x
npm -v

nvm 等价操作:nvm install 24 && nvm alias default 24。

把下面的完整程序保存为 esm-check.mjs,再运行 node esm-check.mjs。它同时确认当前命令实际执行的是 Node 24,且 .mjs 会作为 ESM 解析;这比只看到版本号多验证了一个模块边界。

import assert from "node:assert/strict";

assert.equal(process.versions.node.split(".")[0], "24");
console.log(`Node ${process.version} executed this ESM module`);

步骤二:安装 pnpm

pnpm 通过内容寻址存储 + 硬链接实现快速安装与严格依赖隔离(默认无法引用未声明的依赖)。

# 如果当前 Node 发行版提供 Corepack,先启用它;项目中应由 packageManager 字段锁定版本。
corepack enable
pnpm --version

1. 或独立脚本安装
curl -fsSL https://get.pnpm.io/install.sh | sh

pnpm -v

确认 pnpm --version 后,再把实际决定采用的版本写入 packageManager。不要把 latest 当作锁定策略:它会随时间解析为不同版本。若 Node 发行版没有可用的 Corepack,则使用 pnpm 官方文档所列的安装方式,并在团队中统一版本。

步骤三:初始化项目

mkdir quest-api && cd quest-api
pnpm init
git init

编辑 package.json,后端项目推荐的最小骨架:

{
  "name": "quest-api",
  "version": "0.1.0",
  "type": "module",
  "packageManager": "pnpm@<团队锁定的实际版本>",
  "engines": {
    "node": ">=24"
  },
  "scripts": {
    "dev": "node --watch src/server.ts",
    "build": "tsc",
    "start": "node dist/server.js",
    "lint": "eslint ."
  }
}

关键点:

  • "type": "module":启用原生 ESM,.js 文件按 ES 模块解析(详见 03-modules-esm)
  • --watch:Node 内置文件监听重启,开发期无需 nodemon
  • engines:声明 Node 版本下限;是否强制执行还取决于包管理器与 CI 配置

<团队锁定的实际版本> 是占位符,不能原样写入 JSON。运行 pnpm --version 后,将其替换为例如 pnpm@<该命令输出> 的真实值并提交 package.json 和 lock 文件。

步骤四:配置 TypeScript

Node 24 原生支持运行 TypeScript 类型剥离(type stripping):.ts 文件可直接 node src/server.ts 运行,无需预编译——前提是只使用可被剥离的类型语法(不含 enum、带运行时代码的 namespace、参数属性等需要代码转换的语法)。这条路径只移除类型,不执行类型检查,也不读取 tsconfig.json;路径别名、降级语法和其他依赖 tsconfig 的行为不能因此假定可用。

pnpm add -D typescript @types/node
pnpm exec tsc --init

推荐 tsconfig.json(面向 Node 24 的现代配置):

{
  "compilerOptions": {
    "target": "ES2023",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "lib": ["ES2023"],
    "types": ["node"],
    "outDir": "dist",
    "rootDir": "src",
    "strict": true,
    "verbatimModuleSyntax": true,
    "noUncheckedIndexedAccess": true,
    "skipLibCheck": true
  },
  "include": ["src"]
}

两种运行策略:开发期直接 node src/server.ts(类型剥离);生产或需要 enum 等完整语法时用 tsc && node dist/server.js 预编译输出。无论选择哪条路径,仍需单独运行 pnpm exec tsc --noEmit 做类型检查。Node 的 TypeScript 运行文档列出了可剥离语法、扩展名和模块解析限制。

步骤五:配置 ESLint 9 扁平配置

pnpm add -D eslint @eslint/js typescript-eslint

创建 eslint.config.mjs(扁平配置,替代旧 .eslintrc):

import js from "@eslint/js";
import tseslint from "typescript-eslint";

export default tseslint.config(
  js.configs.recommended,
  ...tseslint.configs.recommended,
  {
    ignores: ["dist/**", "node_modules/**"],
  },
  {
    rules: {
      "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
      "no-console": "off", // 后端项目允许 console,生产建议换 pino
    },
  }
);

验证:pnpm lint 应无报错。

最佳实践

版本文件与 packageManager 字段记录工程约定,还需要开发工具和 CI 实际读取或执行这些约定;一个 major 版本号也不等于锁定所有补丁。安装后检查 Node、包管理器和 TypeScript 实际版本,依赖应在项目清单中可重建。

严格类型检查能更早发现不匹配,但不提供运行时输入验证。直接运行 TypeScript 时核对运行时支持的语法范围,不能把“可剥离类型”当完整编译器。内置模块采用 node: 前缀有助于识别来源,第三方依赖则由锁文件管理。

常见问题

Q1: corepack enable 报权限错误?

A: 不要为了启用包管理器对 Node 安装目录盲目使用 sudo。先确认 Node 是由系统包、版本管理器还是手工安装;版本管理器安装通常不需要写系统目录。无法修改时改用该环境的包管理方式或独立安装脚本。

Q2: pnpm install 后找不到某个依赖的函数?

A: 幽灵依赖问题——引用了传递依赖。把该包显式 pnpm add 即可。

练习与实践

练习一:环境通关

任务要求: 1. 用 fnm 安装 Node 24,并生成 .nvmrc 2. 启用或安装 pnpm,记录 pnpm --version,再把实际版本写入 packageManager 3. 把 node -v、pnpm -v、pnpm lint 的输出和 package.json 的 type、packageManager 字段贴进项目 README

练习二:lint 体检

挑战任务: – 故意在代码里写一个未使用变量和一处 == 比较,观察 ESLint 报错并修复 – 给 ESLint 升级到 recommendedTypeChecked 配置,体会类型感知 lint 的价值

提示: 类型感知规则需要在配置里声明 parserOptions.project: true。


相关文档

暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇