Uninote
Uninote
用户根目录
brdr
common
programming
docs
tests
后端试题
问题讨论

TS 迁移后的开发启动耗时

  • 本文的诊断和分段数据对应提交 90dcc55,保留当时的五组编译配置及命令,不代表当前启动路径。
  • 当前 npm start 使用 --reuse-build 复用成功构建;构建已使用增量缓存,renderer 日志也已归入 ESM 编译。后文“第一、二项优化已实施”记录启动改进,当前开发方式见 Vite renderer 开发。

结论

  • 诊断日期:2026-10-11。
  • 基于提交 90dcc55,Windows,Node.js v24.11.1,仓库安装的 TypeScript 6.0.3。
  • npm start 在启动 Electron 之前,无条件执行一次完整构建。
  • 两次分段实测完整构建分别为 13.91 秒和 14.01 秒。
  • TypeScript 编译占约 87%,足以解释迁移后观察到的约 10 秒启动延迟。
  • 这些数字是构建耗时,不是命令到窗口可用的端到端耗时。

启动链路与迁移差异

  • 迁移前:prestart 执行编辑器打包,再执行 electron .。
  • 迁移后:start 执行 node scripts/run.mts electron .。
    • scripts/run.mts 首先等待 build() 完成。
    • scripts/build.mts 删除 .build,再串行启动五个独立的 tsc 进程。
    • 随后复制静态资源、测试夹具和文档,生成产物清单,重新打包编辑器。
    • 最后才启动 Electron。
  • tsconfig.node.json 同时包含客户端主进程、服务端、工程脚本和测试。
    • 启动客户端也会检查和编译其他入口的代码。
  • 当前没有开启 incremental,无源码变更的第二次启动仍重复完整编译。
  • build:editor 现在也是完整构建的别名,不能作为轻量构建入口。

分段测量

阶段 第一次 第二次
清理输出目录 0.001 秒 0.097 秒
tsconfig.node.json 6.751 秒 7.061 秒
tsconfig.renderer.json 1.915 秒 1.634 秒
tsconfig.scripts.json 2.924 秒 2.836 秒
tsconfig.logging.json 0.331 秒 0.355 秒
tsconfig.wsh.json 0.182 秒 0.195 秒
复制 src/test 0.071 秒 0.064 秒
文档与清单 0.002 秒 0.002 秒
编辑器打包 1.727 秒 1.767 秒
合计 13.906 秒 14.011 秒

方法与边界

  • 以当前 scripts/build.mts 为基础,临时插入阶段计时。
  • 原 .build 被现有进程占用,清理报 EBUSY。
    • 首次清理尝试可能已删除部分文件;测量完成后已从完整测量产物恢复 .build,并检查主要入口存在。
    • 未关闭现有进程。
  • 为继续测量,将输出目录和五个编译器的 outDir 改到仓库内临时目录。
  • 两次运行均使用同一构建流程;第一次临时输出目录不存在,第二次包含上次完整产物。
  • 临时脚本和临时输出目录均已清理。
  • 未测量真实窗口首帧、现有笔记库恢复、迁移前版本或安装包启动耗时。

Node 编译器诊断

运行 node node_modules/typescript/bin/tsc -p tsconfig.node.json --noEmit --extendedDiagnostics 成功。

  • 编译器处理 1,028 个文件,其中 TypeScript 源码 49,959 行。
  • 类型检查耗时 3.21 秒,总编译器耗时 4.37 秒。
  • 该诊断禁用了输出,不能直接替代上表包含代码生成的阶段耗时。
  • 文件读取仅 0.10 秒;本次证据指向编译与检查,而非静态资源复制。

优化建议

第一优先级:分开构建与启动

  • 保留完整构建用于显式构建、CI、测试和打包。
  • 提供复用现有 .build 的启动入口。
    • 缺少产物时给出明确提示或执行首次构建。
    • 修改代码后必须重新构建,避免把旧产物误当作最新代码。
  • 当前无需修改代码即可手工验证:
npm run build
.\node_modules\.bin\electron.cmd .
  • 第二条命令从根目录的 package.json.main 加载 .build/src/main.js。
  • 预计可从反复启动路径移除本次测得的约 14 秒构建等待;实际窗口耗时尚未测量。
  • 如果 .build 被正在运行的进程占用,先正常退出占用它的应用或终端,再执行完整构建。

第二优先级:开发构建保留增量产物

  • 使用 TypeScript incremental 或 watch 模式复用编译状态。
  • 为不同配置保留独立的 tsBuildInfoFile。
  • 开发构建不能继续每次删除所有输出。
    • 仅将增量状态放到目录外、仍删除输出,会让状态和产物不一致。
    • 保留显式 clean 构建,处理源码删除、重命名、分支切换和发布。
    • 当前构建回归明确检查删除源码后不留下旧模块,优化后必须保留该保证。
  • 编辑器仅在入口、依赖图、构建脚本或锁文件变化时重新打包。
  • 增量收益尚未实测,不承诺具体秒数。
  • 参考:TypeScript incremental、tsBuildInfoFile。

第三优先级:缩小开发构建范围或分离类型检查

  • 客户端开发构建可以不编译服务端、管理脚本和测试,但须先梳理跨入口导入和构建脚本依赖。
  • 可评估仅开发转译使用 --noCheck,完整类型检查继续由 npm run typecheck 和 CI 承担。
    • 代价是开发启动不再阻止类型错误,不能直接替换发布校验。
    • 本次没有测试该方案的耗时或行为。
  • 五个编译器并行只能缩短部分等待,仍会重复全量工作,并增加 CPU 和内存竞争,优先级低于复用产物。
  • 参考:TypeScript CLI 选项。

初次诊断范围

  • 仅提交诊断文档,没有修改启动命令、编译配置或应用逻辑。
  • 不需要为本次文档变更重启应用。

第一、二项优化已实施

  • 后续已接入 Vite;当前 npm run dev 的热更新行为见 Vite renderer 开发。以下增量构建与快速启动规则继续有效。

  • 上文测量与启动链路描述保留为优化前基线。

  • npm start 使用 --reuse-build,直接启动上次成功构建。

    • 检查构建状态文件及其中记录的产物是否存在。
    • 首次启动、旧产物没有状态文件或产物缺失时,自动执行完整构建。
    • 不检查源码内容是否更新;这是明确的快速启动入口。
  • npm run dev 先调用增量构建,再启动 Vite 开发服务和 Electron。

  • npm run build:dev 只增量构建,不启动应用。

  • ESM 迁移后四组编译都保留类型检查,分别在 .build/.cache/ 保存编译状态。

    • 日志序列化改为主进程与浏览器共用的 ESM,不再需要独立的日志脚本配置;上文五组配置的耗时记录保留为迁移时的历史测量。
    • 完整构建也生成缓存,便于随后切换到增量构建。
    • 输入文件删除、重命名或编译配置、包清单、锁文件变化时,自动完整清理重建。
    • 输出缺失、构建失败或状态损坏时,下次构建不复用缓存。
  • 编辑器源码、编辑器工程脚本或锁文件变化时重新打包,否则保留 bundle 与许可证文件。

  • 静态资源继续复制,保持现有相对路径与测试夹具布局。

  • npm run build、测试、基准、同步管理和发布保留完整清理构建。

  • 本次未实施第三项:没有拆分客户端编译范围,也没有跳过类型检查。

  • 修改代码后必须使用开发构建并重启应用;需要清理 .build 时先正常退出占用目录的应用或终端。

优化后验证

  • 在隔离的临时仓库目录执行构建回归,避免清理正在使用的原 .build。
  • 无改动增量构建实测 3.50 秒,增量构建加 Node 子进程启动实测 3.34 秒。
  • 复用构建状态并启动 Node 子进程实测 0.15 秒。
    • 该数字仅验证启动入口不再执行构建,不代表 Electron 窗口首帧耗时。
    • 临时目录与初次诊断的输出位置不同,时间只作为本机参考。
  • 构建回归覆盖首次构建、未修改时复用、源码编辑后增量输出、编辑器输入变化、构建失败、缺失产物恢复、源码删除清理及完整构建。
  • 全量类型检查、lint、681 项单元测试以及 CodeMirror Electron 冒烟测试通过。

settings-keyboard

sync-flow

点赞(0) 阅读(5) 举报
目录
标题