project references在tsserver内工作流程

tsserver

在 VS Code 里,TypeScript/JavaScript 的智能提示、跳转、报错检查这些功能,都是靠 tsserver(TypeScript Server)驱动的。它的工作方式可以分为几个层面来看:


1. tsserver 是什么

  • tsserver 是 TypeScript 编译器 (tsc) 提供的一个 长期运行的语言服务进程
  • 它和 tsc 共享同一套编译、类型检查逻辑,但不是一次性编译退出,而是作为一个 服务端 持续运行,响应 VS Code 等客户端发来的请求。
  • 通过 JSON-RPC 协议 与编辑器通信。

2. 启动过程

  • 当你在 VS Code 打开一个含有 JS/TS 文件的工作区时,VS Code 的 TypeScript 扩展 会启动一个 tsserver 进程。
  • 启动时会根据 tsconfig.json / jsconfig.json 初始化项目配置(如果没有配置,就以默认模式运行)。

3. 工作原理

  1. 文件同步

    • 编辑器把当前打开的文件内容同步给 tsserver(包括你还没保存的改动)。
    • 同时告诉它项目结构(有哪些文件、模块路径等)。
  2. 请求/响应模式

    • 编辑器发送请求,比如:

      • completion → 请求补全建议
      • quickinfo → 请求符号的 hover 信息
      • definition → 请求跳转到定义
      • references → 查找引用
    • tsserver 返回 JSON 格式的结果,VS Code 插件渲染成你看到的提示/导航。

  3. 增量更新

    • 当文件发生修改时,VS Code 只会通知 tsserver 哪些部分变了。
    • tsserver 内部维护一份 AST(抽象语法树)+ 类型检查结果,可以做增量更新,不必重头编译。
  4. 语言服务

    • tsserver 使用 TypeScript 编译器 API 提供高级功能:

      • 代码补全:基于 AST + 类型信息推断可能的成员/变量。
      • 错误提示:运行类型检查规则,给出诊断信息。
      • 重构 / 重命名:通过符号表找到受影响的引用并更新。
      • 导航:符号定义、实现、调用链等。

4. 项目和配置管理

tsserver 会探测项目边界:

  • 优先读取最近的 tsconfig.jsonjsconfig.json
  • 如果没有配置文件,就用 inferred project(推断项目),把打开的文件单独作为一个上下文。

项目引用 project references

在 tsconfig.json 使用 project references 时,tsserver 会:

解析所有引用的 tsconfig,为每个项目创建一个 ConfiguredProject。

建立项目依赖图,跨项目共享类型信息。

通过增量更新机制保持依赖关系的实时同步。

提供跨项目的补全、跳转、错误提示,而不进行真正的构建。


1. 例子目录结构

bash 复制代码
/app/tsconfig.json
/core/tsconfig.json
/utils/tsconfig.json
/shared/tsconfig.json

2. 配置关系

  • app 依赖 coreutils
  • core 依赖 utils
  • utils 依赖 shared
json 复制代码
// app/tsconfig.json
{
  "compilerOptions": { "composite": true },
  "references": [
    { "path": "../core" },
    { "path": "../utils" }
  ]
}
json 复制代码
// core/tsconfig.json
{
  "compilerOptions": { "composite": true },
  "references": [
    { "path": "../utils" }
  ]
}
json 复制代码
// utils/tsconfig.json
{
  "compilerOptions": { "composite": true },
  "references": [
    { "path": "../shared" }
  ]
}
json 复制代码
// shared/tsconfig.json
{
  "compilerOptions": { "composite": true }
}

3. 依赖图(tsserver 内存中的 Project Graph)

markdown 复制代码
    app
   /   \
 core   utils
   \     |
    \   shared
     \  /

4. tsserver 处理流程(增量更新)

  1. 初始化

    • 打开 app 项目时,tsserver 发现它有 references,递归解析: app → core → utils → shared
    • 为每个 tsconfig 建立一个 ConfiguredProject,形成项目图。
  2. 类型查询

    • app 里写代码时,如果用到 coreutils 的类型,tsserver 会直接去对应项目的类型快照里查。
    • 如果再间接引用到 shared,也会一路查下去。
  3. 修改 shared

    • 当你改动 shared 里的类型(例如 type User = { name: string }type User = { name: string; age: number })。
    • tsserver 会标记 shared 项目为 dirty
  4. 增量更新

    • utils 依赖 shared → 重新检查 utils 的类型。
    • core 依赖 utils → 重新检查 core 的类型。
    • app 依赖 coreutils → 重新检查 app 的类型。
  5. 结果

    • 最终在 VS Code 里,app 中用到 User 类型的地方会立刻提示 缺少 age 属性
    • 全过程在内存完成,不需要执行 tsc -b

5. 总结图(影响传播链)

scss 复制代码
shared (改动)
   ↓
utils (重新检查)
   ↓
core (重新检查)
   ↓
app (重新检查并提示错误)

一句话总结 : 在 Project References 模式下,tsserver 内部维护一张项目依赖图,当底层项目(如 shared)类型变化时,会通过图逐层向上传递,保证顶层项目(如 app)的智能提示和类型检查始终正确。(注:内容来源ChatGPT)

参考文章:

相关推荐
keep_di21 小时前
05-vue3+ts中axios的封装
前端·vue.js·ajax·typescript·前端框架·axios
RoyLin1 天前
SurrealDB - 统一数据基础设施
前端·后端·typescript
濮水大叔1 天前
Node生态中最优雅的数据库事务处理机制
typescript·nodejs·nestjs
Mintopia1 天前
如何用 TypeScript 折腾出全排列之你不知道的 :“分布式条件类型”、“递归处理”
前端·javascript·typescript
-D调定义之崽崽2 天前
【初学】使用 node 编写 MCP Server
typescript·node·mcp
濮水大叔2 天前
VonaJS提供的读写分离,直观,优雅🌼
typescript·nodejs·nestjs
RoyLin2 天前
命名实体识别
前端·后端·typescript
Ares-Wang3 天前
Vue3 》》vite》》TS》》封装 axios ,Promise<T>
vue.js·typescript