name: typescript-tooling-migration
description: 在Phoenix monorepo中迁移或升级TypeScript工具的指南。覆盖核心依赖升级(TypeScript、React)、工具切换(linter、formatter、bundler),以及管理app/和js/目录中的破坏性变更。
license: Apache-2.0
metadata:
author: oss@arize.com
version: “1.0.0”
languages: TypeScript
internal: true
TypeScript 工具迁移
在Phoenix monorepo中迁移或升级TypeScript工具的指南。此技能覆盖核心依赖升级(TypeScript、React)、工具切换(linter、formatter、bundler),以及管理app/和js/目录中的破坏性变更。
Monorepo 结构
Phoenix有两个TypeScript项目目录,必须保持同步:
| 目录 | 目的 | 包管理器 |
|---|---|---|
app/ |
React/TypeScript前端(主要Phoenix UI) | pnpm |
js/ |
TypeScript包monorepo(phoenix-client、phoenix-evals等) | pnpm(工作区) |
共享依赖
两个目录应使用相同版本的共享工具:
| 工具 | 同步强制 | 配置位置 |
|---|---|---|
| pnpm | CI检查 | package.json → packageManager |
| TypeScript | CI检查 | package.json → devDependencies |
| oxlint | CI检查 | package.json → devDependencies |
| oxfmt | CI检查 | package.json → devDependencies |
配置文件位置
| 配置 | 位置 | 目的 |
|---|---|---|
.oxlintrc.json |
根目录 + app/ + js/ |
Linter配置(嵌套继承) |
.oxfmtrc.jsonc |
根目录 | Formatter配置(共享) |
tsconfig.json |
app/和js/包 |
TypeScript配置 |
vite.config.ts |
app/ |
构建/开发服务器配置 |
relay.config.js |
app/ |
GraphQL/Relay配置 |
迁移类型
类型1:工具替换(例如,ESLint → oxlint)
完全替换一个工具为另一个。
工作流:
- 研究新工具的迁移指南
- 与旧工具一起安装新工具
- 创建新配置,验证其工作
- 更新包脚本
- 更新预提交钩子
- 移除旧工具和配置
- 更新文档
类型2:主要版本升级(例如,TypeScript 5 → 6)
将工具升级到带有破坏性变更的新主要版本。
工作流:
- 阅读变更日志/迁移指南中的破坏性变更
- 检查依赖包的兼容性
- 在分支中升级,修复破坏性变更
- 运行完整测试套件
- 更新任何已弃用的配置选项
- 如果API更改,更新文档
类型3:依赖升级(例如,React 18 → 19)
升级影响应用程序代码的核心依赖。
工作流:
- 检查兼容性矩阵(React + React DOM + types)
- 回顾破坏性变更和新特性
- 一起升级依赖
- 在应用程序代码中修复破坏性变更
- 更新任何已弃用的模式
- 运行E2E测试以验证功能
迁移工作流
阶段1:研究与规划
- 阅读官方迁移指南 - 大多数工具发布升级指南
- 检查GitHub问题 - 查找已知迁移问题
- 识别范围:
- 哪些目录受影响(
app/、js/,或两者) - 哪些配置文件需要更改
- 添加/移除/升级哪些依赖
- 需要哪些代码更改
- 哪些目录受影响(
- 回顾当前配置 - 更改前理解现有设置
- 检查依赖包 - 确保依赖树中的兼容性
阶段2:创建迁移分支
git checkout -b chore/migrate-<tool>-to-<version>
# 或
git checkout -b chore/upgrade-<tool>-<version>
阶段3:安装/升级依赖
# 对于app/(标准项目)
cd app && pnpm add -D <package>@<version>
# 对于js/(工作区根目录)
cd js && pnpm add -D -w <package>@<version>
# 对于升级现有依赖
cd app && pnpm update <package>@<version>
提示: 在迁移验证前保持旧工具安装,对于工具替换。
阶段4:更新配置
对于工具替换 - 创建新配置:
Phoenix使用嵌套配置与继承,尽可能:
phoenix/
├── .<tool>rc.json # 共享基础配置
├── app/
│ └── .<tool>rc.json # 扩展基础,添加React特定选项
└── js/
└── .<tool>rc.json # 扩展基础,添加Node特定选项
配置继承模式:
{
"$schema": "./node_modules/<tool>/configuration_schema.json",
"extends": ["../.<tool>rc.json"]
}
对于版本升级 - 更新现有配置:
- 在变更日志中检查已弃用的选项
- 更新或移除已弃用的设置
- 添加任何新要求的设置
阶段5:修复破坏性变更
代码更改:
- 修复更严格检查导致的类型错误
- 更新已弃用的API使用
- 适应新语法要求
配置更改:
- 更新已弃用的配置选项
- 调整更改后的默认值
提示: 使用工具自身的CLI识别问题:
pnpm run typecheck # TypeScript错误
pnpm run lint # Linter错误
pnpm run build # 构建错误
阶段6:更新包脚本
如果脚本调用更改,更新app/package.json和js/package.json:
{
"scripts": {
"lint": "<new-command>",
"typecheck": "<new-command>"
}
}
阶段7:更新预提交钩子
如果工具用于预提交,编辑.pre-commit-config.yaml:
- 移除旧工具的钩子(对于替换)
- 更新或添加新钩子:
- id: <tool>-app
name: <tool> (app)
entry: pnpm --dir app run <script>
language: system
files: ^app/.*\.[jt]sx?$
pass_filenames: false
- id: <tool>-js
name: <tool> (js)
entry: pnpm --dir js run <script>
language: system
files: ^js/.*\.[jt]sx?$
pass_filenames: false
阶段8:更新编辑器设置
- 如果扩展更改,更新
.vscode/extensions.json - 在
DEVELOPMENT.md中记录任何路径/二进制设置:
{
"<extension>.path.<binary>": "app/node_modules/<package>/bin/<binary>"
}
注意:.vscode/settings.json被git忽略 - 在DEVELOPMENT.md中记录设置。
阶段9:移除旧工具(对于替换)
# 移除旧依赖
cd app && pnpm remove <old-tool> <old-plugins>
cd js && pnpm remove -w <old-tool> <old-plugins>
# 删除旧配置文件
rm app/<old-config> js/<old-config>
阶段10:测试与验证
# 类型检查
cd app && pnpm run typecheck
cd js && pnpm run typecheck
# Linting
cd app && pnpm run lint
cd js && pnpm run lint
# 格式化
cd app && pnpm run fmt:check
cd js && pnpm run fmt:check
# 单元测试
cd app && pnpm test
cd js && pnpm run -r test
# 构建
cd app && pnpm run build
cd js && pnpm run -r build
# E2E测试(对于重大更改)
cd app && pnpm run test:e2e
# 预提交钩子
pre-commit run --all-files
阶段11:更新文档
要检查和更新的文件:
| 文件 | 更新内容 |
|---|---|
AGENTS.md |
工具版本、命令、风格约定 |
DEVELOPMENT.md |
设置说明、VS Code设置 |
app/README.md |
工具引用、测试命令 |
.cursor/rules/typescript-packages/RULE.md |
命令、工作流说明 |
.claude/settings.json |
PostToolUse钩子 |
CHANGELOG.md |
记录重大工具更改 |
阶段12:添加/更新版本同步检查
对于共享依赖,确保.github/workflows/package-version-check.yml强制一致性:
- name: 检查 <tool> 版本一致性
run: |
APP_VERSION=$(jq -r '.devDependencies.<tool> // empty' app/package.json)
JS_VERSION=$(jq -r '.devDependencies.<tool> // empty' js/package.json)
echo "app/package.json: <tool>@$APP_VERSION"
echo "js/package.json: <tool>@$JS_VERSION"
if [ -z "$APP_VERSION" ]; then
echo "::error::app/package.json 缺少 <tool> 在 devDependencies 中"
exit 1
fi
if [ -z "$JS_VERSION" ]; then
echo "::error::js/package.json 缺少 <tool> 在 devDependencies 中"
exit 1
fi
if [ "$APP_VERSION" != "$JS_VERSION" ]; then
echo "::error::<tool> 版本不匹配!"
exit 1
fi
echo "<tool> 版本一致: $APP_VERSION"
关键原则
保持目录同步
升级共享工具时,始终同时升级app/和js/。版本漂移会导致微妙错误和CI失败。
性能重要
- 测量升级前后的构建时间、lint时间、测试时间
- 一些兼容层(如linter的JS插件)添加显著开销
- 优先选择原生实现而非兼容垫片
向后兼容性
- 许多工具支持遗留配置格式(例如,oxlint支持
eslint-disable注释) - 除非有明确好处,不要大规模更新工作代码
- 弃用警告是信息性的 - 修复它们但不要阻塞于它们
配置位置策略
| 场景 | 方法 |
|---|---|
| 两个目录的相同配置 | 单个根配置 |
| 共享基础 + 目录特定覆盖 | 根配置 + 嵌套配置使用extends |
| 每个目录的完全不同配置 | 单独配置(无继承) |
范围外目录
这些目录有自己的工具,不应包含在迁移中:
scripts/docker/devops/oidc-server/- 单独的OIDC测试服务器scripts/mock-llm-server/- 单独的模拟服务器internal_docs/- 内部文档实用程序
故障排除
TypeScript 升级问题
更严格的类型检查: 新TypeScript版本通常添加更严格的检查。通过以下方式修复错误:
- 添加显式类型注解
- 在适当的地方使用类型断言
- 如果需要,更新
tsconfig.json临时放宽检查
依赖类型不匹配: 确保@types/*包与新TS版本兼容。
升级后构建失败
- 清除缓存:
rm -rf node_modules/.cache app/dist js/**/dist - 重新安装:
pnpm install - 重新构建:
pnpm run build
配置未找到
- 检查
$schema路径相对于配置文件位置 - 对于嵌套配置,验证
extends路径(例如,"../.toolrc.json")
编辑器未使用更新后的工具
- 确保扩展是最新的
- 在VS Code设置中设置显式二进制路径
- 重新加载VS Code窗口(
Cmd+Shift+P→ “重新加载窗口”)
预提交钩子失败
- 在两个目录中运行
pnpm install - 验证
package.json中的脚本名称与钩子条目匹配 - 手动测试脚本:
pnpm --dir app run <script>
CI 失败但本地通过
- 检查Node版本匹配CI(见
.nvmrc) - 确保锁文件已提交(
pnpm-lock.yaml) - 在本地运行
--frozen-lockfile以匹配CI行为
CI 工作流
TypeScript工具的相关CI文件:
| 工作流 | 目的 |
|---|---|
.github/workflows/typescript-CI.yml |
app/ 类型检查、lint、测试 |
.github/workflows/typescript-packages-CI.yml |
js/ 构建、测试、lint |
.github/workflows/package-version-check.yml |
版本同步强制 |
.github/workflows/playwright.yaml |
E2E测试 |